Skip to content

Commit

Permalink
fix natspec test
Browse files Browse the repository at this point in the history
* registar url string retrieval chop leading zeros now
* rewrite test using test mining
* remove temporary applyTxs from xeth
  • Loading branch information
zelig authored and obscuren committed Jul 7, 2015
1 parent aa22cf3 commit 1208ac8
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 81 deletions.
2 changes: 1 addition & 1 deletion cmd/geth/js_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ func TestSignature(t *testing.T) {
}

func TestContract(t *testing.T) {
// t.Skip("contract testing is implemented with mining in ethash test mode. This takes about 7seconds to run. Unskip and run on demand")
t.Skip("contract testing is implemented with mining in ethash test mode. This takes about 7seconds to run. Unskip and run on demand")
coinbase := common.HexToAddress(testAddress)
tmp, repl, ethereum := testREPL(t, func(conf *eth.Config) {
conf.Etherbase = testAddress
Expand Down
11 changes: 4 additions & 7 deletions common/docserver/docserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func New(docRoot string) (self *DocServer) {
DocRoot: docRoot,
schemes: []string{"file"},
}
self.DocRoot = "/tmp/"
self.RegisterProtocol("file", http.NewFileTransport(http.Dir(self.DocRoot)))
return
}
Expand Down Expand Up @@ -52,20 +53,16 @@ func (self *DocServer) HasScheme(scheme string) bool {

func (self *DocServer) GetAuthContent(uri string, hash common.Hash) (content []byte, err error) {
// retrieve content
url := uri
fmt.Printf("uri: %v\n", url)
content, err = self.Get(url, "")
content, err = self.Get(uri, "")
if err != nil {
return
}

// check hash to authenticate content
hashbytes := crypto.Sha3(content)
var chash common.Hash
copy(chash[:], hashbytes)
chash := crypto.Sha3Hash(content)
if chash != hash {
content = nil
err = fmt.Errorf("content hash mismatch")
err = fmt.Errorf("content hash mismatch %x != %x (exp)", hash[:], chash[:])
}

return
Expand Down
2 changes: 1 addition & 1 deletion common/docserver/docserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestGetAuthContent(t *testing.T) {

hash = common.Hash{}
content, err = ds.GetAuthContent("file:///test.content", hash)
expected := "content hash mismatch"
expected := "content hash mismatch 0000000000000000000000000000000000000000000000000000000000000000 != 9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658 (exp)"
if err == nil {
t.Errorf("expected error, got nothing")
} else {
Expand Down
122 changes: 89 additions & 33 deletions common/natspec/natspec_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ package natspec
import (
"fmt"
"io/ioutil"
"math/big"
"os"
"runtime"
"strings"
"testing"
"time"

"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/docserver"
"github.com/ethereum/go-ethereum/common/registrar"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
xe "github.com/ethereum/go-ethereum/xeth"
Expand Down Expand Up @@ -76,9 +78,7 @@ type testFrontend struct {
t *testing.T
ethereum *eth.Ethereum
xeth *xe.XEth
coinbase common.Address
stateDb *state.StateDB
txc uint64
wait chan *big.Int
lastConfirm string
wantNatSpec bool
}
Expand Down Expand Up @@ -124,6 +124,8 @@ func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
DataDir: "/tmp/eth-natspec",
AccountManager: am,
MaxPeers: 0,
PowTest: true,
Etherbase: testAddress,
})

if err != nil {
Expand All @@ -149,13 +151,16 @@ func testInit(t *testing.T) (self *testFrontend) {
// mock frontend
self = &testFrontend{t: t, ethereum: ethereum}
self.xeth = xe.New(ethereum, self)

addr, _ := ethereum.Etherbase()
self.coinbase = addr
self.stateDb = self.ethereum.ChainManager().State().Copy()
self.wait = self.xeth.UpdateState()
addr, _ := self.ethereum.Etherbase()

// initialise the registry contracts
reg := registrar.New(self.xeth)
err = reg.SetGlobalRegistrar("", addr)
if err != nil {
t.Errorf("error creating GlobalRegistrar: %v", err)
}

err = reg.SetHashReg("", addr)
if err != nil {
t.Errorf("error creating HashReg: %v", err)
Expand All @@ -164,84 +169,75 @@ func testInit(t *testing.T) (self *testFrontend) {
if err != nil {
t.Errorf("error creating UrlHint: %v", err)
}
self.applyTxs()
if !processTxs(self, t, 7) {
t.Errorf("error mining txs")
}

return

}

// this is needed for transaction to be applied to the state in testing
// the heavy lifing is done in XEth.ApplyTestTxs
// this is fragile,
// and does process leaking since xeth loops cannot quit safely
// should be replaced by proper mining with testDAG for easy full integration tests
func (self *testFrontend) applyTxs() {
self.txc, self.xeth = self.xeth.ApplyTestTxs(self.stateDb, self.coinbase, self.txc)
return
}

// end to end test
func TestNatspecE2E(t *testing.T) {
t.Skip()

tf := testInit(t)
defer tf.ethereum.Stop()
addr, _ := tf.ethereum.Etherbase()

// create a contractInfo file (mock cloud-deployed contract metadocs)
// incidentally this is the info for the registry contract itself
ioutil.WriteFile("/tmp/"+testFileName, []byte(testContractInfo), os.ModePerm)
dochash := common.BytesToHash(crypto.Sha3([]byte(testContractInfo)))
dochash := crypto.Sha3Hash([]byte(testContractInfo))

// take the codehash for the contract we wanna test
// codehex := tf.xeth.CodeAt(registar.HashRegAddr)
codeb := tf.xeth.CodeAtBytes(registrar.HashRegAddr)
codehash := common.BytesToHash(crypto.Sha3(codeb))
codehash := crypto.Sha3Hash(codeb)

// use resolver to register codehash->dochash->url
// test if globalregistry works
// registrar.HashRefAddr = "0x0"
// registrar.UrlHintAddr = "0x0"
reg := registrar.New(tf.xeth)
_, err := reg.SetHashToHash(tf.coinbase, codehash, dochash)
_, err := reg.SetHashToHash(addr, codehash, dochash)
if err != nil {
t.Errorf("error registering: %v", err)
}
_, err = reg.SetUrlToHash(tf.coinbase, dochash, "file:///"+testFileName)
_, err = reg.SetUrlToHash(addr, dochash, "file:///"+testFileName)
if err != nil {
t.Errorf("error registering: %v", err)
}
// apply txs to the state
tf.applyTxs()
if !processTxs(tf, t, 5) {
return
}

// NatSpec info for register method of HashReg contract installed
// now using the same transactions to check confirm messages

tf.wantNatSpec = true // this is set so now the backend uses natspec confirmation
_, err = reg.SetHashToHash(tf.coinbase, codehash, dochash)
_, err = reg.SetHashToHash(addr, codehash, dochash)
if err != nil {
t.Errorf("error calling contract registry: %v", err)
}

fmt.Printf("GlobalRegistrar: %v, HashReg: %v, UrlHint: %v\n", registrar.GlobalRegistrarAddr, registrar.HashRegAddr, registrar.UrlHintAddr)
if tf.lastConfirm != testExpNotice {
t.Errorf("Wrong confirm message. expected '%v', got '%v'", testExpNotice, tf.lastConfirm)
t.Errorf("Wrong confirm message. expected\n'%v', got\n'%v'", testExpNotice, tf.lastConfirm)
}

// test unknown method
exp := fmt.Sprintf(testExpNotice2, registrar.HashRegAddr)
_, err = reg.SetOwner(tf.coinbase)
_, err = reg.SetOwner(addr)
if err != nil {
t.Errorf("error setting owner: %v", err)
}

if tf.lastConfirm != exp {
t.Errorf("Wrong confirm message, expected '%v', got '%v'", exp, tf.lastConfirm)
t.Errorf("Wrong confirm message, expected\n'%v', got\n'%v'", exp, tf.lastConfirm)
}

// test unknown contract
exp = fmt.Sprintf(testExpNotice3, registrar.UrlHintAddr)

_, err = reg.SetUrlToHash(tf.coinbase, dochash, "file:///test.content")
_, err = reg.SetUrlToHash(addr, dochash, "file:///test.content")
if err != nil {
t.Errorf("error registering: %v", err)
}
Expand All @@ -251,3 +247,63 @@ func TestNatspecE2E(t *testing.T) {
}

}

func pendingTransactions(repl *testFrontend, t *testing.T) (txc int64, err error) {
txs := repl.ethereum.TxPool().GetTransactions()
return int64(len(txs)), nil
}

func processTxs(repl *testFrontend, t *testing.T, expTxc int) bool {
var txc int64
var err error
for i := 0; i < 50; i++ {
txc, err = pendingTransactions(repl, t)
if err != nil {
t.Errorf("unexpected error checking pending transactions: %v", err)
return false
}
if expTxc < int(txc) {
t.Errorf("too many pending transactions: expected %v, got %v", expTxc, txc)
return false
} else if expTxc == int(txc) {
break
}
time.Sleep(100 * time.Millisecond)
}
if int(txc) != expTxc {
t.Errorf("incorrect number of pending transactions, expected %v, got %v", expTxc, txc)
return false
}

err = repl.ethereum.StartMining(runtime.NumCPU())
if err != nil {
t.Errorf("unexpected error mining: %v", err)
return false
}
defer repl.ethereum.StopMining()

timer := time.NewTimer(100 * time.Second)
height := new(big.Int).Add(repl.xeth.CurrentBlock().Number(), big.NewInt(1))
repl.wait <- height
select {
case <-timer.C:
// if times out make sure the xeth loop does not block
go func() {
select {
case repl.wait <- nil:
case <-repl.wait:
}
}()
case <-repl.wait:
}
txc, err = pendingTransactions(repl, t)
if err != nil {
t.Errorf("unexpected error checking pending transactions: %v", err)
return false
}
if txc != 0 {
t.Errorf("%d trasactions were not mined", txc)
return false
}
return true
}
15 changes: 4 additions & 11 deletions common/registrar/registrar.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,22 +339,15 @@ func (self *Registrar) HashToUrl(chash common.Hash) (uri string, err error) {
key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(idx)))
hex := self.backend.StorageAt(UrlHintAddr[2:], key)
str = string(common.Hex2Bytes(hex[2:]))
l := len(str)
for (l > 0) && (str[l-1] == 0) {
l--
l := 0
for (l < len(str)) && (str[l] == 0) {
l++
}

str = str[:l]
str = str[l:]
uri = uri + str
idx++
}

l := 0
for (l < len(uri)) && (uri[l] == 0) {
l++
}
uri = uri[l:]

if len(uri) == 0 {
err = fmt.Errorf("GetURLhint: URL hint not found for '%v'", chash.Hex())
}
Expand Down
28 changes: 0 additions & 28 deletions xeth/xeth.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,34 +203,6 @@ func (self *XEth) AtStateNum(num int64) *XEth {
return self.WithState(st)
}

// applies queued transactions originating from address onto the latest state
// and creates a block
// only used in tests
// - could be removed in favour of mining on testdag (natspec e2e + networking)
// + filters
func (self *XEth) ApplyTestTxs(statedb *state.StateDB, address common.Address, txc uint64) (uint64, *XEth) {
chain := self.backend.ChainManager()
header := chain.CurrentBlock().Header()
coinbase := statedb.GetStateObject(address)
coinbase.SetGasLimit(big.NewInt(10000000))
txs := self.backend.TxPool().GetQueuedTransactions()

for i := 0; i < len(txs); i++ {
for _, tx := range txs {
if tx.Nonce() == txc {
_, _, err := core.ApplyMessage(core.NewEnv(statedb, self.backend.ChainManager(), tx, header), tx, coinbase)
if err != nil {
panic(err)
}
txc++
}
}
}

xeth := self.WithState(statedb)
return txc, xeth
}

func (self *XEth) WithState(statedb *state.StateDB) *XEth {
xeth := &XEth{
backend: self.backend,
Expand Down

0 comments on commit 1208ac8

Please sign in to comment.