fix natspec test

* registar url string retrieval chop leading zeros now
* rewrite test using test mining
* remove temporary applyTxs from xeth
This commit is contained in:
zelig 2015-07-05 19:19:42 +01:00 committed by Jeffrey Wilcke
parent aa22cf323e
commit 1208ac83d5
6 changed files with 99 additions and 81 deletions

View File

@ -254,7 +254,7 @@ func TestSignature(t *testing.T) {
} }
func TestContract(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) coinbase := common.HexToAddress(testAddress)
tmp, repl, ethereum := testREPL(t, func(conf *eth.Config) { tmp, repl, ethereum := testREPL(t, func(conf *eth.Config) {
conf.Etherbase = testAddress conf.Etherbase = testAddress

View File

@ -22,6 +22,7 @@ func New(docRoot string) (self *DocServer) {
DocRoot: docRoot, DocRoot: docRoot,
schemes: []string{"file"}, schemes: []string{"file"},
} }
self.DocRoot = "/tmp/"
self.RegisterProtocol("file", http.NewFileTransport(http.Dir(self.DocRoot))) self.RegisterProtocol("file", http.NewFileTransport(http.Dir(self.DocRoot)))
return return
} }
@ -52,20 +53,16 @@ func (self *DocServer) HasScheme(scheme string) bool {
func (self *DocServer) GetAuthContent(uri string, hash common.Hash) (content []byte, err error) { func (self *DocServer) GetAuthContent(uri string, hash common.Hash) (content []byte, err error) {
// retrieve content // retrieve content
url := uri content, err = self.Get(uri, "")
fmt.Printf("uri: %v\n", url)
content, err = self.Get(url, "")
if err != nil { if err != nil {
return return
} }
// check hash to authenticate content // check hash to authenticate content
hashbytes := crypto.Sha3(content) chash := crypto.Sha3Hash(content)
var chash common.Hash
copy(chash[:], hashbytes)
if chash != hash { if chash != hash {
content = nil content = nil
err = fmt.Errorf("content hash mismatch") err = fmt.Errorf("content hash mismatch %x != %x (exp)", hash[:], chash[:])
} }
return return

View File

@ -27,7 +27,7 @@ func TestGetAuthContent(t *testing.T) {
hash = common.Hash{} hash = common.Hash{}
content, err = ds.GetAuthContent("file:///test.content", hash) content, err = ds.GetAuthContent("file:///test.content", hash)
expected := "content hash mismatch" expected := "content hash mismatch 0000000000000000000000000000000000000000000000000000000000000000 != 9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658 (exp)"
if err == nil { if err == nil {
t.Errorf("expected error, got nothing") t.Errorf("expected error, got nothing")
} else { } else {

View File

@ -3,16 +3,18 @@ package natspec
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big"
"os" "os"
"runtime"
"strings" "strings"
"testing" "testing"
"time"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/docserver" "github.com/ethereum/go-ethereum/common/docserver"
"github.com/ethereum/go-ethereum/common/registrar" "github.com/ethereum/go-ethereum/common/registrar"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
xe "github.com/ethereum/go-ethereum/xeth" xe "github.com/ethereum/go-ethereum/xeth"
@ -76,9 +78,7 @@ type testFrontend struct {
t *testing.T t *testing.T
ethereum *eth.Ethereum ethereum *eth.Ethereum
xeth *xe.XEth xeth *xe.XEth
coinbase common.Address wait chan *big.Int
stateDb *state.StateDB
txc uint64
lastConfirm string lastConfirm string
wantNatSpec bool wantNatSpec bool
} }
@ -124,6 +124,8 @@ func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
DataDir: "/tmp/eth-natspec", DataDir: "/tmp/eth-natspec",
AccountManager: am, AccountManager: am,
MaxPeers: 0, MaxPeers: 0,
PowTest: true,
Etherbase: testAddress,
}) })
if err != nil { if err != nil {
@ -149,13 +151,16 @@ func testInit(t *testing.T) (self *testFrontend) {
// mock frontend // mock frontend
self = &testFrontend{t: t, ethereum: ethereum} self = &testFrontend{t: t, ethereum: ethereum}
self.xeth = xe.New(ethereum, self) self.xeth = xe.New(ethereum, self)
self.wait = self.xeth.UpdateState()
addr, _ := ethereum.Etherbase() addr, _ := self.ethereum.Etherbase()
self.coinbase = addr
self.stateDb = self.ethereum.ChainManager().State().Copy()
// initialise the registry contracts // initialise the registry contracts
reg := registrar.New(self.xeth) reg := registrar.New(self.xeth)
err = reg.SetGlobalRegistrar("", addr)
if err != nil {
t.Errorf("error creating GlobalRegistrar: %v", err)
}
err = reg.SetHashReg("", addr) err = reg.SetHashReg("", addr)
if err != nil { if err != nil {
t.Errorf("error creating HashReg: %v", err) t.Errorf("error creating HashReg: %v", err)
@ -164,84 +169,75 @@ func testInit(t *testing.T) (self *testFrontend) {
if err != nil { if err != nil {
t.Errorf("error creating UrlHint: %v", err) t.Errorf("error creating UrlHint: %v", err)
} }
self.applyTxs() if !processTxs(self, t, 7) {
t.Errorf("error mining txs")
}
return 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 // end to end test
func TestNatspecE2E(t *testing.T) { func TestNatspecE2E(t *testing.T) {
t.Skip()
tf := testInit(t) tf := testInit(t)
defer tf.ethereum.Stop() defer tf.ethereum.Stop()
addr, _ := tf.ethereum.Etherbase()
// create a contractInfo file (mock cloud-deployed contract metadocs) // create a contractInfo file (mock cloud-deployed contract metadocs)
// incidentally this is the info for the registry contract itself // incidentally this is the info for the registry contract itself
ioutil.WriteFile("/tmp/"+testFileName, []byte(testContractInfo), os.ModePerm) 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 // take the codehash for the contract we wanna test
// codehex := tf.xeth.CodeAt(registar.HashRegAddr)
codeb := tf.xeth.CodeAtBytes(registrar.HashRegAddr) codeb := tf.xeth.CodeAtBytes(registrar.HashRegAddr)
codehash := common.BytesToHash(crypto.Sha3(codeb)) codehash := crypto.Sha3Hash(codeb)
// use resolver to register codehash->dochash->url // use resolver to register codehash->dochash->url
// test if globalregistry works // test if globalregistry works
// registrar.HashRefAddr = "0x0" // registrar.HashRefAddr = "0x0"
// registrar.UrlHintAddr = "0x0" // registrar.UrlHintAddr = "0x0"
reg := registrar.New(tf.xeth) reg := registrar.New(tf.xeth)
_, err := reg.SetHashToHash(tf.coinbase, codehash, dochash) _, err := reg.SetHashToHash(addr, codehash, dochash)
if err != nil { if err != nil {
t.Errorf("error registering: %v", err) t.Errorf("error registering: %v", err)
} }
_, err = reg.SetUrlToHash(tf.coinbase, dochash, "file:///"+testFileName) _, err = reg.SetUrlToHash(addr, dochash, "file:///"+testFileName)
if err != nil { if err != nil {
t.Errorf("error registering: %v", err) t.Errorf("error registering: %v", err)
} }
// apply txs to the state if !processTxs(tf, t, 5) {
tf.applyTxs() return
}
// NatSpec info for register method of HashReg contract installed // NatSpec info for register method of HashReg contract installed
// now using the same transactions to check confirm messages // now using the same transactions to check confirm messages
tf.wantNatSpec = true // this is set so now the backend uses natspec confirmation 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 { if err != nil {
t.Errorf("error calling contract registry: %v", err) t.Errorf("error calling contract registry: %v", err)
} }
fmt.Printf("GlobalRegistrar: %v, HashReg: %v, UrlHint: %v\n", registrar.GlobalRegistrarAddr, registrar.HashRegAddr, registrar.UrlHintAddr) fmt.Printf("GlobalRegistrar: %v, HashReg: %v, UrlHint: %v\n", registrar.GlobalRegistrarAddr, registrar.HashRegAddr, registrar.UrlHintAddr)
if tf.lastConfirm != testExpNotice { 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 // test unknown method
exp := fmt.Sprintf(testExpNotice2, registrar.HashRegAddr) exp := fmt.Sprintf(testExpNotice2, registrar.HashRegAddr)
_, err = reg.SetOwner(tf.coinbase) _, err = reg.SetOwner(addr)
if err != nil { if err != nil {
t.Errorf("error setting owner: %v", err) t.Errorf("error setting owner: %v", err)
} }
if tf.lastConfirm != exp { 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 // test unknown contract
exp = fmt.Sprintf(testExpNotice3, registrar.UrlHintAddr) 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 { if err != nil {
t.Errorf("error registering: %v", err) t.Errorf("error registering: %v", err)
} }
@ -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
}

View File

@ -339,22 +339,15 @@ func (self *Registrar) HashToUrl(chash common.Hash) (uri string, err error) {
key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(idx))) key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(idx)))
hex := self.backend.StorageAt(UrlHintAddr[2:], key) hex := self.backend.StorageAt(UrlHintAddr[2:], key)
str = string(common.Hex2Bytes(hex[2:])) str = string(common.Hex2Bytes(hex[2:]))
l := len(str) l := 0
for (l > 0) && (str[l-1] == 0) { for (l < len(str)) && (str[l] == 0) {
l-- l++
} }
str = str[:l] str = str[l:]
uri = uri + str uri = uri + str
idx++ idx++
} }
l := 0
for (l < len(uri)) && (uri[l] == 0) {
l++
}
uri = uri[l:]
if len(uri) == 0 { if len(uri) == 0 {
err = fmt.Errorf("GetURLhint: URL hint not found for '%v'", chash.Hex()) err = fmt.Errorf("GetURLhint: URL hint not found for '%v'", chash.Hex())
} }

View File

@ -203,34 +203,6 @@ func (self *XEth) AtStateNum(num int64) *XEth {
return self.WithState(st) 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 { func (self *XEth) WithState(statedb *state.StateDB) *XEth {
xeth := &XEth{ xeth := &XEth{
backend: self.backend, backend: self.backend,