From 1208ac83d5a93214f23bf3f9236e29869ee62407 Mon Sep 17 00:00:00 2001
From: zelig <viktor.tron@gmail.com>
Date: Sun, 5 Jul 2015 19:19:42 +0100
Subject: [PATCH] fix natspec test * registar url string retrieval chop leading
 zeros now * rewrite test using test mining * remove temporary applyTxs from
 xeth

---
 cmd/geth/js_test.go                |   2 +-
 common/docserver/docserver.go      |  11 +--
 common/docserver/docserver_test.go |   2 +-
 common/natspec/natspec_e2e_test.go | 122 +++++++++++++++++++++--------
 common/registrar/registrar.go      |  15 +---
 xeth/xeth.go                       |  28 -------
 6 files changed, 99 insertions(+), 81 deletions(-)

diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go
index 791218997a..eaab3acaa3 100644
--- a/cmd/geth/js_test.go
+++ b/cmd/geth/js_test.go
@@ -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
diff --git a/common/docserver/docserver.go b/common/docserver/docserver.go
index c890cd3f56..6b0cd31308 100644
--- a/common/docserver/docserver.go
+++ b/common/docserver/docserver.go
@@ -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
 }
@@ -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
diff --git a/common/docserver/docserver_test.go b/common/docserver/docserver_test.go
index 09b16864a7..ca126071c7 100644
--- a/common/docserver/docserver_test.go
+++ b/common/docserver/docserver_test.go
@@ -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 {
diff --git a/common/natspec/natspec_e2e_test.go b/common/natspec/natspec_e2e_test.go
index a941acbba1..c66304e315 100644
--- a/common/natspec/natspec_e2e_test.go
+++ b/common/natspec/natspec_e2e_test.go
@@ -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"
@@ -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
 }
@@ -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 {
@@ -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)
@@ -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)
 	}
@@ -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
+}
diff --git a/common/registrar/registrar.go b/common/registrar/registrar.go
index 457dd68942..2622317628 100644
--- a/common/registrar/registrar.go
+++ b/common/registrar/registrar.go
@@ -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())
 	}
diff --git a/xeth/xeth.go b/xeth/xeth.go
index f2295e6e15..a3923436af 100644
--- a/xeth/xeth.go
+++ b/xeth/xeth.go
@@ -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,