From 9d152d6191349316d610208af2f55ef578785355 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 22 Apr 2015 10:58:11 +0200 Subject: [PATCH 1/4] common: delete BinaryLength The test is failing the 32bit build and the function is not used anywhere. --- common/bytes.go | 11 ----------- common/bytes_test.go | 14 -------------- 2 files changed, 25 deletions(-) diff --git a/common/bytes.go b/common/bytes.go index 5d1245107..d279156b4 100644 --- a/common/bytes.go +++ b/common/bytes.go @@ -106,17 +106,6 @@ func ReadVarInt(buff []byte) (ret uint64) { return } -// Binary length -// -// Returns the true binary length of the given number -func BinaryLength(num int) int { - if num == 0 { - return 0 - } - - return 1 + BinaryLength(num>>8) -} - // Copy bytes // // Returns an exact copy of the provided bytes diff --git a/common/bytes_test.go b/common/bytes_test.go index 4b00aa49b..069af984c 100644 --- a/common/bytes_test.go +++ b/common/bytes_test.go @@ -79,20 +79,6 @@ func (s *BytesSuite) TestReadVarInt(c *checker.C) { c.Assert(res1, checker.Equals, exp1) } -func (s *BytesSuite) TestBinaryLength(c *checker.C) { - data1 := 0 - data2 := 920987656789 - - exp1 := 0 - exp2 := 5 - - res1 := BinaryLength(data1) - res2 := BinaryLength(data2) - - c.Assert(res1, checker.Equals, exp1) - c.Assert(res2, checker.Equals, exp2) -} - func (s *BytesSuite) TestCopyBytes(c *checker.C) { data1 := []byte{1, 2, 3, 4} exp1 := []byte{1, 2, 3, 4} From 96e2b6bc0749cde5ad76c51fba55c31f941512b6 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 22 Apr 2015 10:58:43 +0200 Subject: [PATCH 2/4] miner: use 32bit atomic operations 64bit atomic operations are not available on all 32bit platforms. --- miner/worker.go | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index d5ffb398a..dc1f04d87 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -66,7 +66,6 @@ type worker struct { mux *event.TypeMux quit chan struct{} pow pow.PoW - atWork int64 eth core.Backend chain *core.ChainManager @@ -84,7 +83,9 @@ type worker struct { txQueueMu sync.Mutex txQueue map[common.Hash]*types.Transaction - mining int64 + // atomic status counters + mining int32 + atWork int32 } func newWorker(coinbase common.Address, eth core.Backend) *worker { @@ -127,19 +128,19 @@ func (self *worker) start() { agent.Start() } - atomic.StoreInt64(&self.mining, 1) + atomic.StoreInt32(&self.mining, 1) } func (self *worker) stop() { - if atomic.LoadInt64(&self.mining) == 1 { + if atomic.LoadInt32(&self.mining) == 1 { // stop all agents for _, agent := range self.agents { agent.Stop() } } - atomic.StoreInt64(&self.mining, 0) - atomic.StoreInt64(&self.atWork, 0) + atomic.StoreInt32(&self.mining, 0) + atomic.StoreInt32(&self.atWork, 0) } func (self *worker) register(agent Agent) { @@ -162,7 +163,7 @@ out: self.possibleUncles[ev.Block.Hash()] = ev.Block self.uncleMu.Unlock() case core.TxPreEvent: - if atomic.LoadInt64(&self.mining) == 0 { + if atomic.LoadInt32(&self.mining) == 0 { self.commitNewWork() } } @@ -177,7 +178,7 @@ out: func (self *worker) wait() { for { for block := range self.recv { - atomic.AddInt64(&self.atWork, -1) + atomic.AddInt32(&self.atWork, -1) if block == nil { continue @@ -205,13 +206,13 @@ func (self *worker) wait() { } func (self *worker) push() { - if atomic.LoadInt64(&self.mining) == 1 { + if atomic.LoadInt32(&self.mining) == 1 { self.current.block.Header().GasUsed = self.current.totalUsedGas self.current.block.SetRoot(self.current.state.Root()) // push new work to agents for _, agent := range self.agents { - atomic.AddInt64(&self.atWork, 1) + atomic.AddInt32(&self.atWork, 1) if agent.Work() != nil { agent.Work() <- self.current.block.Copy() @@ -320,7 +321,7 @@ func (self *worker) commitNewWork() { } // We only care about logging if we're actually mining - if atomic.LoadInt64(&self.mining) == 1 { + if atomic.LoadInt32(&self.mining) == 1 { glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles\n", self.current.block.Number(), tcount, len(uncles)) } From 635b66acdccc1e9b3793c67a846675dfbb08b6f8 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 22 Apr 2015 10:59:15 +0200 Subject: [PATCH 3/4] p2p: return zero node from Self if the server is not running This helps with fixing the tests for cmd/geth to run without networking. --- p2p/server.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/p2p/server.go b/p2p/server.go index b5c4a1f59..ecf418d13 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -283,6 +283,11 @@ func (srv *Server) Stop() { // Self returns the local node's endpoint information. func (srv *Server) Self() *discover.Node { + srv.lock.RLock() + defer srv.lock.RUnlock() + if !srv.running { + return &discover.Node{IP: net.ParseIP("0.0.0.0")} + } return srv.ntab.Self() } @@ -471,7 +476,7 @@ func (srv *Server) checkPeer(id discover.NodeID) (bool, DiscReason) { return false, DiscTooManyPeers case srv.peers[id] != nil: return false, DiscAlreadyConnected - case id == srv.Self().ID: + case id == srv.ntab.Self().ID: return false, DiscSelf default: return true, 0 From e1f616fadf4fe20030d518d0c3f2a3f05186ab68 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 22 Apr 2015 10:59:27 +0200 Subject: [PATCH 4/4] cmd/geth: improve the JS tests These changes ensure that the JS tests run without networking and fixes the block chain export and its associated test. --- cmd/geth/admin.go | 25 +---- cmd/geth/js_test.go | 263 ++++++++++++-------------------------------- 2 files changed, 75 insertions(+), 213 deletions(-) diff --git a/cmd/geth/admin.go b/cmd/geth/admin.go index bd09291bf..e75ff047a 100644 --- a/cmd/geth/admin.go +++ b/cmd/geth/admin.go @@ -3,7 +3,6 @@ package main import ( "errors" "fmt" - "os" "time" "github.com/ethereum/go-ethereum/cmd/utils" @@ -318,7 +317,7 @@ func (js *jsre) newAccount(call otto.FunctionCall) otto.Value { fmt.Printf("Could not create the account: %v", err) return otto.UndefinedValue() } - return js.re.ToVal(common.Bytes2Hex(acct.Address)) + return js.re.ToVal("0x" + common.Bytes2Hex(acct.Address)) } func (js *jsre) nodeInfo(call otto.FunctionCall) otto.Value { @@ -334,33 +333,15 @@ func (js *jsre) importChain(call otto.FunctionCall) otto.Value { fmt.Println("err: require file name") return otto.FalseValue() } - fn, err := call.Argument(0).ToString() if err != nil { fmt.Println(err) return otto.FalseValue() } - - var fh *os.File - fh, err = os.OpenFile(fn, os.O_RDONLY, os.ModePerm) - if err != nil { - fmt.Println(err) + if err := utils.ImportChain(js.ethereum.ChainManager(), fn); err != nil { + fmt.Println("Import error: ", err) return otto.FalseValue() } - defer fh.Close() - - var blocks types.Blocks - if err = rlp.Decode(fh, &blocks); err != nil { - fmt.Println(err) - return otto.FalseValue() - } - - js.ethereum.ChainManager().Reset() - if err = js.ethereum.ChainManager().InsertChain(blocks); err != nil { - fmt.Println(err) - return otto.FalseValue() - } - return otto.TrueValue() } diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go index 4421b1d68..521039121 100644 --- a/cmd/geth/js_test.go +++ b/cmd/geth/js_test.go @@ -3,260 +3,141 @@ package main import ( "fmt" "io/ioutil" + "path/filepath" "os" "path" "testing" - "github.com/robertkrimen/otto" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" + "runtime" + "regexp" + "strconv" ) var port = 30300 -func testJEthRE(t *testing.T) (repl *jsre, ethereum *eth.Ethereum, err error) { - os.RemoveAll("/tmp/eth/") - err = os.MkdirAll("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/", os.ModePerm) +func testJEthRE(t *testing.T) (*jsre, *eth.Ethereum) { + tmp, err := ioutil.TempDir("", "geth-test") if err != nil { - t.Errorf("%v", err) - return + t.Fatal(err) } - err = os.MkdirAll("/tmp/eth/data", os.ModePerm) - if err != nil { - t.Errorf("%v", err) - return - } - // FIXME: this does not work ATM - ks := crypto.NewKeyStorePlain("/tmp/eth/keys") - ioutil.WriteFile("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/e273f01c99144c438695e10f24926dc1f9fbf62d", - []byte(`{"Id":"RhRXD+fNRKS4jx+7ZfEsNA==","Address":"4nPwHJkUTEOGleEPJJJtwfn79i0=","PrivateKey":"h4ACVpe74uIvi5Cg/2tX/Yrm2xdr3J7QoMbMtNX2CNc="}`), os.ModePerm) + defer os.RemoveAll(tmp) - port++ - ethereum, err = eth.New(ð.Config{ - DataDir: "/tmp/eth", + ks := crypto.NewKeyStorePlain(filepath.Join(tmp, "keys")) + ethereum, err := eth.New(ð.Config{ + DataDir: tmp, AccountManager: accounts.NewManager(ks), - Port: fmt.Sprintf("%d", port), - MaxPeers: 10, + MaxPeers: 0, Name: "test", }) - if err != nil { - t.Errorf("%v", err) - return + t.Fatal("%v", err) } assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext") - repl = newJSRE(ethereum, assetPath, false) - return + repl := newJSRE(ethereum, assetPath, false) + return repl, ethereum } func TestNodeInfo(t *testing.T) { - repl, ethereum, err := testJEthRE(t) - if err != nil { - t.Errorf("error creating jsre, got %v", err) - return - } - err = ethereum.Start() - if err != nil { - t.Errorf("error starting ethereum: %v", err) - return + repl, ethereum := testJEthRE(t) + if err := ethereum.Start(); err != nil { + t.Fatalf("error starting ethereum: %v", err) } defer ethereum.Stop() - val, err := repl.re.Run("admin.nodeInfo()") - if err != nil { - t.Errorf("expected no error, got %v", err) - } - exp, err := val.Export() - if err != nil { - t.Errorf("expected no error, got %v", err) - } - nodeInfo, ok := exp.(*eth.NodeInfo) - if !ok { - t.Errorf("expected nodeInfo, got %v", err) - } - exp = "test" - got := nodeInfo.Name - if exp != got { - t.Errorf("expected %v, got %v", exp, got) - } - exp = 30301 - port := nodeInfo.DiscPort - if exp != port { - t.Errorf("expected %v, got %v", exp, port) - } - exp = 30301 - port = nodeInfo.TCPPort - if exp != port { - t.Errorf("expected %v, got %v", exp, port) - } + want := `{"DiscPort":0,"IP":"0.0.0.0","ListenAddr":"","Name":"test","NodeID":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","NodeUrl":"enode://00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000@0.0.0.0:0","TCPPort":0,"Td":"0"}` + checkEvalJSON(t, repl, `admin.nodeInfo()`, want) } func TestAccounts(t *testing.T) { - repl, ethereum, err := testJEthRE(t) - if err != nil { - t.Errorf("error creating jsre, got %v", err) - return - } - err = ethereum.Start() - if err != nil { - t.Errorf("error starting ethereum: %v", err) - return + repl, ethereum := testJEthRE(t) + if err := ethereum.Start(); err != nil { + t.Fatalf("error starting ethereum: %v", err) } defer ethereum.Stop() - val, err := repl.re.Run("eth.coinbase") + checkEvalJSON(t, repl, `eth.accounts`, `[]`) + checkEvalJSON(t, repl, `eth.coinbase`, `"0x"`) + + val, err := repl.re.Run(`admin.newAccount("password")`) if err != nil { t.Errorf("expected no error, got %v", err) } - - pp, err := repl.re.PrettyPrint(val) - if err != nil { - t.Errorf("%v", err) - } - - if !val.IsString() { - t.Errorf("incorrect type, expected string, got %v: %v", val, pp) - } - strVal, _ := val.ToString() - expected := "0xe273f01c99144c438695e10f24926dc1f9fbf62d" - if strVal != expected { - t.Errorf("incorrect result, expected %s, got %v", expected, strVal) - } - - val, err = repl.re.Run(`admin.newAccount("password")`) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - addr, err := val.ToString() - if err != nil { - t.Errorf("expected string, got %v", err) - } - - val, err = repl.re.Run("eth.accounts") - if err != nil { - t.Errorf("expected no error, got %v", err) - } - exp, err := val.Export() - if err != nil { - t.Errorf("expected no error, got %v", err) - } - interfaceAddr, ok := exp.([]interface{}) - if !ok { - t.Errorf("expected []string, got %T", exp) - } - - addrs := make([]string, len(interfaceAddr)) - for i, addr := range interfaceAddr { - var ok bool - if addrs[i], ok = addr.(string); !ok { - t.Errorf("expected addrs[%d] to be string. Got %T instead", i, addr) - } - } - - if len(addrs) != 2 || (addr != addrs[0][2:] && addr != addrs[1][2:]) { - t.Errorf("expected addrs == [, ], got %v (%v)", addrs, addr) + addr := val.String() + if !regexp.MustCompile(`0x[0-9a-f]{40}`).MatchString(addr) { + t.Errorf("address not hex: %q", addr) } + checkEvalJSON(t, repl, `eth.accounts`, `["` + addr + `"]`) + checkEvalJSON(t, repl, `eth.coinbase`, `"` + addr + `"`) } func TestBlockChain(t *testing.T) { - repl, ethereum, err := testJEthRE(t) - if err != nil { - t.Errorf("error creating jsre, got %v", err) - return - } - err = ethereum.Start() - if err != nil { - t.Errorf("error starting ethereum: %v", err) - return + repl, ethereum := testJEthRE(t) + if err := ethereum.Start(); err != nil { + t.Fatalf("error starting ethereum: %v", err) } defer ethereum.Stop() - // should get current block - val0, err := repl.re.Run("admin.debug.dumpBlock()") + // get current block dump before export/import. + val, err := repl.re.Run("JSON.stringify(admin.debug.dumpBlock())") if err != nil { t.Errorf("expected no error, got %v", err) } + beforeExport := val.String() - fn := "/tmp/eth/data/blockchain.0" - _, err = repl.re.Run("admin.export(\"" + fn + "\")") + // do the export + tmp, err := ioutil.TempDir("", "geth-test-export") if err != nil { - t.Errorf("expected no error, got %v", err) + t.Fatal(err) } - if _, err = os.Stat(fn); err != nil { - t.Errorf("expected no error on file, got %v", err) + defer os.RemoveAll(tmp) + tmpfile := filepath.Join(tmp, "export.chain") + tmpfileq := strconv.Quote(tmpfile) + + checkEvalJSON(t, repl, `admin.export(` + tmpfileq + `)`, `true`) + if _, err := os.Stat(tmpfile); err != nil { + t.Fatal(err) } - _, err = repl.re.Run("admin.import(\"" + fn + "\")") - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - var val1 otto.Value - - // should get current block - val1, err = repl.re.Run("admin.debug.dumpBlock()") - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - // FIXME: neither != , nor reflect.DeepEqual works, doing string comparison - v0 := fmt.Sprintf("%v", val0) - v1 := fmt.Sprintf("%v", val1) - if v0 != v1 { - t.Errorf("expected same head after export-import, got %v (!=%v)", v1, v0) - } + // check import, verify that dumpBlock gives the same result. + checkEvalJSON(t, repl, `admin.import(` + tmpfileq + `)`, `true`) + checkEvalJSON(t, repl, `admin.debug.dumpBlock()`, beforeExport) } func TestMining(t *testing.T) { - repl, ethereum, err := testJEthRE(t) - if err != nil { - t.Errorf("error creating jsre, got %v", err) - return - } - err = ethereum.Start() - if err != nil { - t.Errorf("error starting ethereum: %v", err) - return + repl, ethereum := testJEthRE(t) + if err := ethereum.Start(); err != nil { + t.Fatalf("error starting ethereum: %v", err) } defer ethereum.Stop() - val, err := repl.re.Run("eth.mining") - if err != nil { - t.Errorf("expected no error, got %v", err) - } - var mining bool - mining, err = val.ToBoolean() - if err != nil { - t.Errorf("expected boolean, got %v", err) - } - if mining { - t.Errorf("expected false (not mining), got true") - } - + checkEvalJSON(t, repl, `eth.mining`, `false`) } func TestRPC(t *testing.T) { - repl, ethereum, err := testJEthRE(t) - if err != nil { - t.Errorf("error creating jsre, got %v", err) - return - } - err = ethereum.Start() - if err != nil { + repl, ethereum := testJEthRE(t) + if err := ethereum.Start(); err != nil { t.Errorf("error starting ethereum: %v", err) return } defer ethereum.Stop() - val, err := repl.re.Run(`admin.startRPC("127.0.0.1", 5004)`) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - success, _ := val.ToBoolean() - if !success { - t.Errorf("expected true (started), got false") - } + checkEvalJSON(t, repl, `admin.startRPC("127.0.0.1", 5004)`, `true`) +} + +func checkEvalJSON(t *testing.T, re *jsre, expr, want string) error { + val, err := re.re.Run("JSON.stringify("+ expr + ")") + if err == nil && val.String() != want { + err = fmt.Errorf("Output mismatch for `%s`:\ngot: %s\nwant: %s", expr, val.String(), want) + } + if err != nil { + _, file, line, _ := runtime.Caller(1) + file = path.Base(file) + fmt.Printf("\t%s:%d: %v\n", file, line, err) + t.Fail() + } + return err }