diff options
75 files changed, 1601 insertions, 1170 deletions
diff --git a/blockpool/blockpool.go b/blockpool/blockpool.go index bc998cd7b..c5af481a7 100644 --- a/blockpool/blockpool.go +++ b/blockpool/blockpool.go @@ -1,12 +1,12 @@ package blockpool import ( - "bytes" "fmt" "math/big" "sync" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/errs" ethlogger "github.com/ethereum/go-ethereum/logger" @@ -101,7 +101,7 @@ func (self *Config) init() { // node is the basic unit of the internal model of block chain/tree in the blockpool type node struct { lock sync.RWMutex - hash []byte + hash common.Hash block *types.Block hashBy string blockBy string @@ -123,7 +123,7 @@ type BlockPool struct { Config *Config // the minimal interface with blockchain - hasBlock func(hash []byte) bool + hasBlock func(hash common.Hash) bool insertChain func(types.Blocks) error verifyPoW func(pow.Block) bool @@ -133,7 +133,7 @@ type BlockPool struct { lock sync.RWMutex chainLock sync.RWMutex // alloc-easy pool of hash slices - hashSlicePool chan [][]byte + hashSlicePool chan []common.Hash status *status @@ -144,7 +144,7 @@ type BlockPool struct { // public constructor func New( - hasBlock func(hash []byte) bool, + hasBlock func(hash common.Hash) bool, insertChain func(types.Blocks) error, verifyPoW func(pow.Block) bool, ) *BlockPool { @@ -176,7 +176,7 @@ func (self *BlockPool) Start() { } self.Config.init() - self.hashSlicePool = make(chan [][]byte, 150) + self.hashSlicePool = make(chan []common.Hash, 150) self.status = newStatus() self.quit = make(chan bool) self.pool = make(map[string]*entry) @@ -261,14 +261,13 @@ Peer info is currently not persisted across disconnects (or sessions) */ func (self *BlockPool) AddPeer( - td *big.Int, currentBlockHash []byte, + td *big.Int, currentBlockHash common.Hash, peerId string, - requestBlockHashes func([]byte) error, - requestBlocks func([][]byte) error, + requestBlockHashes func(common.Hash) error, + requestBlocks func([]common.Hash) error, peerError func(*errs.Error), ) (best bool) { - return self.peers.addPeer(td, currentBlockHash, peerId, requestBlockHashes, requestBlocks, peerError) } @@ -289,7 +288,7 @@ launches all block request processes on each chain section the first argument is an iterator function. Using this block hashes are decoded from the rlp message payload on demand. As a result, AddBlockHashes needs to run synchronously for one peer since the message is discarded if the caller thread returns. */ -func (self *BlockPool) AddBlockHashes(next func() ([]byte, bool), peerId string) { +func (self *BlockPool) AddBlockHashes(next func() (common.Hash, bool), peerId string) { bestpeer, best := self.peers.getPeer(peerId) if !best { @@ -306,7 +305,7 @@ func (self *BlockPool) AddBlockHashes(next func() ([]byte, bool), peerId string) self.status.lock.Unlock() var n int - var hash []byte + var hash common.Hash var ok, headSection, peerswitch bool var sec, child, parent *section var entry *entry @@ -318,7 +317,7 @@ func (self *BlockPool) AddBlockHashes(next func() ([]byte, bool), peerId string) plog.Debugf("AddBlockHashes: peer <%s> starting from [%s] (peer head: %s)", peerId, hex(bestpeer.parentHash), hex(bestpeer.currentBlockHash)) // first check if we are building the head section of a peer's chain - if bytes.Equal(bestpeer.parentHash, hash) { + if bestpeer.parentHash == hash { if self.hasBlock(bestpeer.currentBlockHash) { return } @@ -561,7 +560,7 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) { entry := self.get(hash) // a peer's current head block is appearing the first time - if bytes.Equal(hash, sender.currentBlockHash) { + if hash == sender.currentBlockHash { if sender.currentBlock == nil { plog.Debugf("AddBlock: add head block %s for peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash)) sender.setChainInfoFromBlock(block) @@ -664,7 +663,7 @@ LOOP: plog.DebugDetailf("activateChain: section [%s] activated by peer <%s>", sectionhex(sec), p.id) sec.activate(p) if i > 0 && connected != nil { - connected[string(sec.top.hash)] = sec + connected[sec.top.hash.Str()] = sec } /* we need to relink both complete and incomplete sections @@ -696,7 +695,7 @@ LOOP: // must run in separate go routine, otherwise // switchpeer -> activateChain -> activate deadlocks on section process select and peers.lock -func (self *BlockPool) requestBlocks(attempts int, hashes [][]byte) { +func (self *BlockPool) requestBlocks(attempts int, hashes []common.Hash) { self.wg.Add(1) go func() { self.peers.requestBlocks(attempts, hashes) @@ -718,16 +717,16 @@ func (self *BlockPool) getChild(sec *section) *section { } // accessor and setter for entries in the pool -func (self *BlockPool) get(hash []byte) *entry { +func (self *BlockPool) get(hash common.Hash) *entry { self.lock.RLock() defer self.lock.RUnlock() - return self.pool[string(hash)] + return self.pool[hash.Str()] } -func (self *BlockPool) set(hash []byte, e *entry) { +func (self *BlockPool) set(hash common.Hash, e *entry) { self.lock.Lock() defer self.lock.Unlock() - self.pool[string(hash)] = e + self.pool[hash.Str()] = e } func (self *BlockPool) remove(sec *section) { @@ -736,7 +735,7 @@ func (self *BlockPool) remove(sec *section) { defer self.lock.Unlock() for _, node := range sec.nodes { - delete(self.pool, string(node.hash)) + delete(self.pool, node.hash.Str()) } if sec.initialised && sec.poolRootIndex != 0 { self.status.lock.Lock() @@ -745,17 +744,17 @@ func (self *BlockPool) remove(sec *section) { } } -func (self *BlockPool) getHashSlice() (s [][]byte) { +func (self *BlockPool) getHashSlice() (s []common.Hash) { select { case s = <-self.hashSlicePool: default: - s = make([][]byte, self.Config.BlockBatchSize) + s = make([]common.Hash, self.Config.BlockBatchSize) } return } // Return returns a Client to the pool. -func (self *BlockPool) putHashSlice(s [][]byte) { +func (self *BlockPool) putHashSlice(s []common.Hash) { if len(s) == self.Config.BlockBatchSize { select { case self.hashSlicePool <- s: @@ -765,8 +764,8 @@ func (self *BlockPool) putHashSlice(s [][]byte) { } // pretty prints hash (byte array) with first 4 bytes in hex -func hex(hash []byte) (name string) { - if hash == nil { +func hex(hash common.Hash) (name string) { + if (hash == common.Hash{}) { name = "" } else { name = fmt.Sprintf("%x", hash[:4]) diff --git a/blockpool/peers.go b/blockpool/peers.go index 5f4889792..d94d6ac46 100644 --- a/blockpool/peers.go +++ b/blockpool/peers.go @@ -1,16 +1,15 @@ package blockpool import ( - "bytes" "math/big" "math/rand" "sort" "sync" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/errs" - "github.com/ethereum/go-ethereum/common" ) type peer struct { @@ -18,20 +17,20 @@ type peer struct { // last known blockchain status td *big.Int - currentBlockHash []byte + currentBlockHash common.Hash currentBlock *types.Block - parentHash []byte + parentHash common.Hash headSection *section id string // peer callbacks - requestBlockHashes func([]byte) error - requestBlocks func([][]byte) error + requestBlockHashes func(common.Hash) error + requestBlocks func([]common.Hash) error peerError func(*errs.Error) errors *errs.Errors - sections [][]byte + sections []common.Hash // channels to push new head block and head section for peer a currentBlockC chan *types.Block @@ -66,10 +65,10 @@ type peers struct { // peer constructor func (self *peers) newPeer( td *big.Int, - currentBlockHash []byte, + currentBlockHash common.Hash, id string, - requestBlockHashes func([]byte) error, - requestBlocks func([][]byte) error, + requestBlockHashes func(common.Hash) error, + requestBlocks func([]common.Hash) error, peerError func(*errs.Error), ) (p *peer) { @@ -107,7 +106,7 @@ func (self *peer) addError(code int, format string, params ...interface{}) { self.peerError(err) } -func (self *peer) setChainInfo(td *big.Int, c []byte) { +func (self *peer) setChainInfo(td *big.Int, c common.Hash) { self.lock.Lock() defer self.lock.Unlock() @@ -115,7 +114,7 @@ func (self *peer) setChainInfo(td *big.Int, c []byte) { self.currentBlockHash = c self.currentBlock = nil - self.parentHash = nil + self.parentHash = common.Hash{} self.headSection = nil } @@ -139,7 +138,7 @@ func (self *peer) setChainInfoFromBlock(block *types.Block) { }() } -func (self *peers) requestBlocks(attempts int, hashes [][]byte) { +func (self *peers) requestBlocks(attempts int, hashes []common.Hash) { // distribute block request among known peers self.lock.RLock() defer self.lock.RUnlock() @@ -178,18 +177,18 @@ func (self *peers) requestBlocks(attempts int, hashes [][]byte) { // returns true iff peer is promoted as best peer in the pool func (self *peers) addPeer( td *big.Int, - currentBlockHash []byte, + currentBlockHash common.Hash, id string, - requestBlockHashes func([]byte) error, - requestBlocks func([][]byte) error, + requestBlockHashes func(common.Hash) error, + requestBlocks func([]common.Hash) error, peerError func(*errs.Error), ) (best bool) { - var previousBlockHash []byte + var previousBlockHash common.Hash self.lock.Lock() p, found := self.peers[id] if found { - if !bytes.Equal(p.currentBlockHash, currentBlockHash) { + if p.currentBlockHash != currentBlockHash { previousBlockHash = p.currentBlockHash plog.Debugf("addPeer: Update peer <%s> with td %v and current block %s (was %v)", id, td, hex(currentBlockHash), hex(previousBlockHash)) p.setChainInfo(td, currentBlockHash) @@ -221,7 +220,7 @@ func (self *peers) addPeer( // new block update for active current best peer -> request hashes plog.Debugf("addPeer: <%s> already the best peer. Request new head section info from %s", id, hex(currentBlockHash)) - if previousBlockHash != nil { + if (previousBlockHash != common.Hash{}) { if entry := self.bp.get(previousBlockHash); entry != nil { p.headSectionC <- nil self.bp.activateChain(entry.section, p, nil) @@ -318,15 +317,15 @@ func (self *BlockPool) switchPeer(oldp, newp *peer) { } var connected = make(map[string]*section) - var sections [][]byte + var sections []common.Hash for _, hash := range newp.sections { plog.DebugDetailf("activate chain starting from section [%s]", hex(hash)) // if section not connected (ie, top of a contiguous sequence of sections) - if connected[string(hash)] == nil { + if connected[hash.Str()] == nil { // if not deleted, then reread from pool (it can be orphaned top half of a split section) if entry := self.get(hash); entry != nil { self.activateChain(entry.section, newp, connected) - connected[string(hash)] = entry.section + connected[hash.Str()] = entry.section sections = append(sections, hash) } } @@ -396,7 +395,7 @@ func (self *peer) getCurrentBlock(currentBlock *types.Block) { plog.DebugDetailf("HeadSection: <%s> head block %s found in blockpool", self.id, hex(self.currentBlockHash)) } else { plog.DebugDetailf("HeadSection: <%s> head block %s not found... requesting it", self.id, hex(self.currentBlockHash)) - self.requestBlocks([][]byte{self.currentBlockHash}) + self.requestBlocks([]common.Hash{self.currentBlockHash}) self.blocksRequestTimer = time.After(self.bp.Config.BlocksRequestInterval) return } @@ -427,9 +426,9 @@ func (self *peer) getBlockHashes() { self.addError(ErrInvalidBlock, "%v", err) self.bp.status.badPeers[self.id]++ } else { - headKey := string(self.parentHash) + headKey := self.parentHash.Str() height := self.bp.status.chain[headKey] + 1 - self.bp.status.chain[string(self.currentBlockHash)] = height + self.bp.status.chain[self.currentBlockHash.Str()] = height if height > self.bp.status.values.LongestChain { self.bp.status.values.LongestChain = height } diff --git a/blockpool/section.go b/blockpool/section.go index 03c4f5cc6..c73aaa6df 100644 --- a/blockpool/section.go +++ b/blockpool/section.go @@ -4,6 +4,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) @@ -27,9 +28,9 @@ type section struct { nodes []*node peer *peer - parentHash []byte + parentHash common.Hash - blockHashes [][]byte + blockHashes []common.Hash poolRootIndex int @@ -115,7 +116,7 @@ func (self *section) addSectionToBlockChain(p *peer) { break } self.poolRootIndex-- - keys = append(keys, string(node.hash)) + keys = append(keys, node.hash.Str()) blocks = append(blocks, block) } @@ -166,9 +167,9 @@ func (self *section) addSectionToBlockChain(p *peer) { self.bp.status.lock.Lock() if err == nil { - headKey := string(blocks[0].ParentHash()) + headKey := blocks[0].ParentHash().Str() height := self.bp.status.chain[headKey] + len(blocks) - self.bp.status.chain[string(blocks[len(blocks)-1].Hash())] = height + self.bp.status.chain[blocks[len(blocks)-1].Hash().Str()] = height if height > self.bp.status.values.LongestChain { self.bp.status.values.LongestChain = height } @@ -316,7 +317,7 @@ LOOP: self.addSectionToBlockChain(self.peer) } } else { - if self.parentHash == nil && n == self.bottom { + if (self.parentHash == common.Hash{}) && n == self.bottom { self.parentHash = block.ParentHash() plog.DebugDetailf("[%s] got parent head block hash %s...checking", sectionhex(self), hex(self.parentHash)) self.blockHashesRequest() @@ -456,7 +457,7 @@ func (self *section) blockHashesRequest() { // a demoted peer's fork will be chosen over the best peer's chain // because relinking the correct chain (activateChain) is overwritten here in // demoted peer's section process just before the section is put to idle mode - if self.parentHash != nil { + if (self.parentHash != common.Hash{}) { if parent := self.bp.get(self.parentHash); parent != nil { parentSection = parent.section plog.DebugDetailf("[%s] blockHashesRequest: parent section [%s] linked\n", sectionhex(self), sectionhex(parentSection)) diff --git a/cmd/ethereum/admin.go b/cmd/ethereum/admin.go index 880a22c22..41aaf46d8 100644 --- a/cmd/ethereum/admin.go +++ b/cmd/ethereum/admin.go @@ -8,8 +8,8 @@ import ( "time" "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/state" @@ -221,13 +221,10 @@ func (js *jsre) exportChain(call otto.FunctionCall) otto.Value { fmt.Println(err) return otto.FalseValue() } - - data := js.ethereum.ChainManager().Export() - if err := common.WriteFile(fn, data); err != nil { + if err := utils.ExportChain(js.ethereum.ChainManager(), fn); err != nil { fmt.Println(err) return otto.FalseValue() } - return otto.TrueValue() } @@ -239,7 +236,7 @@ func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value { block = js.ethereum.ChainManager().GetBlockByNumber(uint64(num)) } else if call.Argument(0).IsString() { hash, _ := call.Argument(0).ToString() - block = js.ethereum.ChainManager().GetBlock(common.Hex2Bytes(hash)) + block = js.ethereum.ChainManager().GetBlock(common.HexToHash(hash)) } else { fmt.Println("invalid argument for dump. Either hex string or number") } diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 38c04ec9d..afaf06948 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -314,7 +314,7 @@ func dump(ctx *cli.Context) { for _, arg := range ctx.Args() { var block *types.Block if hashish(arg) { - block = chainmgr.GetBlock(common.Hex2Bytes(arg)) + block = chainmgr.GetBlock(common.HexToHash(arg)) } else { num, _ := strconv.Atoi(arg) block = chainmgr.GetBlockByNumber(uint64(num)) diff --git a/cmd/ethtest/main.go b/cmd/ethtest/main.go index cf1ec6dfa..ee6bcc540 100644 --- a/cmd/ethtest/main.go +++ b/cmd/ethtest/main.go @@ -24,6 +24,7 @@ package main import ( "bytes" "encoding/json" + "fmt" "io" "io/ioutil" "log" @@ -33,6 +34,7 @@ import ( "strings" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/state" @@ -66,7 +68,7 @@ type Account struct { } func StateObjectFromAccount(db common.Database, addr string, account Account) *state.StateObject { - obj := state.NewStateObject(common.Hex2Bytes(addr), db) + obj := state.NewStateObject(common.HexToAddress(addr), db) obj.SetBalance(common.Big(account.Balance)) if common.IsHex(account.Code) { @@ -112,7 +114,7 @@ func RunVmTest(r io.Reader) (failed int) { for name, test := range tests { db, _ := ethdb.NewMemDatabase() - statedb := state.New(nil, db) + statedb := state.New(common.Hash{}, db) for addr, account := range test.Pre { obj := StateObjectFromAccount(db, addr, account) statedb.SetStateObject(obj) @@ -135,63 +137,82 @@ func RunVmTest(r io.Reader) (failed int) { rexp := helper.FromHex(test.Out) if bytes.Compare(rexp, ret) != 0 { - helper.Log.Infof("FAIL: %s's return failed. Expected %x, got %x\n", name, rexp, ret) + helper.Log.Infof("%s's return failed. Expected %x, got %x\n", name, rexp, ret) failed = 1 } for addr, account := range test.Post { - obj := statedb.GetStateObject(helper.FromHex(addr)) + obj := statedb.GetStateObject(common.HexToAddress(addr)) if obj == nil { continue } if len(test.Exec) == 0 { if obj.Balance().Cmp(common.Big(account.Balance)) != 0 { - helper.Log.Infof("FAIL: %s's : (%x) balance failed. Expected %v, got %v => %v\n", - name, - obj.Address()[:4], - account.Balance, - obj.Balance(), - new(big.Int).Sub(common.Big(account.Balance), obj.Balance()), - ) + helper.Log.Infof("%s's : (%x) balance failed. Expected %v, got %v => %v\n", name, obj.Address().Bytes()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(common.Big(account.Balance), obj.Balance())) failed = 1 } } for addr, value := range account.Storage { - v := obj.GetState(helper.FromHex(addr)).Bytes() + v := obj.GetState(common.HexToHash(addr)).Bytes() vexp := helper.FromHex(value) if bytes.Compare(v, vexp) != 0 { - helper.Log.Infof("FAIL: %s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address()[0:4], addr, vexp, v, common.BigD(vexp), common.BigD(v)) + helper.Log.Infof("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address().Bytes()[0:4], addr, vexp, v, common.BigD(vexp), common.BigD(v)) failed = 1 } } } - if !bytes.Equal(common.Hex2Bytes(test.PostStateRoot), statedb.Root()) { - helper.Log.Infof("FAIL: %s's : Post state root error. Expected %s, got %x\n", name, test.PostStateRoot, statedb.Root()) + statedb.Sync() + //if !bytes.Equal(common.Hex2Bytes(test.PostStateRoot), statedb.Root()) { + if common.HexToHash(test.PostStateRoot) != statedb.Root() { + helper.Log.Infof("%s's : Post state root failed. Expected %s, got %x", name, test.PostStateRoot, statedb.Root()) failed = 1 } if len(test.Logs) > 0 { if len(test.Logs) != len(logs) { - helper.Log.Infof("FAIL: log length mismatch. Expected %d, got %d", len(test.Logs), len(logs)) + helper.Log.Infof("log length failed. Expected %d, got %d", len(test.Logs), len(logs)) failed = 1 } else { - /* - fmt.Println("A", test.Logs) - fmt.Println("B", logs) - for i, log := range test.Logs { - genBloom := common.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 256) - if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) { - t.Errorf("bloom mismatch") + for i, log := range test.Logs { + if common.HexToAddress(log.AddressF) != logs[i].Address() { + helper.Log.Infof("'%s' log address failed. Expected %v got %x", name, log.AddressF, logs[i].Address()) + failed = 1 + } + + if !bytes.Equal(logs[i].Data(), helper.FromHex(log.DataF)) { + helper.Log.Infof("'%s' log data failed. Expected %v got %x", name, log.DataF, logs[i].Data()) + failed = 1 + } + + if len(log.TopicsF) != len(logs[i].Topics()) { + helper.Log.Infof("'%s' log topics length failed. Expected %d got %d", name, len(log.TopicsF), logs[i].Topics()) + failed = 1 + } else { + for j, topic := range log.TopicsF { + if common.HexToHash(topic) != logs[i].Topics()[j] { + helper.Log.Infof("'%s' log topic[%d] failed. Expected %v got %x", name, j, topic, logs[i].Topics()[j]) + failed = 1 } } - */ + } + genBloom := common.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 256) + + if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) { + helper.Log.Infof("'%s' bloom failed.", name) + failed = 1 + } + } } } + if failed == 1 { + fmt.Println(string(statedb.Dump())) + } + logger.Flush() } diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 74fd5334e..feea29d64 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -23,14 +23,15 @@ package utils import ( "fmt" + "io" "os" "os/signal" "regexp" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/rlp" ) @@ -152,29 +153,34 @@ func ImportChain(chainmgr *core.ChainManager, fn string) error { } defer fh.Close() - var blocks types.Blocks - if err := rlp.Decode(fh, &blocks); err != nil { - return err - } - chainmgr.Reset() - if err := chainmgr.InsertChain(blocks); err != nil { - return err + stream := rlp.NewStream(fh) + var i int + for ; ; i++ { + var b types.Block + if err := stream.Decode(&b); err == io.EOF { + break + } else if err != nil { + return fmt.Errorf("at block %d: %v", i, err) + } + if err := chainmgr.InsertChain(types.Blocks{&b}); err != nil { + return fmt.Errorf("invalid block %d: %v", i, err) + } } - fmt.Printf("imported %d blocks\n", len(blocks)) - + fmt.Printf("imported %d blocks\n", i) return nil } func ExportChain(chainmgr *core.ChainManager, fn string) error { fmt.Printf("exporting blockchain '%s'\n", fn) - - data := chainmgr.Export() - - if err := common.WriteFile(fn, data); err != nil { + fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) + if err != nil { + return err + } + defer fh.Close() + if err := chainmgr.Export(fh); err != nil { return err } fmt.Printf("exported blockchain\n") - return nil } diff --git a/common/bytes.go b/common/bytes.go index 4aef9a223..5e553d23c 100644 --- a/common/bytes.go +++ b/common/bytes.go @@ -211,7 +211,7 @@ func RightPadString(str string, l int) string { } -func Address(slice []byte) (addr []byte) { +func ToAddress(slice []byte) (addr []byte) { if len(slice) < 20 { addr = LeftPadBytes(slice, 20) } else if len(slice) > 20 { diff --git a/common/types.go b/common/types.go index 6a9abdf18..38044d5c8 100644 --- a/common/types.go +++ b/common/types.go @@ -1,6 +1,91 @@ package common +import "math/big" + +const ( + hashLength = 32 + addressLength = 20 +) + type ( - uHash [32]byte - uAddress [20]byte + Hash [hashLength]byte + Address [addressLength]byte ) + +func BytesToHash(b []byte) Hash { + var h Hash + h.SetBytes(b) + return h +} +func StringToHash(s string) Hash { return BytesToHash([]byte(s)) } +func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } +func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) } + +// Don't use the default 'String' method in case we want to overwrite + +// Get the string representation of the underlying hash +func (h Hash) Str() string { return string(h[:]) } +func (h Hash) Bytes() []byte { return h[:] } +func (h Hash) Big() *big.Int { return Bytes2Big(h[:]) } +func (h Hash) Hex() string { return "0x" + Bytes2Hex(h[:]) } + +// Sets the hash to the value of b. If b is larger than len(h) it will panic +func (h *Hash) SetBytes(b []byte) { + if len(b) > len(h) { + b = b[len(b)-hashLength:] + } + + // reverse loop + for i := len(b) - 1; i >= 0; i-- { + h[hashLength-len(b)+i] = b[i] + } +} + +// Set string `s` to h. If s is larger than len(h) it will panic +func (h *Hash) SetString(s string) { h.SetBytes([]byte(s)) } + +// Sets h to other +func (h *Hash) Set(other Hash) { + for i, v := range other { + h[i] = v + } +} + +/////////// Address +func BytesToAddress(b []byte) Address { + var a Address + a.SetBytes(b) + return a +} +func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) } +func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } +func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) } + +// Get the string representation of the underlying address +func (a Address) Str() string { return string(a[:]) } +func (a Address) Bytes() []byte { return a[:] } +func (a Address) Big() *big.Int { return Bytes2Big(a[:]) } +func (a Address) Hash() Hash { return BytesToHash(a[:]) } +func (a Address) Hex() string { return "0x" + Bytes2Hex(a[:]) } + +// Sets the address to the value of b. If b is larger than len(a) it will panic +func (a *Address) SetBytes(b []byte) { + if len(b) > len(a) { + b = b[len(b)-addressLength:] + } + + // reverse loop + for i := len(b) - 1; i >= 0; i-- { + a[addressLength-len(b)+i] = b[i] + } +} + +// Set string `s` to a. If s is larger than len(a) it will panic +func (a *Address) SetString(s string) { a.SetBytes([]byte(s)) } + +// Sets a to other +func (a *Address) Set(other Address) { + for i, v := range other { + a[i] = v + } +} diff --git a/common/types_template.go b/common/types_template.go new file mode 100644 index 000000000..1c82a36dc --- /dev/null +++ b/common/types_template.go @@ -0,0 +1,48 @@ +// +build none +//sed -e 's/_N_/Hash/g' -e 's/_S_/32/g' -e '1d' types_template.go | gofmt -w hash.go + +package common + +import "math/big" + +type _N_ [_S_]byte + +func BytesTo_N_(b []byte) _N_ { + var h _N_ + h.SetBytes(b) + return h +} +func StringTo_N_(s string) _N_ { return BytesTo_N_([]byte(s)) } +func BigTo_N_(b *big.Int) _N_ { return BytesTo_N_(b.Bytes()) } +func HexTo_N_(s string) _N_ { return BytesTo_N_(FromHex(s)) } + +// Don't use the default 'String' method in case we want to overwrite + +// Get the string representation of the underlying hash +func (h _N_) Str() string { return string(h[:]) } +func (h _N_) Bytes() []byte { return h[:] } +func (h _N_) Big() *big.Int { return Bytes2Big(h[:]) } +func (h _N_) Hex() string { return "0x" + Bytes2Hex(h[:]) } + +// Sets the hash to the value of b. If b is larger than len(h) it will panic +func (h *_N_) SetBytes(b []byte) { + // Use the right most bytes + if len(b) > len(h) { + b = b[len(b)-_S_:] + } + + // Reverse the loop + for i := len(b) - 1; i >= 0; i-- { + h[_S_-len(b)+i] = b[i] + } +} + +// Set string `s` to h. If s is larger than len(h) it will panic +func (h *_N_) SetString(s string) { h.SetBytes([]byte(s)) } + +// Sets h to other +func (h *_N_) Set(other _N_) { + for i, v := range other { + h[i] = v + } +} diff --git a/common/types_test.go b/common/types_test.go new file mode 100644 index 000000000..9f303152c --- /dev/null +++ b/common/types_test.go @@ -0,0 +1,15 @@ +package common + +import "testing" + +func TestBytesConversion(t *testing.T) { + bytes := []byte{5} + hash := BytesToHash(bytes) + + var exp Hash + exp[31] = 5 + + if hash != exp { + t.Errorf("expected %x got %x", exp, hash) + } +} diff --git a/core/block_processor.go b/core/block_processor.go index 62c9c92a6..99c5fea05 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -1,7 +1,6 @@ package core import ( - "bytes" "fmt" "math/big" "sync" @@ -78,7 +77,8 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated _, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, block), tx, cb) if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) { // If the account is managed, remove the invalid nonce. - self.bc.TxState().RemoveNonce(tx.From(), tx.Nonce()) + from, _ := tx.From() + self.bc.TxState().RemoveNonce(from, tx.Nonce()) return nil, nil, err } @@ -86,7 +86,7 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated statedb.Update(nil) cumulative := new(big.Int).Set(usedGas.Add(usedGas, gas)) - receipt := types.NewReceipt(statedb.Root(), cumulative) + receipt := types.NewReceipt(statedb.Root().Bytes(), cumulative) receipt.SetLogs(statedb.Logs()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) chainlogger.Debugln(receipt) @@ -186,7 +186,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big // Validate the received block's bloom with the one derived from the generated receipts. // For valid blocks this should always validate to true. rbloom := types.CreateBloom(receipts) - if bytes.Compare(rbloom, header.Bloom) != 0 { + if rbloom != header.Bloom { err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom) return } @@ -194,14 +194,14 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big // The transactions Trie's root (R = (Tr [[H1, T1], [H2, T2], ... [Hn, Tn]])) // can be used by light clients to make sure they've received the correct Txs txSha := types.DeriveSha(block.Transactions()) - if bytes.Compare(txSha, header.TxHash) != 0 { + if txSha != header.TxHash { err = fmt.Errorf("validating transaction root. received=%x got=%x", header.TxHash, txSha) return } // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]])) receiptSha := types.DeriveSha(receipts) - if bytes.Compare(receiptSha, header.ReceiptHash) != 0 { + if receiptSha != header.ReceiptHash { err = fmt.Errorf("validating receipt root. received=%x got=%x", header.ReceiptHash, receiptSha) return } @@ -214,7 +214,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big // Commit state objects/accounts to a temporary trie (does not save) // used to calculate the state root. state.Update(common.Big0) - if !bytes.Equal(header.Root, state.Root()) { + if header.Root != state.Root() { err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root()) return } @@ -230,7 +230,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big putTx(sm.extraDb, tx) } - chainlogger.Infof("processed block #%d (%x...)\n", header.Number, block.Hash()[0:4]) + chainlogger.Infof("processed block #%d (%x...)\n", header.Number, block.Hash().Bytes()[0:4]) return td, state.Logs(), nil } @@ -280,35 +280,34 @@ func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, paren ancestors := set.New() uncles := set.New() - ancestorHeaders := make(map[string]*types.Header) + ancestorHeaders := make(map[common.Hash]*types.Header) for _, ancestor := range sm.bc.GetAncestors(block, 7) { - hash := string(ancestor.Hash()) - ancestorHeaders[hash] = ancestor.Header() - ancestors.Add(hash) + ancestorHeaders[ancestor.Hash()] = ancestor.Header() + ancestors.Add(ancestor.Hash()) // Include ancestors uncles in the uncle set. Uncles must be unique. for _, uncle := range ancestor.Uncles() { - uncles.Add(string(uncle.Hash())) + uncles.Add(uncle.Hash()) } } - uncles.Add(string(block.Hash())) + uncles.Add(block.Hash()) for _, uncle := range block.Uncles() { - if uncles.Has(string(uncle.Hash())) { + if uncles.Has(uncle.Hash()) { // Error not unique return UncleError("Uncle not unique") } - uncles.Add(string(uncle.Hash())) + uncles.Add(uncle.Hash()) - if ancestors.Has(string(uncle.Hash())) { + if ancestors.Has(uncle.Hash()) { return UncleError("Uncle is ancestor") } - if !ancestors.Has(string(uncle.ParentHash)) { + if !ancestors.Has(uncle.ParentHash) { return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4])) } - if err := sm.ValidateHeader(uncle, ancestorHeaders[string(uncle.ParentHash)]); err != nil { + if err := sm.ValidateHeader(uncle, ancestorHeaders[uncle.ParentHash]); err != nil { return ValidationError(fmt.Sprintf("%v", err)) } @@ -354,5 +353,5 @@ func putTx(db common.Database, tx *types.Transaction) { statelogger.Infoln("Failed encoding tx", err) return } - db.Put(tx.Hash(), rlpEnc) + db.Put(tx.Hash().Bytes(), rlpEnc) } diff --git a/core/block_processor_test.go b/core/block_processor_test.go index ad29404e1..64add7e8b 100644 --- a/core/block_processor_test.go +++ b/core/block_processor_test.go @@ -4,6 +4,7 @@ import ( "math/big" "testing" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/pow/ezp" @@ -19,7 +20,7 @@ func proc() (*BlockProcessor, *ChainManager) { func TestNumber(t *testing.T) { bp, chain := proc() - block1 := chain.NewBlock(nil) + block1 := chain.NewBlock(common.Address{}) block1.Header().Number = big.NewInt(3) err := bp.ValidateHeader(block1.Header(), chain.Genesis().Header()) @@ -27,7 +28,7 @@ func TestNumber(t *testing.T) { t.Errorf("expected block number error") } - block1 = chain.NewBlock(nil) + block1 = chain.NewBlock(common.Address{}) err = bp.ValidateHeader(block1.Header(), chain.Genesis().Header()) if err == BlockNumberErr { t.Errorf("didn't expect block number error") diff --git a/core/chain_makers.go b/core/chain_makers.go index d800dee34..e3001331c 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -29,7 +29,7 @@ var ( // Utility functions for making chains on the fly // Exposed for sake of testing from other packages (eg. go-ethash) -func NewBlockFromParent(addr []byte, parent *types.Block) *types.Block { +func NewBlockFromParent(addr common.Address, parent *types.Block) *types.Block { return newBlockFromParent(addr, parent) } @@ -54,7 +54,7 @@ func NewCanonical(n int, db common.Database) (*BlockProcessor, error) { } // block time is fixed at 10 seconds -func newBlockFromParent(addr []byte, parent *types.Block) *types.Block { +func newBlockFromParent(addr common.Address, parent *types.Block) *types.Block { block := types.NewBlock(parent.Hash(), addr, parent.Root(), common.BigPow(2, 32), 0, "") block.SetUncles(nil) block.SetTransactions(nil) @@ -74,8 +74,8 @@ func newBlockFromParent(addr []byte, parent *types.Block) *types.Block { // Actually make a block by simulating what miner would do // we seed chains by the first byte of the coinbase func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db common.Database, seed int) *types.Block { - addr := common.LeftPadBytes([]byte{byte(i)}, 20) - addr[0] = byte(seed) + var addr common.Address + addr[0], addr[19] = byte(seed), byte(i) block := newBlockFromParent(addr, parent) state := state.New(block.Root(), db) cbase := state.GetOrNewStateObject(addr) diff --git a/core/chain_manager.go b/core/chain_manager.go index 64ea8957d..915fa704f 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -3,6 +3,7 @@ package core import ( "bytes" "fmt" + "io" "math/big" "sync" @@ -37,8 +38,8 @@ func CalcDifficulty(block, parent *types.Header) *big.Int { diff.Sub(parent.Difficulty, adjust) } - if diff.Cmp(GenesisDiff) < 0 { - return GenesisDiff + if diff.Cmp(min) < 0 { + return min } return diff @@ -86,7 +87,7 @@ type ChainManager struct { tsmu sync.RWMutex td *big.Int currentBlock *types.Block - lastBlockHash []byte + lastBlockHash common.Hash transState *state.StateDB txState *state.ManagedState @@ -112,7 +113,7 @@ func (self *ChainManager) Td() *big.Int { return self.td } -func (self *ChainManager) LastBlockHash() []byte { +func (self *ChainManager) LastBlockHash() common.Hash { self.mu.RLock() defer self.mu.RUnlock() @@ -126,7 +127,7 @@ func (self *ChainManager) CurrentBlock() *types.Block { return self.currentBlock } -func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) { +func (self *ChainManager) Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) { self.mu.RLock() defer self.mu.RUnlock() @@ -168,7 +169,7 @@ func (self *ChainManager) setTransState(statedb *state.StateDB) { func (bc *ChainManager) setLastBlock() { data, _ := bc.blockDb.Get([]byte("LastBlock")) if len(data) != 0 { - block := bc.GetBlock(data) + block := bc.GetBlock(common.BytesToHash(data)) bc.currentBlock = block bc.lastBlockHash = block.Hash() @@ -182,12 +183,14 @@ func (bc *ChainManager) setLastBlock() { } // Block creation & chain handling -func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block { +func (bc *ChainManager) NewBlock(coinbase common.Address) *types.Block { bc.mu.RLock() defer bc.mu.RUnlock() - var root []byte - parentHash := ZeroHash256 + var ( + root common.Hash + parentHash common.Hash + ) if bc.currentBlock != nil { root = bc.currentBlock.Header().Root @@ -234,7 +237,7 @@ func (bc *ChainManager) Reset() { } func (bc *ChainManager) removeBlock(block *types.Block) { - bc.blockDb.Delete(append(blockHashPre, block.Hash()...)) + bc.blockDb.Delete(append(blockHashPre, block.Hash().Bytes()...)) } func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) { @@ -252,35 +255,32 @@ func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) { bc.currentBlock = bc.genesisBlock } -func (self *ChainManager) Export() []byte { +// Export writes the active chain to the given writer. +func (self *ChainManager) Export(w io.Writer) error { self.mu.RLock() defer self.mu.RUnlock() - chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Header().Number) - - blocks := make([]*types.Block, int(self.currentBlock.NumberU64())+1) for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) { - blocks[block.NumberU64()] = block + if err := block.EncodeRLP(w); err != nil { + return err + } } - - return common.Encode(blocks) + return nil } func (bc *ChainManager) insert(block *types.Block) { - //encodedBlock := common.Encode(block) - bc.blockDb.Put([]byte("LastBlock"), block.Hash()) + bc.blockDb.Put([]byte("LastBlock"), block.Hash().Bytes()) bc.currentBlock = block bc.lastBlockHash = block.Hash() key := append(blockNumPre, block.Number().Bytes()...) - bc.blockDb.Put(key, bc.lastBlockHash) + bc.blockDb.Put(key, bc.lastBlockHash.Bytes()) } func (bc *ChainManager) write(block *types.Block) { - encodedBlock := common.Encode(block.RlpDataForStorage()) - - key := append(blockHashPre, block.Hash()...) - bc.blockDb.Put(key, encodedBlock) + enc, _ := rlp.EncodeToBytes((*types.StorageBlock)(block)) + key := append(blockHashPre, block.Hash().Bytes()...) + bc.blockDb.Put(key, enc) } // Accessors @@ -289,12 +289,12 @@ func (bc *ChainManager) Genesis() *types.Block { } // Block fetching methods -func (bc *ChainManager) HasBlock(hash []byte) bool { - data, _ := bc.blockDb.Get(append(blockHashPre, hash...)) +func (bc *ChainManager) HasBlock(hash common.Hash) bool { + data, _ := bc.blockDb.Get(append(blockHashPre, hash[:]...)) return len(data) != 0 } -func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain [][]byte) { +func (self *ChainManager) GetBlockHashesFromHash(hash common.Hash, max uint64) (chain []common.Hash) { block := self.GetBlock(hash) if block == nil { return @@ -317,18 +317,17 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain return } -func (self *ChainManager) GetBlock(hash []byte) *types.Block { - data, _ := self.blockDb.Get(append(blockHashPre, hash...)) +func (self *ChainManager) GetBlock(hash common.Hash) *types.Block { + data, _ := self.blockDb.Get(append(blockHashPre, hash[:]...)) if len(data) == 0 { return nil } - var block types.Block + var block types.StorageBlock if err := rlp.Decode(bytes.NewReader(data), &block); err != nil { - fmt.Println(err) + chainlogger.Errorf("invalid block RLP for hash %x: %v", hash, err) return nil } - - return &block + return (*types.Block)(&block) } func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { @@ -340,7 +339,7 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { return nil } - return self.GetBlock(key) + return self.GetBlock(common.BytesToHash(key)) } func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) { @@ -418,7 +417,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { } h := block.Header() - chainlogger.Infof("INVALID block #%v (%x)\n", h.Number, h.Hash()[:4]) + chainlogger.Infof("INVALID block #%v (%x)\n", h.Number, h.Hash().Bytes()[:4]) chainlogger.Infoln(err) chainlogger.Debugln(block) return err @@ -435,7 +434,9 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { // At this point it's possible that a different chain (fork) becomes the new canonical chain. if td.Cmp(self.td) > 0 { if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, common.Big1)) < 0 { - chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td) + chash := cblock.Hash() + hash := block.Hash() + chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, hash[:4], td, cblock.Header().Number, chash[:4], self.td) queue[i] = ChainSplitEvent{block, logs} queueEvent.splitCount++ @@ -445,10 +446,10 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { self.insert(block) jsonlogger.LogJson(&logger.EthChainNewHead{ - BlockHash: common.Bytes2Hex(block.Hash()), + BlockHash: block.Hash().Hex(), BlockNumber: block.Number(), - ChainHeadHash: common.Bytes2Hex(cblock.Hash()), - BlockPrevHash: common.Bytes2Hex(block.ParentHash()), + ChainHeadHash: cblock.Hash().Hex(), + BlockPrevHash: block.ParentHash().Hex(), }) self.setTransState(state.New(block.Root(), self.stateDb)) @@ -465,7 +466,6 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { } - // XXX put this in a goroutine? go self.eventMux.Post(queueEvent) return nil @@ -505,7 +505,9 @@ out: } } +/* // Satisfy state query interface -func (self *ChainManager) GetAccount(addr []byte) *state.StateObject { +func (self *ChainManager) GetAccount(addr common.Hash) *state.StateObject { return self.State().GetAccount(addr) } +*/ diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index 898d37f9c..e49e594a3 100644 --- a/core/chain_manager_test.go +++ b/core/chain_manager_test.go @@ -1,7 +1,6 @@ package core import ( - "bytes" "fmt" "math/big" "os" @@ -35,7 +34,7 @@ func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big // asert the bmans have the same block at i bi1 := bman.bc.GetBlockByNumber(uint64(i)).Hash() bi2 := bman2.bc.GetBlockByNumber(uint64(i)).Hash() - if bytes.Compare(bi1, bi2) != 0 { + if bi1 != bi2 { t.Fatal("chains do not have the same hash at height", i) } @@ -270,11 +269,11 @@ func TestChainInsertions(t *testing.T) { <-done } - if bytes.Equal(chain2[len(chain2)-1].Hash(), chainMan.CurrentBlock().Hash()) { + if chain2[len(chain2)-1].Hash() != chainMan.CurrentBlock().Hash() { t.Error("chain2 is canonical and shouldn't be") } - if !bytes.Equal(chain1[len(chain1)-1].Hash(), chainMan.CurrentBlock().Hash()) { + if chain1[len(chain1)-1].Hash() != chainMan.CurrentBlock().Hash() { t.Error("chain1 isn't canonical and should be") } } @@ -320,7 +319,7 @@ func TestChainMultipleInsertions(t *testing.T) { <-done } - if !bytes.Equal(chains[longest][len(chains[longest])-1].Hash(), chainMan.CurrentBlock().Hash()) { + if chains[longest][len(chains[longest])-1].Hash() != chainMan.CurrentBlock().Hash() { t.Error("Invalid canonical chain") } } diff --git a/core/error.go b/core/error.go index 69e320eb0..f6ac26cff 100644 --- a/core/error.go +++ b/core/error.go @@ -4,6 +4,8 @@ import ( "errors" "fmt" "math/big" + + "github.com/ethereum/go-ethereum/common" ) var ( @@ -21,7 +23,7 @@ func (err *ParentErr) Error() string { return err.Message } -func ParentError(hash []byte) error { +func ParentError(hash common.Hash) error { return &ParentErr{Message: fmt.Sprintf("Block's parent unknown %x", hash)} } @@ -136,7 +138,7 @@ func IsTDError(e error) bool { type KnownBlockError struct { number *big.Int - hash []byte + hash common.Hash } func (self *KnownBlockError) Error() string { diff --git a/core/execution.go b/core/execution.go index be45eeeb4..4f15fb42a 100644 --- a/core/execution.go +++ b/core/execution.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" @@ -11,26 +12,23 @@ import ( type Execution struct { env vm.Environment - address, input []byte + address *common.Address + input []byte Gas, price, value *big.Int } -func NewExecution(env vm.Environment, address, input []byte, gas, gasPrice, value *big.Int) *Execution { +func NewExecution(env vm.Environment, address *common.Address, input []byte, gas, gasPrice, value *big.Int) *Execution { return &Execution{env: env, address: address, input: input, Gas: gas, price: gasPrice, value: value} } -func (self *Execution) Addr() []byte { - return self.address -} - -func (self *Execution) Call(codeAddr []byte, caller vm.ContextRef) ([]byte, error) { +func (self *Execution) Call(codeAddr common.Address, caller vm.ContextRef) ([]byte, error) { // Retrieve the executing code code := self.env.State().GetCode(codeAddr) - return self.exec(code, codeAddr, caller) + return self.exec(&codeAddr, code, caller) } -func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret []byte, err error) { +func (self *Execution) exec(contextAddr *common.Address, code []byte, caller vm.ContextRef) (ret []byte, err error) { env := self.env evm := vm.NewVm(env) if env.Depth() == vm.MaxCallDepth { @@ -40,14 +38,15 @@ func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret } vsnapshot := env.State().Copy() - if len(self.address) == 0 { + if self.address == nil { // Generate a new address nonce := env.State().GetNonce(caller.Address()) - self.address = crypto.CreateAddress(caller.Address(), nonce) + addr := crypto.CreateAddress(caller.Address(), nonce) + self.address = &addr env.State().SetNonce(caller.Address(), nonce+1) } - from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(self.address) + from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(*self.address) err = env.Transfer(from, to, self.value) if err != nil { env.State().Set(vsnapshot) @@ -73,8 +72,8 @@ func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret } func (self *Execution) Create(caller vm.ContextRef) (ret []byte, err error, account *state.StateObject) { - ret, err = self.exec(self.input, nil, caller) - account = self.env.State().GetStateObject(self.address) + ret, err = self.exec(nil, self.input, caller) + account = self.env.State().GetStateObject(*self.address) return } diff --git a/core/filter.go b/core/filter.go index 487e82902..f1627636f 100644 --- a/core/filter.go +++ b/core/filter.go @@ -1,9 +1,9 @@ package core import ( - "bytes" "math" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/state" ) @@ -16,8 +16,8 @@ type FilterOptions struct { Earliest int64 Latest int64 - Address [][]byte - Topics [][][]byte + Address []common.Address + Topics [][]common.Hash Skip int Max int @@ -29,9 +29,9 @@ type Filter struct { earliest int64 latest int64 skip int - address [][]byte + address []common.Address max int - topics [][][]byte + topics [][]common.Hash BlockCallback func(*types.Block, state.Logs) PendingCallback func(*types.Block, state.Logs) @@ -67,11 +67,11 @@ func (self *Filter) SetLatestBlock(latest int64) { self.latest = latest } -func (self *Filter) SetAddress(addr [][]byte) { +func (self *Filter) SetAddress(addr []common.Address) { self.address = addr } -func (self *Filter) SetTopics(topics [][][]byte) { +func (self *Filter) SetTopics(topics [][]common.Hash) { self.topics = topics } @@ -131,9 +131,9 @@ func (self *Filter) Find() state.Logs { return logs[skip:] } -func includes(addresses [][]byte, a []byte) bool { +func includes(addresses []common.Address, a common.Address) bool { for _, addr := range addresses { - if !bytes.Equal(addr, a) { + if addr != a { return false } } @@ -151,13 +151,13 @@ Logs: continue } - logTopics := make([][]byte, len(self.topics)) + logTopics := make([]common.Hash, len(self.topics)) copy(logTopics, log.Topics()) for i, topics := range self.topics { for _, topic := range topics { var match bool - if bytes.Equal(log.Topics()[i], topic) { + if log.Topics()[i] == topic { match = true } if !match { @@ -176,7 +176,7 @@ func (self *Filter) bloomFilter(block *types.Block) bool { if len(self.address) > 0 { var included bool for _, addr := range self.address { - if types.BloomLookup(block.Bloom(), addr) { + if types.BloomLookup(block.Bloom(), addr.Hash()) { included = true break } diff --git a/core/genesis.go b/core/genesis.go index bfd51f196..3e00533ae 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -6,9 +6,8 @@ import ( "math/big" "os" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/state" ) @@ -19,19 +18,15 @@ import ( var ZeroHash256 = make([]byte, 32) var ZeroHash160 = make([]byte, 20) var ZeroHash512 = make([]byte, 64) -var EmptyShaList = crypto.Sha3(common.Encode([]interface{}{})) -var EmptyListRoot = crypto.Sha3(common.Encode("")) - var GenesisDiff = big.NewInt(131072) var GenesisGasLimit = big.NewInt(3141592) func GenesisBlock(db common.Database) *types.Block { - genesis := types.NewBlock(ZeroHash256, ZeroHash160, nil, GenesisDiff, 42, "") + genesis := types.NewBlock(common.Hash{}, common.Address{}, common.Hash{}, GenesisDiff, 42, "") genesis.Header().Number = common.Big0 genesis.Header().GasLimit = GenesisGasLimit genesis.Header().GasUsed = common.Big0 genesis.Header().Time = 0 - genesis.Header().MixDigest = make([]byte, 32) genesis.Td = common.Big0 @@ -49,7 +44,7 @@ func GenesisBlock(db common.Database) *types.Block { statedb := state.New(genesis.Root(), db) for addr, account := range accounts { codedAddr := common.Hex2Bytes(addr) - accountState := statedb.GetAccount(codedAddr) + accountState := statedb.GetAccount(common.BytesToAddress(codedAddr)) accountState.SetBalance(common.Big(account.Balance)) statedb.UpdateStateObject(accountState) } diff --git a/core/state_transition.go b/core/state_transition.go index 279abee62..d0b2c5d7c 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -4,8 +4,8 @@ import ( "fmt" "math/big" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" ) @@ -31,7 +31,7 @@ var () * 6) Derive new state root */ type StateTransition struct { - coinbase []byte + coinbase common.Address msg Message gas, gasPrice *big.Int initialGas *big.Int @@ -44,9 +44,10 @@ type StateTransition struct { env vm.Environment } +// Message represents a message sent to a contract. type Message interface { - From() []byte - To() []byte + From() (common.Address, error) + To() *common.Address GasPrice() *big.Int Gas() *big.Int @@ -56,13 +57,14 @@ type Message interface { Data() []byte } -func AddressFromMessage(msg Message) []byte { - // Generate a new address - return crypto.Sha3(common.NewValue([]interface{}{msg.From(), msg.Nonce()}).Encode())[12:] +func AddressFromMessage(msg Message) common.Address { + from, _ := msg.From() + + return crypto.CreateAddress(from, msg.Nonce()) } func MessageCreatesContract(msg Message) bool { - return len(msg.To()) == 0 + return msg.To() == nil } func MessageGasValue(msg Message) *big.Int { @@ -92,13 +94,18 @@ func (self *StateTransition) Coinbase() *state.StateObject { return self.state.GetOrNewStateObject(self.coinbase) } func (self *StateTransition) From() *state.StateObject { - return self.state.GetOrNewStateObject(self.msg.From()) + f, _ := self.msg.From() + return self.state.GetOrNewStateObject(f) } func (self *StateTransition) To() *state.StateObject { - if self.msg != nil && MessageCreatesContract(self.msg) { + if self.msg == nil { return nil } - return self.state.GetOrNewStateObject(self.msg.To()) + to := self.msg.To() + if to == nil { + return nil // contract creation + } + return self.state.GetOrNewStateObject(*to) } func (self *StateTransition) UseGas(amount *big.Int) error { @@ -119,7 +126,7 @@ func (self *StateTransition) BuyGas() error { sender := self.From() if sender.Balance().Cmp(MessageGasValue(self.msg)) < 0 { - return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address()[:4], MessageGasValue(self.msg), sender.Balance()) + return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], MessageGasValue(self.msg), sender.Balance()) } coinbase := self.Coinbase() @@ -196,7 +203,8 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er var ref vm.ContextRef if MessageCreatesContract(msg) { contract := makeContract(msg, self.state) - ret, err, ref = vmenv.Create(sender, contract.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value) + addr := contract.Address() + ret, err, ref = vmenv.Create(sender, &addr, self.msg.Data(), self.gas, self.gasPrice, self.value) if err == nil { dataGas := big.NewInt(int64(len(ret))) dataGas.Mul(dataGas, vm.GasCreateByte) @@ -230,7 +238,7 @@ func (self *StateTransition) refundGas() { for addr, ref := range self.state.Refunds() { refund := common.BigMin(uhalf, ref) self.gas.Add(self.gas, refund) - self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice())) + self.state.AddBalance(common.StringToAddress(addr), refund.Mul(refund, self.msg.GasPrice())) } coinbase.RefundGas(self.gas, self.msg.GasPrice()) @@ -242,7 +250,8 @@ func (self *StateTransition) gasUsed() *big.Int { // Converts an message in to a state object func makeContract(msg Message, state *state.StateDB) *state.StateObject { - addr := AddressFromMessage(msg) + faddr, _ := msg.From() + addr := crypto.CreateAddress(faddr, msg.Nonce()) contract := state.GetOrNewStateObject(addr) contract.SetInitCode(msg.Data()) diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 515cc2040..f2fe5c748 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -5,8 +5,8 @@ import ( "fmt" "sync" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" ) @@ -20,9 +20,7 @@ var ( const txPoolQueueSize = 50 type TxPoolHook chan *types.Transaction -type TxMsg struct { - Tx *types.Transaction -} +type TxMsg struct{ Tx *types.Transaction } const ( minGasPrice = 1000000 @@ -44,7 +42,7 @@ type TxPool struct { quit chan bool // The actual pool //pool *list.List - txs map[string]*types.Transaction + txs map[common.Hash]*types.Transaction SecondaryProcessor TxProcessor @@ -55,7 +53,7 @@ type TxPool struct { func NewTxPool(eventMux *event.TypeMux) *TxPool { return &TxPool{ - txs: make(map[string]*types.Transaction), + txs: make(map[common.Hash]*types.Transaction), queueChan: make(chan *types.Transaction, txPoolQueueSize), quit: make(chan bool), eventMux: eventMux, @@ -63,21 +61,16 @@ func NewTxPool(eventMux *event.TypeMux) *TxPool { } func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error { - if len(tx.To()) != 0 && len(tx.To()) != 20 { - return fmt.Errorf("Invalid recipient. len = %d", len(tx.To())) + // Validate sender + if _, err := tx.From(); err != nil { + return ErrInvalidSender } - // Validate curve param v, _, _ := tx.Curve() if v > 28 || v < 27 { return fmt.Errorf("tx.v != (28 || 27) => %v", v) } - - // Validate sender address - senderAddr := tx.From() - if senderAddr == nil || len(senderAddr) != 20 { - return ErrInvalidSender - } + return nil /* XXX this kind of validation needs to happen elsewhere in the gui when sending txs. Other clients should do their own validation. Value transfer could throw error @@ -91,19 +84,17 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error { return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.From()) } */ - - return nil } func (self *TxPool) addTx(tx *types.Transaction) { - self.txs[string(tx.Hash())] = tx + self.txs[tx.Hash()] = tx } func (self *TxPool) add(tx *types.Transaction) error { - if self.txs[string(tx.Hash())] != nil { - return fmt.Errorf("Known transaction (%x)", tx.Hash()[0:4]) + hash := tx.Hash() + if self.txs[hash] != nil { + return fmt.Errorf("Known transaction (%x)", hash[0:4]) } - err := self.ValidateTransaction(tx) if err != nil { return err @@ -111,19 +102,17 @@ func (self *TxPool) add(tx *types.Transaction) error { self.addTx(tx) - var to string - if len(tx.To()) > 0 { - to = common.Bytes2Hex(tx.To()[:4]) + var toname string + if to := tx.To(); to != nil { + toname = common.Bytes2Hex(to[:4]) } else { - to = "[NEW_CONTRACT]" + toname = "[NEW_CONTRACT]" } - var from string - if len(tx.From()) > 0 { - from = common.Bytes2Hex(tx.From()[:4]) - } else { - return errors.New(fmt.Sprintf("FROM ADDRESS MUST BE POSITIVE (was %v)", tx.From())) - } - txplogger.Debugf("(t) %x => %s (%v) %x\n", from, to, tx.Value, tx.Hash()) + // we can ignore the error here because From is + // verified in ValidateTransaction. + f, _ := tx.From() + from := common.Bytes2Hex(f[:4]) + txplogger.Debugf("(t) %x => %s (%v) %x\n", from, toname, tx.Value, tx.Hash()) // Notify the subscribers go self.eventMux.Post(TxPreEvent{tx}) @@ -140,6 +129,7 @@ func (self *TxPool) Add(tx *types.Transaction) error { defer self.mu.Unlock() return self.add(tx) } + func (self *TxPool) AddTransactions(txs []*types.Transaction) { self.mu.Lock() defer self.mu.Unlock() @@ -148,7 +138,8 @@ func (self *TxPool) AddTransactions(txs []*types.Transaction) { if err := self.add(tx); err != nil { txplogger.Debugln(err) } else { - txplogger.Debugf("tx %x\n", tx.Hash()[0:4]) + h := tx.Hash() + txplogger.Debugf("tx %x\n", h[:4]) } } } @@ -172,7 +163,8 @@ func (pool *TxPool) RemoveInvalid(query StateQuery) { var removedTxs types.Transactions for _, tx := range pool.txs { - sender := query.GetAccount(tx.From()) + from, _ := tx.From() + sender := query.GetAccount(from[:]) err := pool.ValidateTransaction(tx) if err != nil || sender.Nonce() >= tx.Nonce() { removedTxs = append(removedTxs, tx) @@ -186,14 +178,13 @@ func (pool *TxPool) RemoveInvalid(query StateQuery) { func (self *TxPool) RemoveSet(txs types.Transactions) { self.mu.Lock() defer self.mu.Unlock() - for _, tx := range txs { - delete(self.txs, string(tx.Hash())) + delete(self.txs, tx.Hash()) } } func (pool *TxPool) Flush() { - pool.txs = make(map[string]*types.Transaction) + pool.txs = make(map[common.Hash]*types.Transaction) } func (pool *TxPool) Start() { diff --git a/core/transaction_pool_test.go b/core/transaction_pool_test.go index 418cb0415..bf9012573 100644 --- a/core/transaction_pool_test.go +++ b/core/transaction_pool_test.go @@ -4,10 +4,10 @@ import ( "crypto/ecdsa" "testing" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/state" ) @@ -21,11 +21,11 @@ func SQ() stateQuery { } func (self stateQuery) GetAccount(addr []byte) *state.StateObject { - return state.NewStateObject(addr, self.db) + return state.NewStateObject(common.BytesToAddress(addr), self.db) } func transaction() *types.Transaction { - return types.NewTransactionMessage(make([]byte, 20), common.Big0, common.Big0, common.Big0, nil) + return types.NewTransactionMessage(common.Address{}, common.Big0, common.Big0, common.Big0, nil) } func setup() (*TxPool, *ecdsa.PrivateKey) { @@ -88,10 +88,8 @@ func TestRemoveInvalid(t *testing.T) { func TestInvalidSender(t *testing.T) { pool, _ := setup() - tx := new(types.Transaction) - tx.V = 28 - err := pool.ValidateTransaction(tx) + err := pool.ValidateTransaction(new(types.Transaction)) if err != ErrInvalidSender { - t.Error("expected %v, got %v", ErrInvalidSender, err) + t.Errorf("expected %v, got %v", ErrInvalidSender, err) } } diff --git a/core/types/block.go b/core/types/block.go index 2d65cdca6..6f26358fb 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -1,33 +1,33 @@ package types import ( - "bytes" "encoding/binary" "fmt" + "io" "math/big" "sort" "time" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/rlp" ) type Header struct { // Hash to the previous block - ParentHash []byte + ParentHash common.Hash // Uncles of this block - UncleHash []byte + UncleHash common.Hash // The coin base address - Coinbase []byte + Coinbase common.Address // Block Trie state - Root []byte + Root common.Hash // Tx sha - TxHash []byte + TxHash common.Hash // Receipt sha - ReceiptHash []byte + ReceiptHash common.Hash // Bloom - Bloom []byte + Bloom Bloom // Difficulty for the current block Difficulty *big.Int // The block number @@ -41,9 +41,17 @@ type Header struct { // Extra data Extra string // Mix digest for quick checking to prevent DOS - MixDigest []byte + MixDigest common.Hash // Nonce - Nonce []byte + Nonce [8]byte +} + +func (self *Header) Hash() common.Hash { + return rlpHash(self.rlpData(true)) +} + +func (self *Header) HashNoNonce() common.Hash { + return rlpHash(self.rlpData(false)) } func (self *Header) rlpData(withNonce bool) []interface{} { @@ -65,7 +73,6 @@ func (self *Header) rlpData(withNonce bool) []interface{} { if withNonce { fields = append(fields, self.MixDigest, self.Nonce) } - return fields } @@ -73,28 +80,49 @@ func (self *Header) RlpData() interface{} { return self.rlpData(true) } -func (self *Header) Hash() []byte { - return crypto.Sha3(common.Encode(self.rlpData(true))) -} - -func (self *Header) HashNoNonce() []byte { - return crypto.Sha3(common.Encode(self.rlpData(false))) +func rlpHash(x interface{}) (h common.Hash) { + hw := sha3.NewKeccak256() + rlp.Encode(hw, x) + hw.Sum(h[:0]) + return h } type Block struct { - // Preset Hash for mock - HeaderHash []byte - ParentHeaderHash []byte - header *Header - uncles []*Header - transactions Transactions - Td *big.Int + // Preset Hash for mock (Tests) + HeaderHash common.Hash + ParentHeaderHash common.Hash + // ^^^^ ignore ^^^^ + + header *Header + uncles []*Header + transactions Transactions + Td *big.Int receipts Receipts Reward *big.Int } -func NewBlock(parentHash []byte, coinbase []byte, root []byte, difficulty *big.Int, nonce uint64, extra string) *Block { +// StorageBlock defines the RLP encoding of a Block stored in the +// state database. The StorageBlock encoding contains fields that +// would otherwise need to be recomputed. +type StorageBlock Block + +// "external" block encoding. used for eth protocol, etc. +type extblock struct { + Header *Header + Txs []*Transaction + Uncles []*Header +} + +// "storage" block encoding. used for database. +type storageblock struct { + Header *Header + Txs []*Transaction + Uncles []*Header + TD *big.Int +} + +func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, difficulty *big.Int, nonce uint64, extra string) *Block { header := &Header{ Root: root, ParentHash: parentHash, @@ -105,16 +133,13 @@ func NewBlock(parentHash []byte, coinbase []byte, root []byte, difficulty *big.I GasUsed: new(big.Int), GasLimit: new(big.Int), } - header.setNonce(nonce) - + header.SetNonce(nonce) block := &Block{header: header, Reward: new(big.Int)} - return block } -func (self *Header) setNonce(nonce uint64) { - self.Nonce = make([]byte, 8) - binary.BigEndian.PutUint64(self.Nonce, nonce) +func (self *Header) SetNonce(nonce uint64) { + binary.BigEndian.PutUint64(self.Nonce[:], nonce) } func NewBlockWithHeader(header *Header) *Block { @@ -122,22 +147,40 @@ func NewBlockWithHeader(header *Header) *Block { } func (self *Block) DecodeRLP(s *rlp.Stream) error { - var extblock struct { - Header *Header - Txs []*Transaction - Uncles []*Header - TD *big.Int // optional + var eb extblock + if err := s.Decode(&eb); err != nil { + return err } - if err := s.Decode(&extblock); err != nil { + self.header, self.uncles, self.transactions = eb.Header, eb.Uncles, eb.Txs + return nil +} + +func (self Block) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, extblock{ + Header: self.header, + Txs: self.transactions, + Uncles: self.uncles, + }) +} + +func (self *StorageBlock) DecodeRLP(s *rlp.Stream) error { + var sb storageblock + if err := s.Decode(&sb); err != nil { return err } - self.header = extblock.Header - self.uncles = extblock.Uncles - self.transactions = extblock.Txs - self.Td = extblock.TD + self.header, self.uncles, self.transactions, self.Td = sb.Header, sb.Uncles, sb.Txs, sb.TD return nil } +func (self StorageBlock) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, storageblock{ + Header: self.header, + Txs: self.transactions, + Uncles: self.uncles, + TD: self.Td, + }) +} + func (self *Block) Header() *Header { return self.header } @@ -148,16 +191,16 @@ func (self *Block) Uncles() []*Header { func (self *Block) SetUncles(uncleHeaders []*Header) { self.uncles = uncleHeaders - self.header.UncleHash = crypto.Sha3(common.Encode(uncleHeaders)) + self.header.UncleHash = rlpHash(uncleHeaders) } func (self *Block) Transactions() Transactions { return self.transactions } -func (self *Block) Transaction(hash []byte) *Transaction { +func (self *Block) Transaction(hash common.Hash) *Transaction { for _, transaction := range self.transactions { - if bytes.Equal(hash, transaction.Hash()) { + if transaction.Hash() == hash { return transaction } } @@ -196,24 +239,23 @@ func (self *Block) RlpDataForStorage() interface{} { } // Header accessors (add as you need them) -func (self *Block) Number() *big.Int { return self.header.Number } -func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() } -func (self *Block) MixDigest() []byte { return self.header.MixDigest } +func (self *Block) Number() *big.Int { return self.header.Number } +func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() } +func (self *Block) MixDigest() common.Hash { return self.header.MixDigest } func (self *Block) Nonce() uint64 { - return binary.BigEndian.Uint64(self.header.Nonce) + return binary.BigEndian.Uint64(self.header.Nonce[:]) } func (self *Block) SetNonce(nonce uint64) { - self.header.setNonce(nonce) + self.header.SetNonce(nonce) } -func (self *Block) Bloom() []byte { return self.header.Bloom } -func (self *Block) Coinbase() []byte { return self.header.Coinbase } -func (self *Block) Time() int64 { return int64(self.header.Time) } -func (self *Block) GasLimit() *big.Int { return self.header.GasLimit } -func (self *Block) GasUsed() *big.Int { return self.header.GasUsed } -func (self *Block) Root() []byte { return self.header.Root } -func (self *Block) SetRoot(root []byte) { self.header.Root = root } -func (self *Block) Size() common.StorageSize { return common.StorageSize(len(common.Encode(self))) } +func (self *Block) Bloom() Bloom { return self.header.Bloom } +func (self *Block) Coinbase() common.Address { return self.header.Coinbase } +func (self *Block) Time() int64 { return int64(self.header.Time) } +func (self *Block) GasLimit() *big.Int { return self.header.GasLimit } +func (self *Block) GasUsed() *big.Int { return self.header.GasUsed } +func (self *Block) Root() common.Hash { return self.header.Root } +func (self *Block) SetRoot(root common.Hash) { self.header.Root = root } func (self *Block) GetTransaction(i int) *Transaction { if len(self.transactions) > i { return self.transactions[i] @@ -227,20 +269,33 @@ func (self *Block) GetUncle(i int) *Header { return nil } +func (self *Block) Size() common.StorageSize { + c := writeCounter(0) + rlp.Encode(&c, self) + return common.StorageSize(c) +} + +type writeCounter common.StorageSize + +func (c *writeCounter) Write(b []byte) (int, error) { + *c += writeCounter(len(b)) + return len(b), nil +} + // Implement pow.Block -func (self *Block) Difficulty() *big.Int { return self.header.Difficulty } -func (self *Block) HashNoNonce() []byte { return self.header.HashNoNonce() } +func (self *Block) Difficulty() *big.Int { return self.header.Difficulty } +func (self *Block) HashNoNonce() common.Hash { return self.header.HashNoNonce() } -func (self *Block) Hash() []byte { - if self.HeaderHash != nil { +func (self *Block) Hash() common.Hash { + if (self.HeaderHash != common.Hash{}) { return self.HeaderHash } else { return self.header.Hash() } } -func (self *Block) ParentHash() []byte { - if self.ParentHeaderHash != nil { +func (self *Block) ParentHash() common.Hash { + if (self.ParentHeaderHash != common.Hash{}) { return self.ParentHeaderHash } else { return self.header.ParentHash diff --git a/core/types/block_test.go b/core/types/block_test.go index ab1254f4c..e4f6c38a5 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -1 +1,60 @@ package types + +import ( + "bytes" + "math/big" + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" +) + +// from bcValidBlockTest.json, "SimpleTx" +func TestBlockEncoding(t *testing.T) { + blockEnc := common.FromHex("f90260f901f9a083cafc574e1f51ba9dc0568fc617a08ea2429fb384059c972f13b19fa1c8dd55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a05fe50b260da6308036625b850b5d6ced6d0a9f814c0688bc91ffb7b7a3a54b67a0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4f861f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1c0") + + var block Block + if err := rlp.DecodeBytes(blockEnc, &block); err != nil { + t.Fatal("decode error: ", err) + } + + check := func(f string, got, want interface{}) { + if !reflect.DeepEqual(got, want) { + t.Errorf("%s mismatch: got %v, want %v", f, got, want) + } + } + check("Difficulty", block.Difficulty(), big.NewInt(131072)) + check("GasLimit", block.GasLimit(), big.NewInt(3141592)) + check("GasUsed", block.GasUsed(), big.NewInt(21000)) + check("Coinbase", block.Coinbase(), common.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1")) + check("MixDigest", block.MixDigest(), common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498")) + check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017")) + check("Hash", block.Hash(), common.HexToHash("0a5843ac1cb04865017cb35a57b50b07084e5fcee39b5acadade33149f4fff9e")) + check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4)) + check("Time", block.Time(), int64(1426516743)) + check("Size", block.Size(), common.StorageSize(len(blockEnc))) + + to := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") + check("Transactions", block.Transactions(), Transactions{ + { + Payload: []byte{}, + Amount: big.NewInt(10), + Price: big.NewInt(10), + GasLimit: big.NewInt(50000), + AccountNonce: 0, + V: 27, + R: common.FromHex("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f"), + S: common.FromHex("8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1"), + Recipient: &to, + }, + }) + + ourBlockEnc, err := rlp.EncodeToBytes(&block) + if err != nil { + t.Fatal("encode error: ", err) + } + if !bytes.Equal(ourBlockEnc, blockEnc) { + t.Errorf("encoded block mismatch:\ngot: %x\nwant: %x", ourBlockEnc, blockEnc) + } +} diff --git a/core/types/bloom9.go b/core/types/bloom9.go index af76f226f..64a8ff49a 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -3,32 +3,32 @@ package types import ( "math/big" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/state" ) -func CreateBloom(receipts Receipts) []byte { +func CreateBloom(receipts Receipts) Bloom { bin := new(big.Int) for _, receipt := range receipts { bin.Or(bin, LogsBloom(receipt.logs)) } - return common.LeftPadBytes(bin.Bytes(), 256) + return BytesToBloom(bin.Bytes()) } func LogsBloom(logs state.Logs) *big.Int { bin := new(big.Int) for _, log := range logs { - data := make([][]byte, len(log.Topics())+1) - data[0] = log.Address() + data := make([]common.Hash, len(log.Topics())) + bin.Or(bin, bloom9(log.Address().Bytes())) for i, topic := range log.Topics() { - data[i+1] = topic + data[i] = topic } for _, b := range data { - bin.Or(bin, common.BigD(bloom9(crypto.Sha3(b)).Bytes())) + bin.Or(bin, bloom9(b[:])) } } @@ -36,20 +36,24 @@ func LogsBloom(logs state.Logs) *big.Int { } func bloom9(b []byte) *big.Int { + b = crypto.Sha3(b[:]) + r := new(big.Int) - for i := 0; i < 16; i += 2 { + for i := 0; i < 6; i += 2 { t := big.NewInt(1) - b := uint(b[i+1]) + 1024*(uint(b[i])&1) + b := (uint(b[i+1]) + (uint(b[i]) << 8)) & 2047 r.Or(r, t.Lsh(t, b)) } return r } -func BloomLookup(bin, topic []byte) bool { - bloom := common.BigD(bin) - cmp := bloom9(crypto.Sha3(topic)) +var Bloom9 = bloom9 + +func BloomLookup(bin Bloom, topic common.Hash) bool { + bloom := bin.Big() + cmp := bloom9(topic[:]) return bloom.And(bloom, cmp).Cmp(cmp) == 0 } diff --git a/core/types/common.go b/core/types/common.go index def7936a5..4e885c4c6 100644 --- a/core/types/common.go +++ b/core/types/common.go @@ -4,8 +4,40 @@ import ( "math/big" "github.com/ethereum/go-ethereum/state" + "github.com/ethereum/go-ethereum/common" + + "fmt" ) type BlockProcessor interface { Process(*Block) (*big.Int, state.Logs, error) } + +const bloomLength = 256 + +type Bloom [bloomLength]byte + +func BytesToBloom(b []byte) Bloom { + var bloom Bloom + bloom.SetBytes(b) + return bloom +} + +func (b *Bloom) SetBytes(d []byte) { + if len(b) < len(d) { + panic(fmt.Sprintf("bloom bytes too big %d %d", len(b), len(d))) + } + + // reverse loop + for i := len(d) - 1; i >= 0; i-- { + b[bloomLength-len(d)+i] = b[i] + } +} + +func (b Bloom) Big() *big.Int { + return common.Bytes2Big(b[:]) +} + +func (b Bloom) Bytes() []byte { + return b[:] +} diff --git a/core/types/derive_sha.go b/core/types/derive_sha.go index 593a31f1c..10e3d7446 100644 --- a/core/types/derive_sha.go +++ b/core/types/derive_sha.go @@ -1,8 +1,9 @@ package types import ( - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" ) @@ -11,12 +12,13 @@ type DerivableList interface { GetRlp(i int) []byte } -func DeriveSha(list DerivableList) []byte { +func DeriveSha(list DerivableList) common.Hash { db, _ := ethdb.NewMemDatabase() trie := trie.New(nil, db) for i := 0; i < list.Len(); i++ { - trie.Update(common.Encode(i), list.GetRlp(i)) + key, _ := rlp.EncodeToBytes(i) + trie.Update(key, list.GetRlp(i)) } - return trie.Root() + return common.BytesToHash(trie.Root()) } diff --git a/core/types/receipt.go b/core/types/receipt.go index be14d0e0e..f88d42b29 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -3,16 +3,18 @@ package types import ( "bytes" "fmt" + "io" "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/state" ) type Receipt struct { PostState []byte CumulativeGasUsed *big.Int - Bloom []byte + Bloom Bloom logs state.Logs } @@ -20,34 +22,26 @@ func NewReceipt(root []byte, cumalativeGasUsed *big.Int) *Receipt { return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumalativeGasUsed)} } -func NewRecieptFromValue(val *common.Value) *Receipt { - r := &Receipt{} - r.RlpValueDecode(val) - - return r -} - func (self *Receipt) SetLogs(logs state.Logs) { self.logs = logs } -func (self *Receipt) RlpValueDecode(decoder *common.Value) { - self.PostState = decoder.Get(0).Bytes() - self.CumulativeGasUsed = decoder.Get(1).BigInt() - self.Bloom = decoder.Get(2).Bytes() - - it := decoder.Get(3).NewIterator() - for it.Next() { - self.logs = append(self.logs, state.NewLogFromValue(it.Value())) - } +func (self *Receipt) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs}) } +/* func (self *Receipt) RlpData() interface{} { return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs.RlpData()} } +*/ func (self *Receipt) RlpEncode() []byte { - return common.Encode(self.RlpData()) + bytes, err := rlp.EncodeToBytes(self) + if err != nil { + fmt.Println("TMP -- RECEIPT ENCODE ERROR", err) + } + return bytes } func (self *Receipt) Cmp(other *Receipt) bool { @@ -64,6 +58,7 @@ func (self *Receipt) String() string { type Receipts []*Receipt +/* func (self Receipts) RlpData() interface{} { data := make([]interface{}, len(self)) for i, receipt := range self { @@ -72,9 +67,14 @@ func (self Receipts) RlpData() interface{} { return data } +*/ func (self Receipts) RlpEncode() []byte { - return common.Encode(self.RlpData()) + bytes, err := rlp.EncodeToBytes(self) + if err != nil { + fmt.Println("TMP -- RECEIPTS ENCODE ERROR", err) + } + return bytes } func (self Receipts) Len() int { return len(self) } diff --git a/core/types/transaction.go b/core/types/transaction.go index dcd48af11..391fb46f5 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -1,14 +1,14 @@ package types import ( - "bytes" "crypto/ecdsa" + "errors" "fmt" "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/secp256k1" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rlp" ) @@ -20,39 +20,34 @@ type Transaction struct { AccountNonce uint64 Price *big.Int GasLimit *big.Int - Recipient []byte + Recipient *common.Address // nil means contract creation Amount *big.Int Payload []byte V byte R, S []byte } -func NewContractCreationTx(Amount, gasAmount, price *big.Int, data []byte) *Transaction { - return NewTransactionMessage(nil, Amount, gasAmount, price, data) +func NewContractCreationTx(amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction { + return &Transaction{Recipient: nil, Amount: amount, GasLimit: gasLimit, Price: gasPrice, Payload: data} } -func NewTransactionMessage(to []byte, Amount, gasAmount, price *big.Int, data []byte) *Transaction { - return &Transaction{Recipient: to, Amount: Amount, Price: price, GasLimit: gasAmount, Payload: data} +func NewTransactionMessage(to common.Address, amount, gasAmount, gasPrice *big.Int, data []byte) *Transaction { + return &Transaction{Recipient: &to, Amount: amount, GasLimit: gasAmount, Price: gasPrice, Payload: data} } func NewTransactionFromBytes(data []byte) *Transaction { - tx := &Transaction{} - tx.RlpDecode(data) - - return tx -} - -func NewTransactionFromAmount(val *common.Value) *Transaction { - tx := &Transaction{} - tx.RlpValueDecode(val) - + // TODO: remove this function if possible. callers would + // much better off decoding into transaction directly. + // it's not that hard. + tx := new(Transaction) + rlp.DecodeBytes(data, tx) return tx } -func (tx *Transaction) Hash() []byte { - data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload} - - return crypto.Sha3(common.Encode(data)) +func (tx *Transaction) Hash() common.Hash { + return rlpHash([]interface{}{ + tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload, + }) } func (self *Transaction) Data() []byte { @@ -79,68 +74,47 @@ func (self *Transaction) SetNonce(AccountNonce uint64) { self.AccountNonce = AccountNonce } -func (self *Transaction) From() []byte { - return self.sender() +func (self *Transaction) From() (common.Address, error) { + pubkey := self.PublicKey() + if len(pubkey) == 0 || pubkey[0] != 4 { + return common.Address{}, errors.New("invalid public key") + } + var addr common.Address + copy(addr[:], crypto.Sha3(pubkey[1:])) + return addr, nil } -func (self *Transaction) To() []byte { - return self.Recipient +// To returns the recipient of the transaction. +// If transaction is a contract creation (with no recipient address) +// To returns nil. +func (tx *Transaction) To() *common.Address { + return tx.Recipient } func (tx *Transaction) Curve() (v byte, r []byte, s []byte) { v = byte(tx.V) r = common.LeftPadBytes(tx.R, 32) s = common.LeftPadBytes(tx.S, 32) - return } func (tx *Transaction) Signature(key []byte) []byte { hash := tx.Hash() - - sig, _ := secp256k1.Sign(hash, key) - + sig, _ := secp256k1.Sign(hash[:], key) return sig } func (tx *Transaction) PublicKey() []byte { hash := tx.Hash() - v, r, s := tx.Curve() - sig := append(r, s...) sig = append(sig, v-27) //pubkey := crypto.Ecrecover(append(hash, sig...)) - pubkey, _ := secp256k1.RecoverPubkey(hash, sig) - + pubkey, _ := secp256k1.RecoverPubkey(hash[:], sig) return pubkey } -func (tx *Transaction) sender() []byte { - pubkey := tx.PublicKey() - - // Validate the returned key. - // Return nil if public key isn't in full format - if len(pubkey) == 0 || pubkey[0] != 4 { - return nil - } - - return crypto.Sha3(pubkey[1:])[12:] -} - -// TODO: deprecate after new accounts & key stores are integrated -func (tx *Transaction) Sign(privk []byte) error { - - sig := tx.Signature(privk) - - tx.R = sig[:32] - tx.S = sig[32:64] - tx.V = sig[64] + 27 - - return nil -} - func (tx *Transaction) SetSignatureValues(sig []byte) error { tx.R = sig[:32] tx.S = sig[32:64] @@ -148,42 +122,40 @@ func (tx *Transaction) SetSignatureValues(sig []byte) error { return nil } -func (tx *Transaction) SignECDSA(key *ecdsa.PrivateKey) error { - return tx.Sign(crypto.FromECDSA(key)) +func (tx *Transaction) SignECDSA(prv *ecdsa.PrivateKey) error { + h := tx.Hash() + sig, err := crypto.Sign(h[:], prv) + if err != nil { + return err + } + tx.SetSignatureValues(sig) + return nil } +// TODO: remove func (tx *Transaction) RlpData() interface{} { data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload} - return append(data, tx.V, new(big.Int).SetBytes(tx.R).Bytes(), new(big.Int).SetBytes(tx.S).Bytes()) } -func (tx *Transaction) RlpEncode() []byte { - return common.Encode(tx) -} - -func (tx *Transaction) RlpDecode(data []byte) { - rlp.Decode(bytes.NewReader(data), tx) -} - -func (tx *Transaction) RlpValueDecode(decoder *common.Value) { - tx.AccountNonce = decoder.Get(0).Uint() - tx.Price = decoder.Get(1).BigInt() - tx.GasLimit = decoder.Get(2).BigInt() - tx.Recipient = decoder.Get(3).Bytes() - tx.Amount = decoder.Get(4).BigInt() - tx.Payload = decoder.Get(5).Bytes() - tx.V = decoder.Get(6).Byte() - tx.R = decoder.Get(7).Bytes() - tx.S = decoder.Get(8).Bytes() -} - func (tx *Transaction) String() string { + var from, to string + if f, err := tx.From(); err != nil { + from = "[invalid sender]" + } else { + from = fmt.Sprintf("%x", f[:]) + } + if t := tx.To(); t == nil { + to = "[contract creation]" + } else { + to = fmt.Sprintf("%x", t[:]) + } + enc, _ := rlp.EncodeToBytes(tx) return fmt.Sprintf(` TX(%x) Contract: %v - From: %x - To: %x + From: %s + To: %s Nonce: %v GasPrice: %v GasLimit %v @@ -196,8 +168,8 @@ func (tx *Transaction) String() string { `, tx.Hash(), len(tx.Recipient) == 0, - tx.From(), - tx.To(), + from, + to, tx.AccountNonce, tx.Price, tx.GasLimit, @@ -206,13 +178,14 @@ func (tx *Transaction) String() string { tx.V, tx.R, tx.S, - common.Encode(tx), + enc, ) } // Transaction slice type for basic sorting type Transactions []*Transaction +// TODO: remove func (self Transactions) RlpData() interface{} { // Marshal the transactions of this block enc := make([]interface{}, len(self)) @@ -223,9 +196,14 @@ func (self Transactions) RlpData() interface{} { return enc } -func (s Transactions) Len() int { return len(s) } -func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s Transactions) GetRlp(i int) []byte { return common.Rlp(s[i]) } + +func (s Transactions) Len() int { return len(s) } +func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +func (s Transactions) GetRlp(i int) []byte { + enc, _ := rlp.EncodeToBytes(s[i]) + return enc +} type TxByNonce struct{ Transactions } diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index ab1254f4c..0b0dfe3ff 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -1 +1,58 @@ package types + +import ( + "bytes" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" +) + +// The values in those tests are from the Transaction Tests +// at github.com/ethereum/tests. + +var ( + emptyTx = NewTransactionMessage( + common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), + big.NewInt(0), big.NewInt(0), big.NewInt(0), + nil, + ) + + rightvrsRecipient = common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b") + rightvrsTx = &Transaction{ + Recipient: &rightvrsRecipient, + AccountNonce: 3, + Price: big.NewInt(1), + GasLimit: big.NewInt(2000), + Amount: big.NewInt(10), + Payload: common.FromHex("5544"), + V: 28, + R: common.FromHex("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a"), + S: common.FromHex("8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"), + } +) + +func TestTransactionHash(t *testing.T) { + // "EmptyTransaction" + if emptyTx.Hash() != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") { + t.Errorf("empty transaction hash mismatch, got %x", emptyTx.Hash()) + } + + // "RightVRSTest" + if rightvrsTx.Hash() != common.HexToHash("fe7a79529ed5f7c3375d06b26b186a8644e0e16c373d7a12be41c62d6042b77a") { + t.Errorf("RightVRS transaction hash mismatch, got %x", rightvrsTx.Hash()) + } +} + +func TestTransactionEncode(t *testing.T) { + // "RightVRSTest" + txb, err := rlp.EncodeToBytes(rightvrsTx) + if err != nil { + t.Fatalf("encode error: %v", err) + } + should := common.FromHex("f86103018207d094b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a8255441ca098ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4aa08887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3") + if !bytes.Equal(txb, should) { + t.Errorf("encoded RLP mismatch, got %x", txb) + } +} diff --git a/core/vm_env.go b/core/vm_env.go index c7491bcdc..7845d1cd9 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -3,6 +3,7 @@ package core import ( "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" @@ -27,24 +28,24 @@ func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types } } -func (self *VMEnv) Origin() []byte { return self.msg.From() } -func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() } -func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() } -func (self *VMEnv) Time() int64 { return self.block.Time() } -func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() } -func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } -func (self *VMEnv) Value() *big.Int { return self.msg.Value() } -func (self *VMEnv) State() *state.StateDB { return self.state } -func (self *VMEnv) Depth() int { return self.depth } -func (self *VMEnv) SetDepth(i int) { self.depth = i } -func (self *VMEnv) VmType() vm.Type { return self.typ } -func (self *VMEnv) SetVmType(t vm.Type) { self.typ = t } -func (self *VMEnv) GetHash(n uint64) []byte { +func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f } +func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() } +func (self *VMEnv) Coinbase() common.Address { return self.block.Coinbase() } +func (self *VMEnv) Time() int64 { return self.block.Time() } +func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() } +func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } +func (self *VMEnv) Value() *big.Int { return self.msg.Value() } +func (self *VMEnv) State() *state.StateDB { return self.state } +func (self *VMEnv) Depth() int { return self.depth } +func (self *VMEnv) SetDepth(i int) { self.depth = i } +func (self *VMEnv) VmType() vm.Type { return self.typ } +func (self *VMEnv) SetVmType(t vm.Type) { self.typ = t } +func (self *VMEnv) GetHash(n uint64) common.Hash { if block := self.chain.GetBlockByNumber(n); block != nil { return block.Hash() } - return nil + return common.Hash{} } func (self *VMEnv) AddLog(log state.Log) { self.state.AddLog(log) @@ -53,20 +54,21 @@ func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { return vm.Transfer(from, to, amount) } -func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *Execution { +func (self *VMEnv) vm(addr *common.Address, data []byte, gas, price, value *big.Int) *Execution { return NewExecution(self, addr, data, gas, price, value) } -func (self *VMEnv) Call(me vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) { - exe := self.vm(addr, data, gas, price, value) +func (self *VMEnv) Call(me vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { + exe := self.vm(&addr, data, gas, price, value) return exe.Call(addr, me) } -func (self *VMEnv) CallCode(me vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) { - exe := self.vm(me.Address(), data, gas, price, value) +func (self *VMEnv) CallCode(me vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { + maddr := me.Address() + exe := self.vm(&maddr, data, gas, price, value) return exe.Call(addr, me) } -func (self *VMEnv) Create(me vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { +func (self *VMEnv) Create(me vm.ContextRef, addr *common.Address, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { exe := self.vm(addr, data, gas, price, value) return exe.Create(me) } diff --git a/crypto/crypto.go b/crypto/crypto.go index bc72928ac..c3d47b629 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -16,10 +16,11 @@ import ( "errors" "code.google.com/p/go-uuid/uuid" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/crypto/sha3" - "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" "golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/ripemd160" ) @@ -37,9 +38,20 @@ func Sha3(data ...[]byte) []byte { return d.Sum(nil) } +func Sha3Hash(data ...[]byte) (h common.Hash) { + d := sha3.NewKeccak256() + for _, b := range data { + d.Write(b) + } + d.Sum(h[:0]) + return h +} + // Creates an ethereum address given the bytes and the nonce -func CreateAddress(b []byte, nonce uint64) []byte { - return Sha3(common.NewValue([]interface{}{b, nonce}).Encode())[12:] +func CreateAddress(b common.Address, nonce uint64) common.Address { + data, _ := rlp.EncodeToBytes([]interface{}{b, nonce}) + return common.BytesToAddress(Sha3(data)[12:]) + //return Sha3(common.NewValue([]interface{}{b, nonce}).Encode())[12:] } func Sha256(data []byte) []byte { diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index 754287641..63a9c3f5e 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -7,8 +7,8 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/secp256k1" ) // These tests are sanity checks. @@ -21,6 +21,12 @@ func TestSha3(t *testing.T) { checkhash(t, "Sha3-256", func(in []byte) []byte { return Sha3(in) }, msg, exp) } +func TestSha3Hash(t *testing.T) { + msg := []byte("abc") + exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45") + checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := Sha3Hash(in); return h[:] }, msg, exp) +} + func TestSha256(t *testing.T) { msg := []byte("abc") exp, _ := hex.DecodeString("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") diff --git a/eth/backend.go b/eth/backend.go index c1aa28f3c..afe314d74 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -295,7 +295,7 @@ func (s *Ethereum) StartMining() error { servlogger.Errorf("Cannot start mining without coinbase: %v\n", err) return fmt.Errorf("no coinbase: %v", err) } - s.miner.Start(cb) + s.miner.Start(common.BytesToAddress(cb)) return nil } @@ -405,7 +405,7 @@ func (self *Ethereum) txBroadcastLoop() { // automatically stops if unsubscribe for obj := range self.txSub.Chan() { event := obj.(core.TxPreEvent) - self.net.Broadcast("eth", TxMsg, event.Tx.RlpData()) + self.net.Broadcast("eth", TxMsg, []*types.Transaction{event.Tx}) } } @@ -414,7 +414,7 @@ func (self *Ethereum) blockBroadcastLoop() { for obj := range self.blockSub.Chan() { switch ev := obj.(type) { case core.NewMinedBlockEvent: - self.net.Broadcast("eth", NewBlockMsg, ev.Block.RlpData(), ev.Block.Td) + self.net.Broadcast("eth", NewBlockMsg, []interface{}{ev.Block, ev.Block.Td}) } } } diff --git a/eth/protocol.go b/eth/protocol.go index 1d4322886..6d610a663 100644 --- a/eth/protocol.go +++ b/eth/protocol.go @@ -1,7 +1,6 @@ package eth import ( - "bytes" "fmt" "math/big" @@ -78,29 +77,37 @@ type txPool interface { } type chainManager interface { - GetBlockHashesFromHash(hash []byte, amount uint64) (hashes [][]byte) - GetBlock(hash []byte) (block *types.Block) - Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) + GetBlockHashesFromHash(hash common.Hash, amount uint64) (hashes []common.Hash) + GetBlock(hash common.Hash) (block *types.Block) + Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) } type blockPool interface { - AddBlockHashes(next func() ([]byte, bool), peerId string) + AddBlockHashes(next func() (common.Hash, bool), peerId string) AddBlock(block *types.Block, peerId string) - AddPeer(td *big.Int, currentBlock []byte, peerId string, requestHashes func([]byte) error, requestBlocks func([][]byte) error, peerError func(*errs.Error)) (best bool) + AddPeer(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool) RemovePeer(peerId string) } -// message structs used for rlp decoding +// message structs used for RLP serialization type newBlockMsgData struct { Block *types.Block TD *big.Int } type getBlockHashesMsgData struct { - Hash []byte + Hash common.Hash Amount uint64 } +type statusMsgData struct { + ProtocolVersion uint32 + NetworkId uint32 + TD *big.Int + CurrentBlock common.Hash + GenesisBlock common.Hash +} + // main entrypoint, wrappers starting a server running the eth protocol // use this constructor to attach the protocol ("class") to server caps // the Dev p2p layer then runs the protocol instance on each peer @@ -133,18 +140,25 @@ func runEthProtocol(protocolVersion, networkId int, txPool txPool, chainManager }, id: fmt.Sprintf("%x", id[:8]), } - err = self.handleStatus() - if err == nil { - self.propagateTxs() - for { - err = self.handle() - if err != nil { - self.blockPool.RemovePeer(self.id) - break - } + + // handshake. + if err := self.handleStatus(); err != nil { + return err + } + defer self.blockPool.RemovePeer(self.id) + + // propagate existing transactions. new transactions appearing + // after this will be sent via broadcasts. + if err := p2p.Send(rw, TxMsg, txPool.GetTransactions()); err != nil { + return err + } + + // main loop. handle incoming messages. + for { + if err := self.handle(); err != nil { + return err } } - return } func (self *ethProtocol) handle() error { @@ -171,7 +185,7 @@ func (self *ethProtocol) handle() error { } for _, tx := range txs { jsonlogger.LogJson(&logger.EthTxReceived{ - TxHash: common.Bytes2Hex(tx.Hash()), + TxHash: tx.Hash().Hex(), RemoteId: self.peer.ID().String(), }) } @@ -187,7 +201,7 @@ func (self *ethProtocol) handle() error { request.Amount = maxHashes } hashes := self.chainManager.GetBlockHashesFromHash(request.Hash, request.Amount) - return p2p.EncodeMsg(self.rw, BlockHashesMsg, common.ByteSliceToInterface(hashes)...) + return p2p.Send(self.rw, BlockHashesMsg, hashes) case BlockHashesMsg: msgStream := rlp.NewStream(msg.Payload) @@ -196,14 +210,16 @@ func (self *ethProtocol) handle() error { } var i int - iter := func() (hash []byte, ok bool) { - hash, err := msgStream.Bytes() + iter := func() (hash common.Hash, ok bool) { + var h common.Hash + err := msgStream.Decode(&h) if err == rlp.EOL { - return nil, false + return common.Hash{}, false } else if err != nil { self.protoError(ErrDecode, "msg %v: after %v hashes : %v", msg, i, err) - return nil, false + return common.Hash{}, false } + i++ return hash, true } @@ -215,18 +231,18 @@ func (self *ethProtocol) handle() error { return err } - var blocks []interface{} + var blocks []*types.Block var i int for { i++ - var hash []byte - if err := msgStream.Decode(&hash); err != nil { - if err == rlp.EOL { - break - } else { - return self.protoError(ErrDecode, "msg %v: %v", msg, err) - } + var hash common.Hash + err := msgStream.Decode(&hash) + if err == rlp.EOL { + break + } else if err != nil { + return self.protoError(ErrDecode, "msg %v: %v", msg, err) } + block := self.chainManager.GetBlock(hash) if block != nil { blocks = append(blocks, block) @@ -235,7 +251,7 @@ func (self *ethProtocol) handle() error { break } } - return p2p.EncodeMsg(self.rw, BlocksMsg, blocks...) + return p2p.Send(self.rw, BlocksMsg, blocks) case BlocksMsg: msgStream := rlp.NewStream(msg.Payload) @@ -263,10 +279,10 @@ func (self *ethProtocol) handle() error { _, chainHead, _ := self.chainManager.Status() jsonlogger.LogJson(&logger.EthChainReceivedNewBlock{ - BlockHash: common.Bytes2Hex(hash), + BlockHash: hash.Hex(), BlockNumber: request.Block.Number(), // this surely must be zero - ChainHeadHash: common.Bytes2Hex(chainHead), - BlockPrevHash: common.Bytes2Hex(request.Block.ParentHash()), + ChainHeadHash: chainHead.Hex(), + BlockPrevHash: request.Block.ParentHash().Hex(), RemoteId: self.peer.ID().String(), }) // to simplify backend interface adding a new block @@ -282,29 +298,8 @@ func (self *ethProtocol) handle() error { return nil } -type statusMsgData struct { - ProtocolVersion uint32 - NetworkId uint32 - TD *big.Int - CurrentBlock []byte - GenesisBlock []byte -} - -func (self *ethProtocol) statusMsg() p2p.Msg { - td, currentBlock, genesisBlock := self.chainManager.Status() - - return p2p.NewMsg(StatusMsg, - uint32(self.protocolVersion), - uint32(self.networkId), - td, - currentBlock, - genesisBlock, - ) -} - func (self *ethProtocol) handleStatus() error { - // send precanned status message - if err := self.rw.WriteMsg(self.statusMsg()); err != nil { + if err := self.sendStatus(); err != nil { return err } @@ -313,11 +308,9 @@ func (self *ethProtocol) handleStatus() error { if err != nil { return err } - if msg.Code != StatusMsg { return self.protoError(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg) } - if msg.Size > ProtocolMaxMsgSize { return self.protoError(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize) } @@ -329,7 +322,7 @@ func (self *ethProtocol) handleStatus() error { _, _, genesisBlock := self.chainManager.Status() - if !bytes.Equal(status.GenesisBlock, genesisBlock) { + if status.GenesisBlock != genesisBlock { return self.protoError(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock, genesisBlock) } @@ -348,14 +341,14 @@ func (self *ethProtocol) handleStatus() error { return nil } -func (self *ethProtocol) requestBlockHashes(from []byte) error { +func (self *ethProtocol) requestBlockHashes(from common.Hash) error { self.peer.Debugf("fetching hashes (%d) %x...\n", maxHashes, from[0:4]) - return p2p.EncodeMsg(self.rw, GetBlockHashesMsg, interface{}(from), uint64(maxHashes)) + return p2p.Send(self.rw, GetBlockHashesMsg, getBlockHashesMsgData{from, maxHashes}) } -func (self *ethProtocol) requestBlocks(hashes [][]byte) error { +func (self *ethProtocol) requestBlocks(hashes []common.Hash) error { self.peer.Debugf("fetching %v blocks", len(hashes)) - return p2p.EncodeMsg(self.rw, GetBlocksMsg, common.ByteSliceToInterface(hashes)...) + return p2p.Send(self.rw, GetBlocksMsg, hashes) } func (self *ethProtocol) protoError(code int, format string, params ...interface{}) (err *errs.Error) { @@ -364,19 +357,20 @@ func (self *ethProtocol) protoError(code int, format string, params ...interface return } +func (self *ethProtocol) sendStatus() error { + td, currentBlock, genesisBlock := self.chainManager.Status() + return p2p.Send(self.rw, StatusMsg, &statusMsgData{ + ProtocolVersion: uint32(self.protocolVersion), + NetworkId: uint32(self.networkId), + TD: td, + CurrentBlock: currentBlock, + GenesisBlock: genesisBlock, + }) +} + func (self *ethProtocol) protoErrorDisconnect(err *errs.Error) { err.Log(self.peer.Logger) if err.Fatal() { self.peer.Disconnect(p2p.DiscSubprotocolError) } } - -func (self *ethProtocol) propagateTxs() { - transactions := self.txPool.GetTransactions() - iface := make([]interface{}, len(transactions)) - for i, transaction := range transactions { - iface[i] = transaction - } - - self.rw.WriteMsg(p2p.NewMsg(TxMsg, iface...)) -} diff --git a/eth/protocol_test.go b/eth/protocol_test.go index 108fb4475..7620b3854 100644 --- a/eth/protocol_test.go +++ b/eth/protocol_test.go @@ -1,8 +1,6 @@ package eth import ( - "bytes" - "io" "log" "math/big" "os" @@ -29,52 +27,21 @@ func logInit() { } } -type testMsgReadWriter struct { - in chan p2p.Msg - out []p2p.Msg -} - -func (self *testMsgReadWriter) In(msg p2p.Msg) { - self.in <- msg -} - -func (self *testMsgReadWriter) Out() (msg p2p.Msg, ok bool) { - if len(self.out) > 0 { - msg = self.out[0] - self.out = self.out[1:] - ok = true - } - return -} - -func (self *testMsgReadWriter) WriteMsg(msg p2p.Msg) error { - self.out = append(self.out, msg) - return nil -} - -func (self *testMsgReadWriter) ReadMsg() (p2p.Msg, error) { - msg, ok := <-self.in - if !ok { - return msg, io.EOF - } - return msg, nil -} - type testTxPool struct { getTransactions func() []*types.Transaction addTransactions func(txs []*types.Transaction) } type testChainManager struct { - getBlockHashes func(hash []byte, amount uint64) (hashes [][]byte) - getBlock func(hash []byte) *types.Block - status func() (td *big.Int, currentBlock []byte, genesisBlock []byte) + getBlockHashes func(hash common.Hash, amount uint64) (hashes []common.Hash) + getBlock func(hash common.Hash) *types.Block + status func() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) } type testBlockPool struct { - addBlockHashes func(next func() ([]byte, bool), peerId string) + addBlockHashes func(next func() (common.Hash, bool), peerId string) addBlock func(block *types.Block, peerId string) (err error) - addPeer func(td *big.Int, currentBlock []byte, peerId string, requestHashes func([]byte) error, requestBlocks func([][]byte) error, peerError func(*errs.Error)) (best bool) + addPeer func(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool) removePeer func(peerId string) } @@ -93,28 +60,28 @@ func (self *testTxPool) AddTransactions(txs []*types.Transaction) { func (self *testTxPool) GetTransactions() types.Transactions { return nil } -func (self *testChainManager) GetBlockHashesFromHash(hash []byte, amount uint64) (hashes [][]byte) { +func (self *testChainManager) GetBlockHashesFromHash(hash common.Hash, amount uint64) (hashes []common.Hash) { if self.getBlockHashes != nil { hashes = self.getBlockHashes(hash, amount) } return } -func (self *testChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) { +func (self *testChainManager) Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) { if self.status != nil { td, currentBlock, genesisBlock = self.status() } return } -func (self *testChainManager) GetBlock(hash []byte) (block *types.Block) { +func (self *testChainManager) GetBlock(hash common.Hash) (block *types.Block) { if self.getBlock != nil { block = self.getBlock(hash) } return } -func (self *testBlockPool) AddBlockHashes(next func() ([]byte, bool), peerId string) { +func (self *testBlockPool) AddBlockHashes(next func() (common.Hash, bool), peerId string) { if self.addBlockHashes != nil { self.addBlockHashes(next, peerId) } @@ -126,7 +93,7 @@ func (self *testBlockPool) AddBlock(block *types.Block, peerId string) { } } -func (self *testBlockPool) AddPeer(td *big.Int, currentBlock []byte, peerId string, requestBlockHashes func([]byte) error, requestBlocks func([][]byte) error, peerError func(*errs.Error)) (best bool) { +func (self *testBlockPool) AddPeer(td *big.Int, currentBlock common.Hash, peerId string, requestBlockHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool) { if self.addPeer != nil { best = self.addPeer(td, currentBlock, peerId, requestBlockHashes, requestBlocks, peerError) } @@ -147,28 +114,36 @@ func testPeer() *p2p.Peer { } type ethProtocolTester struct { + p2p.MsgReadWriter // writing to the tester feeds the protocol + quit chan error - rw *testMsgReadWriter // p2p.MsgReadWriter - txPool *testTxPool // txPool - chainManager *testChainManager // chainManager - blockPool *testBlockPool // blockPool + pipe *p2p.MsgPipeRW // the protocol read/writes on this end + txPool *testTxPool // txPool + chainManager *testChainManager // chainManager + blockPool *testBlockPool // blockPool t *testing.T } func newEth(t *testing.T) *ethProtocolTester { + p1, p2 := p2p.MsgPipe() return ðProtocolTester{ - quit: make(chan error), - rw: &testMsgReadWriter{in: make(chan p2p.Msg, 10)}, - txPool: &testTxPool{}, - chainManager: &testChainManager{}, - blockPool: &testBlockPool{}, - t: t, + MsgReadWriter: p1, + quit: make(chan error, 1), + pipe: p2, + txPool: &testTxPool{}, + chainManager: &testChainManager{}, + blockPool: &testBlockPool{}, + t: t, } } func (self *ethProtocolTester) reset() { - self.rw = &testMsgReadWriter{in: make(chan p2p.Msg, 10)} - self.quit = make(chan error) + self.pipe.Close() + + p1, p2 := p2p.MsgPipe() + self.MsgReadWriter = p1 + self.pipe = p2 + self.quit = make(chan error, 1) } func (self *ethProtocolTester) checkError(expCode int, delay time.Duration) (err error) { @@ -190,33 +165,8 @@ func (self *ethProtocolTester) checkError(expCode int, delay time.Duration) (err return } -func (self *ethProtocolTester) In(msg p2p.Msg) { - self.rw.In(msg) -} - -func (self *ethProtocolTester) Out() (p2p.Msg, bool) { - return self.rw.Out() -} - -func (self *ethProtocolTester) checkMsg(i int, code uint64, val interface{}) (msg p2p.Msg) { - if i >= len(self.rw.out) { - self.t.Errorf("expected at least %v msgs, got %v", i, len(self.rw.out)) - return - } - msg = self.rw.out[i] - if msg.Code != code { - self.t.Errorf("expected msg code %v, got %v", code, msg.Code) - } - if val != nil { - if err := msg.Decode(val); err != nil { - self.t.Errorf("rlp encoding error: %v", err) - } - } - return -} - func (self *ethProtocolTester) run() { - err := runEthProtocol(ProtocolVersion, NetworkId, self.txPool, self.chainManager, self.blockPool, testPeer(), self.rw) + err := runEthProtocol(ProtocolVersion, NetworkId, self.txPool, self.chainManager, self.blockPool, testPeer(), self.pipe) self.quit <- err } @@ -224,41 +174,52 @@ func TestStatusMsgErrors(t *testing.T) { logInit() eth := newEth(t) td := common.Big1 - currentBlock := []byte{1} - genesis := []byte{2} - eth.chainManager.status = func() (*big.Int, []byte, []byte) { return td, currentBlock, genesis } - go eth.run() - statusMsg := p2p.NewMsg(4) - eth.In(statusMsg) - delay := 1 * time.Second - eth.checkError(ErrNoStatusMsg, delay) - var status statusMsgData - eth.checkMsg(0, StatusMsg, &status) // first outgoing msg should be StatusMsg - if status.TD.Cmp(td) != 0 || - status.ProtocolVersion != ProtocolVersion || - status.NetworkId != NetworkId || - status.TD.Cmp(td) != 0 || - bytes.Compare(status.CurrentBlock, currentBlock) != 0 || - bytes.Compare(status.GenesisBlock, genesis) != 0 { - t.Errorf("incorrect outgoing status") - } - - eth.reset() + currentBlock := common.Hash{1} + genesis := common.Hash{2} + eth.chainManager.status = func() (*big.Int, common.Hash, common.Hash) { return td, currentBlock, genesis } go eth.run() - statusMsg = p2p.NewMsg(0, uint32(48), uint32(0), td, currentBlock, genesis) - eth.In(statusMsg) - eth.checkError(ErrProtocolVersionMismatch, delay) - eth.reset() - go eth.run() - statusMsg = p2p.NewMsg(0, uint32(49), uint32(1), td, currentBlock, genesis) - eth.In(statusMsg) - eth.checkError(ErrNetworkIdMismatch, delay) + tests := []struct { + code uint64 + data interface{} + wantErrorCode int + }{ + { + code: TxMsg, data: []interface{}{}, + wantErrorCode: ErrNoStatusMsg, + }, + { + code: StatusMsg, data: statusMsgData{10, NetworkId, td, currentBlock, genesis}, + wantErrorCode: ErrProtocolVersionMismatch, + }, + { + code: StatusMsg, data: statusMsgData{ProtocolVersion, 999, td, currentBlock, genesis}, + wantErrorCode: ErrNetworkIdMismatch, + }, + { + code: StatusMsg, data: statusMsgData{ProtocolVersion, NetworkId, td, currentBlock, common.Hash{3}}, + wantErrorCode: ErrGenesisBlockMismatch, + }, + } + for _, test := range tests { + // first outgoing msg should be StatusMsg. + err := p2p.ExpectMsg(eth, StatusMsg, &statusMsgData{ + ProtocolVersion: ProtocolVersion, + NetworkId: NetworkId, + TD: td, + CurrentBlock: currentBlock, + GenesisBlock: genesis, + }) + if err != nil { + t.Fatalf("incorrect outgoing status: %v", err) + } - eth.reset() - go eth.run() - statusMsg = p2p.NewMsg(0, uint32(49), uint32(0), td, currentBlock, []byte{3}) - eth.In(statusMsg) - eth.checkError(ErrGenesisBlockMismatch, delay) + // the send call might hang until reset because + // the protocol might not read the payload. + go p2p.Send(eth, test.code, test.data) + eth.checkError(test.wantErrorCode, 1*time.Second) + eth.reset() + go eth.run() + } } diff --git a/miner/miner.go b/miner/miner.go index 7bf67a6ec..ccc19c754 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -4,6 +4,7 @@ import ( "math/big" "github.com/ethereum/ethash" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/pow" @@ -32,7 +33,7 @@ func (self *Miner) Mining() bool { return self.mining } -func (self *Miner) Start(coinbase []byte) { +func (self *Miner) Start(coinbase common.Address) { self.mining = true self.worker = newWorker(coinbase, self.eth) self.worker.register(NewCpuMiner(0, self.pow)) diff --git a/miner/worker.go b/miner/worker.go index 10fc6f508..63d1bfa0b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -7,9 +7,9 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/pow" @@ -39,7 +39,7 @@ func env(block *types.Block, eth core.Backend) *environment { coinbase: state.GetOrNewStateObject(block.Coinbase()), } for _, ancestor := range eth.ChainManager().GetAncestors(block, 7) { - env.ancestors.Add(string(ancestor.Hash())) + env.ancestors.Add(ancestor.Hash()) } return env @@ -71,14 +71,14 @@ type worker struct { eth core.Backend chain *core.ChainManager proc *core.BlockProcessor - coinbase []byte + coinbase common.Address current *environment mining bool } -func newWorker(coinbase []byte, eth core.Backend) *worker { +func newWorker(coinbase common.Address, eth core.Backend) *worker { return &worker{ eth: eth, mux: eth.EventMux(), @@ -152,13 +152,13 @@ func (self *worker) wait() { block := self.current.block if block.Number().Uint64() == work.Number && block.Nonce() == 0 { self.current.block.SetNonce(work.Nonce) - self.current.block.Header().MixDigest = work.MixDigest + self.current.block.Header().MixDigest = common.BytesToHash(work.MixDigest) jsonlogger.LogJson(&logger.EthMinerNewBlock{ - BlockHash: common.Bytes2Hex(block.Hash()), + BlockHash: block.Hash().Hex(), BlockNumber: block.Number(), - ChainHeadHash: common.Bytes2Hex(block.ParentHeaderHash), - BlockPrevHash: common.Bytes2Hex(block.ParentHeaderHash), + ChainHeadHash: block.ParentHeaderHash.Hex(), + BlockPrevHash: block.ParentHeaderHash.Hex(), }) if err := self.chain.InsertChain(types.Blocks{self.current.block}); err == nil { @@ -208,9 +208,10 @@ gasLimit: fallthrough case core.IsInvalidTxErr(err): // Remove invalid transactions - self.chain.TxState().RemoveNonce(tx.From(), tx.Nonce()) + from, _ := tx.From() + self.chain.TxState().RemoveNonce(from, tx.Nonce()) remove = append(remove, tx) - minerlogger.Infof("TX (%x) failed. Transaction will be removed\n", tx.Hash()[:4]) + minerlogger.Infof("TX (%x) failed. Transaction will be removed\n", tx.Hash().Bytes()[:4]) case state.IsGasLimitErr(err): minerlogger.Infof("Gas limit reached for block. %d TXs included in this block\n", i) // Break on gas limit @@ -232,13 +233,13 @@ var ( ) func (self *worker) commitUncle(uncle *types.Header) error { - if self.current.uncles.Has(string(uncle.Hash())) { + if self.current.uncles.Has(uncle.Hash()) { // Error not unique return core.UncleError("Uncle not unique") } - self.current.uncles.Add(string(uncle.Hash())) + self.current.uncles.Add(uncle.Hash()) - if !self.current.ancestors.Has(string(uncle.ParentHash)) { + if !self.current.ancestors.Has(uncle.ParentHash) { return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4])) } diff --git a/p2p/handshake.go b/p2p/handshake.go index 7fc497517..031064407 100644 --- a/p2p/handshake.go +++ b/p2p/handshake.go @@ -92,7 +92,7 @@ func setupInboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake) ( return nil, errors.New("node ID in protocol handshake does not match encryption handshake") } // TODO: validate that handshake node ID matches - if err := writeProtocolHandshake(rw, our); err != nil { + if err := Send(rw, handshakeMsg, our); err != nil { return nil, fmt.Errorf("protocol write error: %v", err) } return &conn{rw, rhs}, nil @@ -106,7 +106,7 @@ func setupOutboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, // Run the protocol handshake using authenticated messages. rw := newRlpxFrameRW(fd, secrets) - if err := writeProtocolHandshake(rw, our); err != nil { + if err := Send(rw, handshakeMsg, our); err != nil { return nil, fmt.Errorf("protocol write error: %v", err) } rhs, err := readProtocolHandshake(rw, our) @@ -398,10 +398,6 @@ func xor(one, other []byte) (xor []byte) { return xor } -func writeProtocolHandshake(w MsgWriter, our *protoHandshake) error { - return EncodeMsg(w, handshakeMsg, our.Version, our.Name, our.Caps, our.ListenPort, our.ID[:]) -} - func readProtocolHandshake(r MsgReader, our *protoHandshake) (*protoHandshake, error) { // read and handle remote handshake msg, err := r.ReadMsg() diff --git a/p2p/message.go b/p2p/message.go index 14e4404c9..ef3630a90 100644 --- a/p2p/message.go +++ b/p2p/message.go @@ -11,7 +11,6 @@ import ( "sync/atomic" "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rlp" ) @@ -28,13 +27,7 @@ type Msg struct { Payload io.Reader } -// NewMsg creates an RLP-encoded message with the given code. -func NewMsg(code uint64, params ...interface{}) Msg { - p := bytes.NewReader(common.Encode(params)) - return Msg{Code: code, Size: uint32(p.Len()), Payload: p} -} - -// Decode parse the RLP content of a message into +// Decode parses the RLP content of a message into // the given value, which must be a pointer. // // For the decoding rules, please see package rlp. @@ -76,13 +69,30 @@ type MsgReadWriter interface { MsgWriter } -// EncodeMsg writes an RLP-encoded message with the given code and -// data elements. -func EncodeMsg(w MsgWriter, code uint64, data ...interface{}) error { - return w.WriteMsg(NewMsg(code, data...)) +// Send writes an RLP-encoded message with the given code. +// data should encode as an RLP list. +func Send(w MsgWriter, msgcode uint64, data interface{}) error { + size, r, err := rlp.EncodeToReader(data) + if err != nil { + return err + } + return w.WriteMsg(Msg{Code: msgcode, Size: uint32(size), Payload: r}) +} + +// SendItems writes an RLP with the given code and data elements. +// For a call such as: +// +// SendItems(w, code, e1, e2, e3) +// +// the message payload will be an RLP list containing the items: +// +// [e1, e2, e3] +// +func SendItems(w MsgWriter, msgcode uint64, elems ...interface{}) error { + return Send(w, msgcode, elems) } -// netWrapper wrapsa MsgReadWriter with locks around +// netWrapper wraps a MsgReadWriter with locks around // ReadMsg/WriteMsg and applies read/write deadlines. type netWrapper struct { rmu, wmu sync.Mutex @@ -175,7 +185,10 @@ func (p *MsgPipeRW) WriteMsg(msg Msg) error { case p.w <- msg: if msg.Size > 0 { // wait for payload read or discard - <-consumed + select { + case <-consumed: + case <-p.closing: + } } return nil case <-p.closing: @@ -197,8 +210,8 @@ func (p *MsgPipeRW) ReadMsg() (Msg, error) { } // Close unblocks any pending ReadMsg and WriteMsg calls on both ends -// of the pipe. They will return ErrPipeClosed. Note that Close does -// not interrupt any reads from a message payload. +// of the pipe. They will return ErrPipeClosed. Close also +// interrupts any reads from a message payload. func (p *MsgPipeRW) Close() error { if atomic.AddInt32(p.closed, 1) != 1 { // someone else is already closing @@ -208,3 +221,35 @@ func (p *MsgPipeRW) Close() error { close(p.closing) return nil } + +// ExpectMsg reads a message from r and verifies that its +// code and encoded RLP content match the provided values. +// If content is nil, the payload is discarded and not verified. +func ExpectMsg(r MsgReader, code uint64, content interface{}) error { + msg, err := r.ReadMsg() + if err != nil { + return err + } + if msg.Code != code { + return fmt.Errorf("message code mismatch: got %d, expected %d", msg.Code, code) + } + if content == nil { + return msg.Discard() + } else { + contentEnc, err := rlp.EncodeToBytes(content) + if err != nil { + panic("content encode error: " + err.Error()) + } + if int(msg.Size) != len(contentEnc) { + return fmt.Errorf("message size mismatch: got %d, want %d", msg.Size, len(contentEnc)) + } + actualContent, err := ioutil.ReadAll(msg.Payload) + if err != nil { + return err + } + if !bytes.Equal(actualContent, contentEnc) { + return fmt.Errorf("message payload mismatch:\ngot: %x\nwant: %x", actualContent, contentEnc) + } + } + return nil +} diff --git a/p2p/message_test.go b/p2p/message_test.go index 31ed61d87..9a93dd347 100644 --- a/p2p/message_test.go +++ b/p2p/message_test.go @@ -5,33 +5,17 @@ import ( "encoding/hex" "fmt" "io" - "io/ioutil" "runtime" "strings" "testing" "time" ) -func TestNewMsg(t *testing.T) { - msg := NewMsg(3, 1, "000") - if msg.Code != 3 { - t.Errorf("incorrect code %d, want %d", msg.Code) - } - expect := unhex("c50183303030") - if msg.Size != uint32(len(expect)) { - t.Errorf("incorrect size %d, want %d", msg.Size, len(expect)) - } - pl, _ := ioutil.ReadAll(msg.Payload) - if !bytes.Equal(pl, expect) { - t.Errorf("incorrect payload content, got %x, want %x", pl, expect) - } -} - func ExampleMsgPipe() { rw1, rw2 := MsgPipe() go func() { - EncodeMsg(rw1, 8, []byte{0, 0}) - EncodeMsg(rw1, 5, []byte{1, 1}) + Send(rw1, 8, [][]byte{{0, 0}}) + Send(rw1, 5, [][]byte{{1, 1}}) rw1.Close() }() @@ -40,7 +24,7 @@ func ExampleMsgPipe() { if err != nil { break } - var data [1][]byte + var data [][]byte msg.Decode(&data) fmt.Printf("msg: %d, %x\n", msg.Code, data[0]) } @@ -55,7 +39,7 @@ loop: rw1, rw2 := MsgPipe() done := make(chan struct{}) go func() { - if err := EncodeMsg(rw1, 1); err == nil { + if err := SendItems(rw1, 1); err == nil { t.Error("EncodeMsg returned nil error") } else if err != ErrPipeClosed { t.Error("EncodeMsg returned wrong error: got %v, want %v", err, ErrPipeClosed) diff --git a/p2p/peer.go b/p2p/peer.go index c2c83abfc..6b97ea58d 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -132,7 +132,7 @@ loop: select { case <-ping.C: go func() { - if err := EncodeMsg(p.rw, pingMsg, nil); err != nil { + if err := SendItems(p.rw, pingMsg); err != nil { p.protoErr <- err return } @@ -161,7 +161,7 @@ loop: func (p *Peer) politeDisconnect(reason DiscReason) { done := make(chan struct{}) go func() { - EncodeMsg(p.rw, discMsg, uint(reason)) + SendItems(p.rw, discMsg, uint(reason)) // Wait for the other side to close the connection. // Discard any data that they send until then. io.Copy(ioutil.Discard, p.conn) @@ -192,12 +192,13 @@ func (p *Peer) handle(msg Msg) error { switch { case msg.Code == pingMsg: msg.Discard() - go EncodeMsg(p.rw, pongMsg) + go SendItems(p.rw, pongMsg) case msg.Code == discMsg: var reason [1]DiscReason // no need to discard or for error checking, we'll close the // connection after this. rlp.Decode(msg.Payload, &reason) + p.Debugf("Disconnect requested: %v\n", reason[0]) p.Disconnect(DiscRequested) return discRequestedError(reason[0]) case msg.Code < baseProtocolLength: diff --git a/p2p/peer_test.go b/p2p/peer_test.go index cc9f1f0cd..3c4c71c0c 100644 --- a/p2p/peer_test.go +++ b/p2p/peer_test.go @@ -4,13 +4,10 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "net" "reflect" "testing" "time" - - "github.com/ethereum/go-ethereum/rlp" ) var discard = Protocol{ @@ -55,13 +52,13 @@ func TestPeerProtoReadMsg(t *testing.T) { Name: "a", Length: 5, Run: func(peer *Peer, rw MsgReadWriter) error { - if err := expectMsg(rw, 2, []uint{1}); err != nil { + if err := ExpectMsg(rw, 2, []uint{1}); err != nil { t.Error(err) } - if err := expectMsg(rw, 3, []uint{2}); err != nil { + if err := ExpectMsg(rw, 3, []uint{2}); err != nil { t.Error(err) } - if err := expectMsg(rw, 4, []uint{3}); err != nil { + if err := ExpectMsg(rw, 4, []uint{3}); err != nil { t.Error(err) } close(done) @@ -72,9 +69,9 @@ func TestPeerProtoReadMsg(t *testing.T) { closer, rw, _, errc := testPeer([]Protocol{proto}) defer closer.Close() - EncodeMsg(rw, baseProtocolLength+2, 1) - EncodeMsg(rw, baseProtocolLength+3, 2) - EncodeMsg(rw, baseProtocolLength+4, 3) + Send(rw, baseProtocolLength+2, []uint{1}) + Send(rw, baseProtocolLength+3, []uint{2}) + Send(rw, baseProtocolLength+4, []uint{3}) select { case <-done: @@ -92,10 +89,10 @@ func TestPeerProtoEncodeMsg(t *testing.T) { Name: "a", Length: 2, Run: func(peer *Peer, rw MsgReadWriter) error { - if err := EncodeMsg(rw, 2); err == nil { + if err := SendItems(rw, 2); err == nil { t.Error("expected error for out-of-range msg code, got nil") } - if err := EncodeMsg(rw, 1, "foo", "bar"); err != nil { + if err := SendItems(rw, 1, "foo", "bar"); err != nil { t.Errorf("write error: %v", err) } return nil @@ -104,7 +101,7 @@ func TestPeerProtoEncodeMsg(t *testing.T) { closer, rw, _, _ := testPeer([]Protocol{proto}) defer closer.Close() - if err := expectMsg(rw, 17, []string{"foo", "bar"}); err != nil { + if err := ExpectMsg(rw, 17, []string{"foo", "bar"}); err != nil { t.Error(err) } } @@ -115,11 +112,15 @@ func TestPeerWriteForBroadcast(t *testing.T) { closer, rw, peer, peerErr := testPeer([]Protocol{discard}) defer closer.Close() + emptymsg := func(code uint64) Msg { + return Msg{Code: code, Size: 0, Payload: bytes.NewReader(nil)} + } + // test write errors - if err := peer.writeProtoMsg("b", NewMsg(3)); err == nil { + if err := peer.writeProtoMsg("b", emptymsg(3)); err == nil { t.Errorf("expected error for unknown protocol, got nil") } - if err := peer.writeProtoMsg("discard", NewMsg(8)); err == nil { + if err := peer.writeProtoMsg("discard", emptymsg(8)); err == nil { t.Errorf("expected error for out-of-range msg code, got nil") } else if perr, ok := err.(*peerError); !ok || perr.Code != errInvalidMsgCode { t.Errorf("wrong error for out-of-range msg code, got %#v", err) @@ -128,14 +129,14 @@ func TestPeerWriteForBroadcast(t *testing.T) { // setup for reading the message on the other end read := make(chan struct{}) go func() { - if err := expectMsg(rw, 16, nil); err != nil { + if err := ExpectMsg(rw, 16, nil); err != nil { t.Error(err) } close(read) }() // test successful write - if err := peer.writeProtoMsg("discard", NewMsg(0)); err != nil { + if err := peer.writeProtoMsg("discard", emptymsg(0)); err != nil { t.Errorf("expect no error for known protocol: %v", err) } select { @@ -150,10 +151,10 @@ func TestPeerPing(t *testing.T) { closer, rw, _, _ := testPeer(nil) defer closer.Close() - if err := EncodeMsg(rw, pingMsg); err != nil { + if err := SendItems(rw, pingMsg); err != nil { t.Fatal(err) } - if err := expectMsg(rw, pongMsg, nil); err != nil { + if err := ExpectMsg(rw, pongMsg, nil); err != nil { t.Error(err) } } @@ -163,10 +164,10 @@ func TestPeerDisconnect(t *testing.T) { closer, rw, _, disc := testPeer(nil) defer closer.Close() - if err := EncodeMsg(rw, discMsg, DiscQuitting); err != nil { + if err := SendItems(rw, discMsg, DiscQuitting); err != nil { t.Fatal(err) } - if err := expectMsg(rw, discMsg, []interface{}{DiscRequested}); err != nil { + if err := ExpectMsg(rw, discMsg, []interface{}{DiscRequested}); err != nil { t.Error(err) } closer.Close() // make test end faster @@ -192,35 +193,3 @@ func TestNewPeer(t *testing.T) { p.Disconnect(DiscAlreadyConnected) // Should not hang } - -// expectMsg reads a message from r and verifies that its -// code and encoded RLP content match the provided values. -// If content is nil, the payload is discarded and not verified. -func expectMsg(r MsgReader, code uint64, content interface{}) error { - msg, err := r.ReadMsg() - if err != nil { - return err - } - if msg.Code != code { - return fmt.Errorf("message code mismatch: got %d, expected %d", msg.Code, code) - } - if content == nil { - return msg.Discard() - } else { - contentEnc, err := rlp.EncodeToBytes(content) - if err != nil { - panic("content encode error: " + err.Error()) - } - if int(msg.Size) != len(contentEnc) { - return fmt.Errorf("message size mismatch: got %d, want %d", msg.Size, len(contentEnc)) - } - actualContent, err := ioutil.ReadAll(msg.Payload) - if err != nil { - return err - } - if !bytes.Equal(actualContent, contentEnc) { - return fmt.Errorf("message payload mismatch:\ngot: %x\nwant: %x", actualContent, contentEnc) - } - } - return nil -} diff --git a/p2p/rlpx_test.go b/p2p/rlpx_test.go index 49354c7ed..d98f1c2cd 100644 --- a/p2p/rlpx_test.go +++ b/p2p/rlpx_test.go @@ -30,7 +30,7 @@ ba628a4ba590cb43f7848f41c4382885 `) // Check WriteMsg. This puts a message into the buffer. - if err := EncodeMsg(rw, 8, 1, 2, 3, 4); err != nil { + if err := Send(rw, 8, []uint{1, 2, 3, 4}); err != nil { t.Fatalf("WriteMsg error: %v", err) } written := buf.Bytes() @@ -102,7 +102,7 @@ func TestRlpxFrameRW(t *testing.T) { for i := 0; i < 10; i++ { // write message into conn buffer wmsg := []interface{}{"foo", "bar", strings.Repeat("test", i)} - err := EncodeMsg(rw1, uint64(i), wmsg...) + err := Send(rw1, uint64(i), wmsg) if err != nil { t.Fatalf("WriteMsg error (i=%d): %v", i, err) } diff --git a/p2p/server.go b/p2p/server.go index 9c148ba39..813b0676f 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -9,10 +9,10 @@ import ( "sync" "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/nat" + "github.com/ethereum/go-ethereum/rlp" ) const ( @@ -129,10 +129,14 @@ func (srv *Server) SuggestPeer(n *discover.Node) { // Broadcast sends an RLP-encoded message to all connected peers. // This method is deprecated and will be removed later. -func (srv *Server) Broadcast(protocol string, code uint64, data ...interface{}) { +func (srv *Server) Broadcast(protocol string, code uint64, data interface{}) error { var payload []byte if data != nil { - payload = common.Encode(data) + var err error + payload, err = rlp.EncodeToBytes(data) + if err != nil { + return err + } } srv.lock.RLock() defer srv.lock.RUnlock() @@ -146,6 +150,7 @@ func (srv *Server) Broadcast(protocol string, code uint64, data ...interface{}) peer.writeProtoMsg(protocol, msg) } } + return nil } // Start starts running the server. diff --git a/p2p/server_test.go b/p2p/server_test.go index 30447050c..14e7c7de2 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -149,7 +149,7 @@ func TestServerBroadcast(t *testing.T) { connected.Wait() // broadcast one message - srv.Broadcast("discard", 0, "foo") + srv.Broadcast("discard", 0, []string{"foo"}) golden := unhex("66e94d166f0a2c3b884cfa59ca34") // check that the message has been written everywhere diff --git a/pow/block.go b/pow/block.go index 136e4bf8d..9ae25bd4d 100644 --- a/pow/block.go +++ b/pow/block.go @@ -3,14 +3,15 @@ package pow import ( "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) type Block interface { Difficulty() *big.Int - HashNoNonce() []byte + HashNoNonce() common.Hash Nonce() uint64 - MixDigest() []byte + MixDigest() common.Hash NumberU64() uint64 } diff --git a/pow/ezp/pow.go b/pow/ezp/pow.go index 7eba95784..bd2927fe8 100644 --- a/pow/ezp/pow.go +++ b/pow/ezp/pow.go @@ -6,8 +6,8 @@ import ( "math/rand" "time" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/pow" ) @@ -83,17 +83,14 @@ func (pow *EasyPow) Verify(block pow.Block) bool { return Verify(block) } -func verify(hash []byte, diff *big.Int, nonce uint64) bool { +func verify(hash common.Hash, diff *big.Int, nonce uint64) bool { sha := sha3.NewKeccak256() - n := make([]byte, 8) binary.PutUvarint(n, nonce) - d := append(hash, n...) - sha.Write(d) - + sha.Write(n) + sha.Write(hash[:]) verification := new(big.Int).Div(common.BigPow(2, 256), diff) res := common.BigD(sha.Sum(nil)) - return res.Cmp(verification) <= 0 } diff --git a/rlp/decode.go b/rlp/decode.go index 55f7187a3..6d7e670c2 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -2,6 +2,7 @@ package rlp import ( "bufio" + "bytes" "encoding/binary" "errors" "fmt" @@ -73,6 +74,12 @@ func Decode(r io.Reader, val interface{}) error { return NewStream(r).Decode(val) } +// DecodeBytes parses RLP data from b into val. +// Please see the documentation of Decode for the decoding rules. +func DecodeBytes(b []byte, val interface{}) error { + return NewStream(bytes.NewReader(b)).Decode(val) +} + type decodeError struct { msg string typ reflect.Type diff --git a/rlp/encode.go b/rlp/encode.go index 9d11d66bf..7ac74d8fb 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -203,8 +203,13 @@ func (w *encbuf) encodeStringHeader(size int) { } func (w *encbuf) encodeString(b []byte) { - w.encodeStringHeader(len(b)) - w.str = append(w.str, b...) + if len(b) == 1 && b[0] <= 0x7F { + // fits single byte, no string header + w.str = append(w.str, b[0]) + } else { + w.encodeStringHeader(len(b)) + w.str = append(w.str, b...) + } } func (w *encbuf) list() *listhead { @@ -386,7 +391,12 @@ func writeUint(val reflect.Value, w *encbuf) error { } func writeBigIntPtr(val reflect.Value, w *encbuf) error { - return writeBigInt(val.Interface().(*big.Int), w) + ptr := val.Interface().(*big.Int) + if ptr == nil { + w.str = append(w.str, 0x80) + return nil + } + return writeBigInt(ptr, w) } func writeBigIntNoPtr(val reflect.Value, w *encbuf) error { @@ -399,9 +409,6 @@ func writeBigInt(i *big.Int, w *encbuf) error { return fmt.Errorf("rlp: cannot encode negative *big.Int") } else if cmp == 0 { w.str = append(w.str, 0x80) - } else if bits := i.BitLen(); bits < 8 { - // fits single byte - w.str = append(w.str, byte(i.Uint64())) } else { w.encodeString(i.Bytes()) } @@ -429,8 +436,13 @@ func writeByteArray(val reflect.Value, w *encbuf) error { func writeString(val reflect.Value, w *encbuf) error { s := val.String() - w.encodeStringHeader(len(s)) - w.str = append(w.str, s...) + if len(s) == 1 && s[0] <= 0x7f { + // fits single byte, no string header + w.str = append(w.str, s[0]) + } else { + w.encodeStringHeader(len(s)) + w.str = append(w.str, s...) + } return nil } diff --git a/rlp/encode_test.go b/rlp/encode_test.go index c283fbd57..611514bda 100644 --- a/rlp/encode_test.go +++ b/rlp/encode_test.go @@ -103,12 +103,18 @@ var encTests = []encTest{ // byte slices, strings {val: []byte{}, output: "80"}, + {val: []byte{0x7E}, output: "7E"}, + {val: []byte{0x7F}, output: "7F"}, + {val: []byte{0x80}, output: "8180"}, {val: []byte{1, 2, 3}, output: "83010203"}, {val: []namedByteType{1, 2, 3}, output: "83010203"}, {val: [...]namedByteType{1, 2, 3}, output: "83010203"}, {val: "", output: "80"}, + {val: "\x7E", output: "7E"}, + {val: "\x7F", output: "7F"}, + {val: "\x80", output: "8180"}, {val: "dog", output: "83646F67"}, { val: "Lorem ipsum dolor sit amet, consectetur adipisicing eli", @@ -196,6 +202,7 @@ var encTests = []encTest{ {val: (*uint)(nil), output: "80"}, {val: (*string)(nil), output: "80"}, {val: (*[]byte)(nil), output: "80"}, + {val: (*big.Int)(nil), output: "80"}, {val: (*[]string)(nil), output: "C0"}, {val: (*[]interface{})(nil), output: "C0"}, {val: (*[]struct{ uint })(nil), output: "C0"}, diff --git a/rpc/api.go b/rpc/api.go index afc0bd455..39a6b8f5b 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -676,7 +676,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return NewValidationError("Index", "does not exist") } - uncle, err := p.GetBlockByHash(common.ToHex(v.Uncles[args.Index]), false) + uncle, err := p.GetBlockByHash(v.Uncles[args.Index].Hex(), false) if err != nil { return err } @@ -695,7 +695,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return NewValidationError("Index", "does not exist") } - uncle, err := p.GetBlockByHash(common.ToHex(v.Uncles[args.Index]), false) + uncle, err := p.GetBlockByHash(v.Uncles[args.Index].Hex(), false) if err != nil { return err } @@ -840,12 +840,12 @@ func toFilterOptions(options *FilterOptions) core.FilterOptions { // Convert optional address slice/string to byte slice if str, ok := options.Address.(string); ok { - opts.Address = [][]byte{common.FromHex(str)} + opts.Address = []common.Address{common.HexToAddress(str)} } else if slice, ok := options.Address.([]interface{}); ok { - bslice := make([][]byte, len(slice)) + bslice := make([]common.Address, len(slice)) for i, addr := range slice { if saddr, ok := addr.(string); ok { - bslice[i] = common.FromHex(saddr) + bslice[i] = common.HexToAddress(saddr) } } opts.Address = bslice @@ -854,16 +854,15 @@ func toFilterOptions(options *FilterOptions) core.FilterOptions { opts.Earliest = options.Earliest opts.Latest = options.Latest - topics := make([][][]byte, len(options.Topics)) + topics := make([][]common.Hash, len(options.Topics)) for i, topicDat := range options.Topics { if slice, ok := topicDat.([]interface{}); ok { - topics[i] = make([][]byte, len(slice)) + topics[i] = make([]common.Hash, len(slice)) for j, topic := range slice { - topics[i][j] = common.FromHex(topic.(string)) + topics[i][j] = common.HexToHash(topic.(string)) } } else if str, ok := topicDat.(string); ok { - topics[i] = make([][]byte, 1) - topics[i][0] = common.FromHex(str) + topics[i] = []common.Hash{common.HexToHash(str)} } } opts.Topics = topics diff --git a/rpc/responses.go b/rpc/responses.go index eec483fb7..5e197b729 100644 --- a/rpc/responses.go +++ b/rpc/responses.go @@ -13,14 +13,14 @@ type BlockRes struct { fullTx bool BlockNumber int64 `json:"number"` - BlockHash []byte `json:"hash"` - ParentHash []byte `json:"parentHash"` - Nonce []byte `json:"nonce"` - Sha3Uncles []byte `json:"sha3Uncles"` - LogsBloom []byte `json:"logsBloom"` - TransactionRoot []byte `json:"transactionRoot"` - StateRoot []byte `json:"stateRoot"` - Miner []byte `json:"miner"` + BlockHash common.Hash `json:"hash"` + ParentHash common.Hash `json:"parentHash"` + Nonce [8]byte `json:"nonce"` + Sha3Uncles common.Hash `json:"sha3Uncles"` + LogsBloom types.Bloom `json:"logsBloom"` + TransactionRoot common.Hash `json:"transactionRoot"` + StateRoot common.Hash `json:"stateRoot"` + Miner common.Address `json:"miner"` Difficulty int64 `json:"difficulty"` TotalDifficulty int64 `json:"totalDifficulty"` Size int64 `json:"size"` @@ -30,7 +30,7 @@ type BlockRes struct { GasUsed int64 `json:"gasUsed"` UnixTimestamp int64 `json:"timestamp"` Transactions []*TransactionRes `json:"transactions"` - Uncles [][]byte `json:"uncles"` + Uncles []common.Hash `json:"uncles"` } func (b *BlockRes) MarshalJSON() ([]byte, error) { @@ -58,14 +58,14 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) { // convert strict types to hexified strings ext.BlockNumber = common.ToHex(big.NewInt(b.BlockNumber).Bytes()) - ext.BlockHash = common.ToHex(b.BlockHash) - ext.ParentHash = common.ToHex(b.ParentHash) - ext.Nonce = common.ToHex(b.Nonce) - ext.Sha3Uncles = common.ToHex(b.Sha3Uncles) - ext.LogsBloom = common.ToHex(b.LogsBloom) - ext.TransactionRoot = common.ToHex(b.TransactionRoot) - ext.StateRoot = common.ToHex(b.StateRoot) - ext.Miner = common.ToHex(b.Miner) + ext.BlockHash = b.BlockHash.Hex() + ext.ParentHash = b.ParentHash.Hex() + ext.Nonce = common.ToHex(b.Nonce[:]) + ext.Sha3Uncles = b.Sha3Uncles.Hex() + ext.LogsBloom = common.ToHex(b.LogsBloom[:]) + ext.TransactionRoot = b.TransactionRoot.Hex() + ext.StateRoot = b.StateRoot.Hex() + ext.Miner = b.Miner.Hex() ext.Difficulty = common.ToHex(big.NewInt(b.Difficulty).Bytes()) ext.TotalDifficulty = common.ToHex(big.NewInt(b.TotalDifficulty).Bytes()) ext.Size = common.ToHex(big.NewInt(b.Size).Bytes()) @@ -81,12 +81,12 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) { } } else { for i, tx := range b.Transactions { - ext.Transactions[i] = common.ToHex(tx.Hash) + ext.Transactions[i] = tx.Hash.Hex() } } ext.Uncles = make([]string, len(b.Uncles)) for i, v := range b.Uncles { - ext.Uncles[i] = common.ToHex(v) + ext.Uncles[i] = v.Hex() } return json.Marshal(ext) @@ -125,7 +125,7 @@ func NewBlockRes(block *types.Block) *BlockRes { v.TxIndex = int64(i) res.Transactions[i] = v } - res.Uncles = make([][]byte, len(block.Uncles())) + res.Uncles = make([]common.Hash, len(block.Uncles())) for i, uncle := range block.Uncles() { res.Uncles[i] = uncle.Hash() } @@ -133,17 +133,17 @@ func NewBlockRes(block *types.Block) *BlockRes { } type TransactionRes struct { - Hash []byte `json:"hash"` - Nonce int64 `json:"nonce"` - BlockHash []byte `json:"blockHash,omitempty"` - BlockNumber int64 `json:"blockNumber,omitempty"` - TxIndex int64 `json:"transactionIndex,omitempty"` - From []byte `json:"from"` - To []byte `json:"to"` - Value int64 `json:"value"` - Gas int64 `json:"gas"` - GasPrice int64 `json:"gasPrice"` - Input []byte `json:"input"` + Hash common.Hash `json:"hash"` + Nonce int64 `json:"nonce"` + BlockHash common.Hash `json:"blockHash,omitempty"` + BlockNumber int64 `json:"blockNumber,omitempty"` + TxIndex int64 `json:"transactionIndex,omitempty"` + From common.Address `json:"from"` + To *common.Address `json:"to"` + Value int64 `json:"value"` + Gas int64 `json:"gas"` + GasPrice int64 `json:"gasPrice"` + Input []byte `json:"input"` } func (t *TransactionRes) MarshalJSON() ([]byte, error) { @@ -161,13 +161,17 @@ func (t *TransactionRes) MarshalJSON() ([]byte, error) { Input string `json:"input"` } - ext.Hash = common.ToHex(t.Hash) + ext.Hash = t.Hash.Hex() ext.Nonce = common.ToHex(big.NewInt(t.Nonce).Bytes()) - ext.BlockHash = common.ToHex(t.BlockHash) + ext.BlockHash = t.BlockHash.Hex() ext.BlockNumber = common.ToHex(big.NewInt(t.BlockNumber).Bytes()) ext.TxIndex = common.ToHex(big.NewInt(t.TxIndex).Bytes()) - ext.From = common.ToHex(t.From) - ext.To = common.ToHex(t.To) + ext.From = t.From.Hex() + if t.To == nil { + ext.To = "0x00" + } else { + ext.To = t.To.Hex() + } ext.Value = common.ToHex(big.NewInt(t.Value).Bytes()) ext.Gas = common.ToHex(big.NewInt(t.Gas).Bytes()) ext.GasPrice = common.ToHex(big.NewInt(t.GasPrice).Bytes()) @@ -180,7 +184,7 @@ func NewTransactionRes(tx *types.Transaction) *TransactionRes { var v = new(TransactionRes) v.Hash = tx.Hash() v.Nonce = int64(tx.Nonce()) - v.From = tx.From() + v.From, _ = tx.From() v.To = tx.To() v.Value = tx.Value().Int64() v.Gas = tx.Gas().Int64() diff --git a/rpc/util.go b/rpc/util.go index 0798ae1d2..724c8b503 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -40,11 +40,11 @@ func toLogs(logs state.Logs) (ls []Log) { for i, log := range logs { var l Log l.Topic = make([]string, len(log.Topics())) - l.Address = common.ToHex(log.Address()) + l.Address = log.Address().Hex() l.Data = common.ToHex(log.Data()) l.Number = log.Number() for j, topic := range log.Topics() { - l.Topic[j] = common.ToHex(topic) + l.Topic[j] = topic.Hex() } ls[i] = l } diff --git a/state/dump.go b/state/dump.go index 6db0d5074..712f8da1f 100644 --- a/state/dump.go +++ b/state/dump.go @@ -28,7 +28,7 @@ func (self *StateDB) RawDump() World { it := self.trie.Iterator() for it.Next() { - stateObject := NewStateObjectFromBytes(it.Key, it.Value, self.db) + stateObject := NewStateObjectFromBytes(common.BytesToAddress(it.Key), it.Value, self.db) account := Account{Balance: stateObject.balance.String(), Nonce: stateObject.nonce, Root: common.Bytes2Hex(stateObject.Root()), CodeHash: common.Bytes2Hex(stateObject.codeHash)} account.Storage = make(map[string]string) diff --git a/state/log.go b/state/log.go index a0859aaf2..f8aa4c08c 100644 --- a/state/log.go +++ b/state/log.go @@ -2,36 +2,36 @@ package state import ( "fmt" + "io" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" ) type Log interface { - common.RlpEncodable - - Address() []byte - Topics() [][]byte + Address() common.Address + Topics() []common.Hash Data() []byte Number() uint64 } type StateLog struct { - address []byte - topics [][]byte + address common.Address + topics []common.Hash data []byte number uint64 } -func NewLog(address []byte, topics [][]byte, data []byte, number uint64) *StateLog { +func NewLog(address common.Address, topics []common.Hash, data []byte, number uint64) *StateLog { return &StateLog{address, topics, data, number} } -func (self *StateLog) Address() []byte { +func (self *StateLog) Address() common.Address { return self.address } -func (self *StateLog) Topics() [][]byte { +func (self *StateLog) Topics() []common.Hash { return self.topics } @@ -43,7 +43,12 @@ func (self *StateLog) Number() uint64 { return self.number } +/* func NewLogFromValue(decoder *common.Value) *StateLog { + var extlog struct { + + } + log := &StateLog{ address: decoder.Get(0).Bytes(), data: decoder.Get(2).Bytes(), @@ -56,10 +61,17 @@ func NewLogFromValue(decoder *common.Value) *StateLog { return log } +*/ + +func (self *StateLog) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, []interface{}{self.address, self.topics, self.data}) +} +/* func (self *StateLog) RlpData() interface{} { return []interface{}{self.address, common.ByteSliceToInterface(self.topics), self.data} } +*/ func (self *StateLog) String() string { return fmt.Sprintf(`log: %x %x %x`, self.address, self.topics, self.data) @@ -67,6 +79,7 @@ func (self *StateLog) String() string { type Logs []Log +/* func (self Logs) RlpData() interface{} { data := make([]interface{}, len(self)) for i, log := range self { @@ -75,6 +88,7 @@ func (self Logs) RlpData() interface{} { return data } +*/ func (self Logs) String() (ret string) { for _, log := range self { diff --git a/state/managed_state.go b/state/managed_state.go index aff0206b2..0fcc1be67 100644 --- a/state/managed_state.go +++ b/state/managed_state.go @@ -1,6 +1,10 @@ package state -import "sync" +import ( + "sync" + + "github.com/ethereum/go-ethereum/common" +) type account struct { stateObject *StateObject @@ -29,7 +33,7 @@ func (ms *ManagedState) SetState(statedb *StateDB) { ms.StateDB = statedb } -func (ms *ManagedState) RemoveNonce(addr []byte, n uint64) { +func (ms *ManagedState) RemoveNonce(addr common.Address, n uint64) { if ms.hasAccount(addr) { ms.mu.Lock() defer ms.mu.Unlock() @@ -43,7 +47,7 @@ func (ms *ManagedState) RemoveNonce(addr []byte, n uint64) { } } -func (ms *ManagedState) NewNonce(addr []byte) uint64 { +func (ms *ManagedState) NewNonce(addr common.Address) uint64 { ms.mu.RLock() defer ms.mu.RUnlock() @@ -57,26 +61,27 @@ func (ms *ManagedState) NewNonce(addr []byte) uint64 { return uint64(len(account.nonces)) + account.nstart } -func (ms *ManagedState) hasAccount(addr []byte) bool { - _, ok := ms.accounts[string(addr)] +func (ms *ManagedState) hasAccount(addr common.Address) bool { + _, ok := ms.accounts[addr.Str()] return ok } -func (ms *ManagedState) getAccount(addr []byte) *account { - if account, ok := ms.accounts[string(addr)]; !ok { +func (ms *ManagedState) getAccount(addr common.Address) *account { + straddr := addr.Str() + if account, ok := ms.accounts[straddr]; !ok { so := ms.GetOrNewStateObject(addr) - ms.accounts[string(addr)] = newAccount(so) + ms.accounts[straddr] = newAccount(so) } else { // Always make sure the state account nonce isn't actually higher // than the tracked one. so := ms.StateDB.GetStateObject(addr) if so != nil && uint64(len(account.nonces))+account.nstart < so.nonce { - ms.accounts[string(addr)] = newAccount(so) + ms.accounts[straddr] = newAccount(so) } } - return ms.accounts[string(addr)] + return ms.accounts[straddr] } func newAccount(so *StateObject) *account { diff --git a/state/managed_state_test.go b/state/managed_state_test.go index 4aad1e1e3..b61f59e6d 100644 --- a/state/managed_state_test.go +++ b/state/managed_state_test.go @@ -6,15 +6,15 @@ import ( "github.com/ethereum/go-ethereum/common" ) -var addr = common.Address([]byte("test")) +var addr = common.BytesToAddress([]byte("test")) func create() (*ManagedState, *account) { ms := ManageState(&StateDB{stateObjects: make(map[string]*StateObject)}) so := &StateObject{address: addr, nonce: 100} - ms.StateDB.stateObjects[string(addr)] = so - ms.accounts[string(addr)] = newAccount(so) + ms.StateDB.stateObjects[addr.Str()] = so + ms.accounts[addr.Str()] = newAccount(so) - return ms, ms.accounts[string(addr)] + return ms, ms.accounts[addr.Str()] } func TestNewNonce(t *testing.T) { @@ -73,7 +73,7 @@ func TestRemoteNonceChange(t *testing.T) { account.nonces = append(account.nonces, nn...) nonce := ms.NewNonce(addr) - ms.StateDB.stateObjects[string(addr)].nonce = 200 + ms.StateDB.stateObjects[addr.Str()].nonce = 200 nonce = ms.NewNonce(addr) if nonce != 200 { t.Error("expected nonce after remote update to be", 201, "got", nonce) @@ -81,7 +81,7 @@ func TestRemoteNonceChange(t *testing.T) { ms.NewNonce(addr) ms.NewNonce(addr) ms.NewNonce(addr) - ms.StateDB.stateObjects[string(addr)].nonce = 200 + ms.StateDB.stateObjects[addr.Str()].nonce = 200 nonce = ms.NewNonce(addr) if nonce != 204 { t.Error("expected nonce after remote update to be", 201, "got", nonce) diff --git a/state/state_object.go b/state/state_object.go index cdb9abf79..a7c20722c 100644 --- a/state/state_object.go +++ b/state/state_object.go @@ -44,7 +44,7 @@ type StateObject struct { State *StateDB // Address belonging to this account - address []byte + address common.Address // The balance of the account balance *big.Int // The nonce of the account @@ -77,12 +77,12 @@ func (self *StateObject) Reset() { self.State.Reset() } -func NewStateObject(addr []byte, db common.Database) *StateObject { +func NewStateObject(address common.Address, db common.Database) *StateObject { // This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter. - address := common.Address(addr) + //address := common.ToAddress(addr) object := &StateObject{db: db, address: address, balance: new(big.Int), gasPool: new(big.Int), dirty: true} - object.State = New(nil, db) //New(trie.New(common.Config.Db, "")) + object.State = New(common.Hash{}, db) //New(trie.New(common.Config.Db, "")) object.storage = make(Storage) object.gasPool = new(big.Int) object.prepaid = new(big.Int) @@ -90,12 +90,12 @@ func NewStateObject(addr []byte, db common.Database) *StateObject { return object } -func NewStateObjectFromBytes(address, data []byte, db common.Database) *StateObject { +func NewStateObjectFromBytes(address common.Address, data []byte, db common.Database) *StateObject { // TODO clean me up var extobject struct { Nonce uint64 Balance *big.Int - Root []byte + Root common.Hash CodeHash []byte } err := rlp.Decode(bytes.NewReader(data), &extobject) @@ -124,8 +124,8 @@ func (self *StateObject) MarkForDeletion() { statelogger.Debugf("%x: #%d %v X\n", self.Address(), self.nonce, self.balance) } -func (c *StateObject) getAddr(addr []byte) *common.Value { - return common.NewValueFromBytes([]byte(c.State.trie.Get(addr))) +func (c *StateObject) getAddr(addr common.Hash) *common.Value { + return common.NewValueFromBytes([]byte(c.State.trie.Get(addr[:]))) } func (c *StateObject) setAddr(addr []byte, value interface{}) { @@ -133,34 +133,32 @@ func (c *StateObject) setAddr(addr []byte, value interface{}) { } func (self *StateObject) GetStorage(key *big.Int) *common.Value { - return self.GetState(key.Bytes()) + return self.GetState(common.BytesToHash(key.Bytes())) } func (self *StateObject) SetStorage(key *big.Int, value *common.Value) { - self.SetState(key.Bytes(), value) + self.SetState(common.BytesToHash(key.Bytes()), value) } func (self *StateObject) Storage() Storage { return self.storage } -func (self *StateObject) GetState(k []byte) *common.Value { - key := common.LeftPadBytes(k, 32) - - value := self.storage[string(key)] +func (self *StateObject) GetState(key common.Hash) *common.Value { + strkey := key.Str() + value := self.storage[strkey] if value == nil { value = self.getAddr(key) if !value.IsNil() { - self.storage[string(key)] = value + self.storage[strkey] = value } } return value } -func (self *StateObject) SetState(k []byte, value *common.Value) { - key := common.LeftPadBytes(k, 32) - self.storage[string(key)] = value.Copy() +func (self *StateObject) SetState(k common.Hash, value *common.Value) { + self.storage[k.Str()] = value.Copy() self.dirty = true } @@ -284,7 +282,7 @@ func (c *StateObject) N() *big.Int { } // Returns the address of the contract/account -func (c *StateObject) Address() []byte { +func (c *StateObject) Address() common.Address { return c.address } @@ -341,7 +339,7 @@ func (c *StateObject) RlpDecode(data []byte) { decoder := common.NewValueFromBytes(data) c.nonce = decoder.Get(0).Uint() c.balance = decoder.Get(1).BigInt() - c.State = New(decoder.Get(2).Bytes(), c.db) //New(trie.New(common.Config.Db, decoder.Get(2).Interface())) + c.State = New(common.BytesToHash(decoder.Get(2).Bytes()), c.db) //New(trie.New(common.Config.Db, decoder.Get(2).Interface())) c.storage = make(map[string]*common.Value) c.gasPool = new(big.Int) diff --git a/state/state_test.go b/state/state_test.go index 3a1ea225d..b6e22f891 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -17,15 +17,16 @@ type StateSuite struct { var _ = checker.Suite(&StateSuite{}) -// var ZeroHash256 = make([]byte, 32) +var toAddr = common.BytesToAddress func (s *StateSuite) TestDump(c *checker.C) { + return // generate a few entries - obj1 := s.state.GetOrNewStateObject([]byte{0x01}) + obj1 := s.state.GetOrNewStateObject(toAddr([]byte{0x01})) obj1.AddBalance(big.NewInt(22)) - obj2 := s.state.GetOrNewStateObject([]byte{0x01, 0x02}) + obj2 := s.state.GetOrNewStateObject(toAddr([]byte{0x01, 0x02})) obj2.SetCode([]byte{3, 3, 3, 3, 3, 3, 3}) - obj3 := s.state.GetOrNewStateObject([]byte{0x02}) + obj3 := s.state.GetOrNewStateObject(toAddr([]byte{0x02})) obj3.SetBalance(big.NewInt(44)) // write some of them to the trie @@ -80,7 +81,7 @@ func TestNull(t *testing.T) { } func (s *StateSuite) TestSnapshot(c *checker.C) { - stateobjaddr := []byte("aa") + stateobjaddr := toAddr([]byte("aa")) storageaddr := common.Big("0") data1 := common.NewValue(42) data2 := common.NewValue(43) diff --git a/state/statedb.go b/state/statedb.go index d01b6056d..6fcd39dbc 100644 --- a/state/statedb.go +++ b/state/statedb.go @@ -28,8 +28,8 @@ type StateDB struct { } // Create a new state from a given trie -func New(root []byte, db common.Database) *StateDB { - trie := trie.NewSecure(common.CopyBytes(root), db) +func New(root common.Hash, db common.Database) *StateDB { + trie := trie.NewSecure(root[:], db) return &StateDB{db: db, trie: trie, stateObjects: make(map[string]*StateObject), refund: make(map[string]*big.Int)} } @@ -49,15 +49,16 @@ func (self *StateDB) Logs() Logs { return self.logs } -func (self *StateDB) Refund(addr []byte, gas *big.Int) { - if self.refund[string(addr)] == nil { - self.refund[string(addr)] = new(big.Int) +func (self *StateDB) Refund(address common.Address, gas *big.Int) { + addr := address.Str() + if self.refund[addr] == nil { + self.refund[addr] = new(big.Int) } - self.refund[string(addr)].Add(self.refund[string(addr)], gas) + self.refund[addr].Add(self.refund[addr], gas) } // Retrieve the balance from the given address or 0 if object not found -func (self *StateDB) GetBalance(addr []byte) *big.Int { +func (self *StateDB) GetBalance(addr common.Address) *big.Int { stateObject := self.GetStateObject(addr) if stateObject != nil { return stateObject.balance @@ -66,14 +67,14 @@ func (self *StateDB) GetBalance(addr []byte) *big.Int { return common.Big0 } -func (self *StateDB) AddBalance(addr []byte, amount *big.Int) { +func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.AddBalance(amount) } } -func (self *StateDB) GetNonce(addr []byte) uint64 { +func (self *StateDB) GetNonce(addr common.Address) uint64 { stateObject := self.GetStateObject(addr) if stateObject != nil { return stateObject.nonce @@ -82,7 +83,7 @@ func (self *StateDB) GetNonce(addr []byte) uint64 { return 0 } -func (self *StateDB) GetCode(addr []byte) []byte { +func (self *StateDB) GetCode(addr common.Address) []byte { stateObject := self.GetStateObject(addr) if stateObject != nil { return stateObject.code @@ -91,7 +92,7 @@ func (self *StateDB) GetCode(addr []byte) []byte { return nil } -func (self *StateDB) GetState(a, b []byte) []byte { +func (self *StateDB) GetState(a common.Address, b common.Hash) []byte { stateObject := self.GetStateObject(a) if stateObject != nil { return stateObject.GetState(b).Bytes() @@ -100,28 +101,28 @@ func (self *StateDB) GetState(a, b []byte) []byte { return nil } -func (self *StateDB) SetNonce(addr []byte, nonce uint64) { +func (self *StateDB) SetNonce(addr common.Address, nonce uint64) { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.SetNonce(nonce) } } -func (self *StateDB) SetCode(addr, code []byte) { +func (self *StateDB) SetCode(addr common.Address, code []byte) { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.SetCode(code) } } -func (self *StateDB) SetState(addr, key []byte, value interface{}) { +func (self *StateDB) SetState(addr common.Address, key common.Hash, value interface{}) { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.SetState(key, common.NewValue(value)) } } -func (self *StateDB) Delete(addr []byte) bool { +func (self *StateDB) Delete(addr common.Address) bool { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.MarkForDeletion() @@ -133,7 +134,7 @@ func (self *StateDB) Delete(addr []byte) bool { return false } -func (self *StateDB) IsDeleted(addr []byte) bool { +func (self *StateDB) IsDeleted(addr common.Address) bool { stateObject := self.GetStateObject(addr) if stateObject != nil { return stateObject.remove @@ -147,32 +148,34 @@ func (self *StateDB) IsDeleted(addr []byte) bool { // Update the given state object and apply it to state trie func (self *StateDB) UpdateStateObject(stateObject *StateObject) { - addr := stateObject.Address() + //addr := stateObject.Address() if len(stateObject.CodeHash()) > 0 { self.db.Put(stateObject.CodeHash(), stateObject.code) } - self.trie.Update(addr, stateObject.RlpEncode()) + addr := stateObject.Address() + self.trie.Update(addr[:], stateObject.RlpEncode()) } // Delete the given state object and delete it from the state trie func (self *StateDB) DeleteStateObject(stateObject *StateObject) { - self.trie.Delete(stateObject.Address()) + addr := stateObject.Address() + self.trie.Delete(addr[:]) - delete(self.stateObjects, string(stateObject.Address())) + delete(self.stateObjects, addr.Str()) } // Retrieve a state object given my the address. Nil if not found -func (self *StateDB) GetStateObject(addr []byte) *StateObject { - addr = common.Address(addr) +func (self *StateDB) GetStateObject(addr common.Address) *StateObject { + //addr = common.Address(addr) - stateObject := self.stateObjects[string(addr)] + stateObject := self.stateObjects[addr.Str()] if stateObject != nil { return stateObject } - data := self.trie.Get(addr) + data := self.trie.Get(addr[:]) if len(data) == 0 { return nil } @@ -184,11 +187,11 @@ func (self *StateDB) GetStateObject(addr []byte) *StateObject { } func (self *StateDB) SetStateObject(object *StateObject) { - self.stateObjects[string(object.address)] = object + self.stateObjects[object.Address().Str()] = object } // Retrieve a state object or create a new state object if nil -func (self *StateDB) GetOrNewStateObject(addr []byte) *StateObject { +func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject { stateObject := self.GetStateObject(addr) if stateObject == nil { stateObject = self.NewStateObject(addr) @@ -198,19 +201,19 @@ func (self *StateDB) GetOrNewStateObject(addr []byte) *StateObject { } // Create a state object whether it exist in the trie or not -func (self *StateDB) NewStateObject(addr []byte) *StateObject { - addr = common.Address(addr) +func (self *StateDB) NewStateObject(addr common.Address) *StateObject { + //addr = common.Address(addr) statelogger.Debugf("(+) %x\n", addr) stateObject := NewStateObject(addr, self.db) - self.stateObjects[string(addr)] = stateObject + self.stateObjects[addr.Str()] = stateObject return stateObject } // Deprecated -func (self *StateDB) GetAccount(addr []byte) *StateObject { +func (self *StateDB) GetAccount(addr common.Address) *StateObject { return self.GetOrNewStateObject(addr) } @@ -223,7 +226,7 @@ func (s *StateDB) Cmp(other *StateDB) bool { } func (self *StateDB) Copy() *StateDB { - state := New(nil, self.db) + state := New(common.Hash{}, self.db) state.trie = self.trie.Copy() for k, stateObject := range self.stateObjects { state.stateObjects[k] = stateObject.Copy() @@ -248,8 +251,8 @@ func (self *StateDB) Set(state *StateDB) { self.logs = state.logs } -func (s *StateDB) Root() []byte { - return s.trie.Root() +func (s *StateDB) Root() common.Hash { + return common.BytesToHash(s.trie.Root()) } func (s *StateDB) Trie() *trie.SecureTrie { diff --git a/tests/blocktest.go b/tests/blocktest.go index 0b923f08b..44b459c8d 100644 --- a/tests/blocktest.go +++ b/tests/blocktest.go @@ -12,8 +12,8 @@ import ( "strconv" "strings" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/state" ) @@ -98,15 +98,15 @@ func LoadBlockTests(file string) (map[string]*BlockTest, error) { // InsertPreState populates the given database with the genesis // accounts defined by the test. func (t *BlockTest) InsertPreState(db common.Database) error { - statedb := state.New(nil, db) + statedb := state.New(common.Hash{}, db) for addrString, acct := range t.preAccounts { // XXX: is is worth it checking for errors here? - addr, _ := hex.DecodeString(addrString) + //addr, _ := hex.DecodeString(addrString) code, _ := hex.DecodeString(strings.TrimPrefix(acct.Code, "0x")) balance, _ := new(big.Int).SetString(acct.Balance, 0) nonce, _ := strconv.ParseUint(acct.Nonce, 16, 64) - obj := statedb.NewStateObject(addr) + obj := statedb.NewStateObject(common.HexToAddress(addrString)) obj.SetCode(code) obj.SetBalance(balance) obj.SetNonce(nonce) @@ -119,7 +119,7 @@ func (t *BlockTest) InsertPreState(db common.Database) error { // sync trie to disk statedb.Sync() - if !bytes.Equal(t.Genesis.Root(), statedb.Root()) { + if t.Genesis.Root() != statedb.Root() { return errors.New("computed state root does not match genesis block") } return nil @@ -153,23 +153,25 @@ func mustConvertGenesis(testGenesis btHeader) *types.Block { func mustConvertHeader(in btHeader) *types.Header { // hex decode these fields - return &types.Header{ + header := &types.Header{ //SeedHash: mustConvertBytes(in.SeedHash), - MixDigest: mustConvertBytes(in.MixHash), - Bloom: mustConvertBytes(in.Bloom), - ReceiptHash: mustConvertBytes(in.ReceiptTrie), - TxHash: mustConvertBytes(in.TransactionsTrie), - Root: mustConvertBytes(in.StateRoot), - Coinbase: mustConvertBytes(in.Coinbase), - UncleHash: mustConvertBytes(in.UncleHash), - ParentHash: mustConvertBytes(in.ParentHash), - Nonce: mustConvertBytes(in.Nonce), + MixDigest: mustConvertHash(in.MixHash), + Bloom: mustConvertBloom(in.Bloom), + ReceiptHash: mustConvertHash(in.ReceiptTrie), + TxHash: mustConvertHash(in.TransactionsTrie), + Root: mustConvertHash(in.StateRoot), + Coinbase: mustConvertAddress(in.Coinbase), + UncleHash: mustConvertHash(in.UncleHash), + ParentHash: mustConvertHash(in.ParentHash), Extra: string(mustConvertBytes(in.ExtraData)), GasUsed: mustConvertBigInt10(in.GasUsed), GasLimit: mustConvertBigInt10(in.GasLimit), Difficulty: mustConvertBigInt10(in.Difficulty), Time: mustConvertUint(in.Timestamp), } + // XXX cheats? :-) + header.SetNonce(common.BytesToHash(mustConvertBytes(in.Nonce)).Big().Uint64()) + return header } func mustConvertBlocks(testBlocks []btBlock) []*types.Block { @@ -193,6 +195,30 @@ func mustConvertBytes(in string) []byte { return out } +func mustConvertHash(in string) common.Hash { + out, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) + if err != nil { + panic(fmt.Errorf("invalid hex: %q", in)) + } + return common.BytesToHash(out) +} + +func mustConvertAddress(in string) common.Address { + out, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) + if err != nil { + panic(fmt.Errorf("invalid hex: %q", in)) + } + return common.BytesToAddress(out) +} + +func mustConvertBloom(in string) types.Bloom { + out, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) + if err != nil { + panic(fmt.Errorf("invalid hex: %q", in)) + } + return types.BytesToBloom(out) +} + func mustConvertBigInt10(in string) *big.Int { out, ok := new(big.Int).SetString(in, 10) if !ok { diff --git a/tests/helper/vm.go b/tests/helper/vm.go index a7fd98696..44c108870 100644 --- a/tests/helper/vm.go +++ b/tests/helper/vm.go @@ -4,9 +4,9 @@ import ( "errors" "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" ) @@ -18,9 +18,9 @@ type Env struct { initial bool Gas *big.Int - origin []byte - parent []byte - coinbase []byte + origin common.Address + //parent common.Hash + coinbase common.Address number *big.Int time int64 @@ -41,9 +41,9 @@ func NewEnv(state *state.StateDB) *Env { func NewEnvFromMap(state *state.StateDB, envValues map[string]string, exeValues map[string]string) *Env { env := NewEnv(state) - env.origin = common.Hex2Bytes(exeValues["caller"]) - env.parent = common.Hex2Bytes(envValues["previousHash"]) - env.coinbase = common.Hex2Bytes(envValues["currentCoinbase"]) + env.origin = common.HexToAddress(exeValues["caller"]) + //env.parent = common.Hex2Bytes(envValues["previousHash"]) + env.coinbase = common.HexToAddress(envValues["currentCoinbase"]) env.number = common.Big(envValues["currentNumber"]) env.time = common.Big(envValues["currentTimestamp"]).Int64() env.difficulty = common.Big(envValues["currentDifficulty"]) @@ -53,17 +53,18 @@ func NewEnvFromMap(state *state.StateDB, envValues map[string]string, exeValues return env } -func (self *Env) Origin() []byte { return self.origin } -func (self *Env) BlockNumber() *big.Int { return self.number } -func (self *Env) PrevHash() []byte { return self.parent } -func (self *Env) Coinbase() []byte { return self.coinbase } -func (self *Env) Time() int64 { return self.time } -func (self *Env) Difficulty() *big.Int { return self.difficulty } -func (self *Env) State() *state.StateDB { return self.state } -func (self *Env) GasLimit() *big.Int { return self.gasLimit } -func (self *Env) VmType() vm.Type { return vm.StdVmTy } -func (self *Env) GetHash(n uint64) []byte { - return crypto.Sha3([]byte(big.NewInt(int64(n)).String())) +func (self *Env) Origin() common.Address { return self.origin } +func (self *Env) BlockNumber() *big.Int { return self.number } + +//func (self *Env) PrevHash() []byte { return self.parent } +func (self *Env) Coinbase() common.Address { return self.coinbase } +func (self *Env) Time() int64 { return self.time } +func (self *Env) Difficulty() *big.Int { return self.difficulty } +func (self *Env) State() *state.StateDB { return self.state } +func (self *Env) GasLimit() *big.Int { return self.gasLimit } +func (self *Env) VmType() vm.Type { return vm.StdVmTy } +func (self *Env) GetHash(n uint64) common.Hash { + return common.BytesToHash(crypto.Sha3([]byte(big.NewInt(int64(n)).String()))) } func (self *Env) AddLog(log state.Log) { self.logs = append(self.logs, log) @@ -87,36 +88,38 @@ func (self *Env) Transfer(from, to vm.Account, amount *big.Int) error { return vm.Transfer(from, to, amount) } -func (self *Env) vm(addr, data []byte, gas, price, value *big.Int) *core.Execution { +func (self *Env) vm(addr *common.Address, data []byte, gas, price, value *big.Int) *core.Execution { exec := core.NewExecution(self, addr, data, gas, price, value) return exec } -func (self *Env) Call(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) { +func (self *Env) Call(caller vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { if self.vmTest && self.depth > 0 { caller.ReturnGas(gas, price) return nil, nil } - exe := self.vm(addr, data, gas, price, value) + exe := self.vm(&addr, data, gas, price, value) ret, err := exe.Call(addr, caller) self.Gas = exe.Gas return ret, err } -func (self *Env) CallCode(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) { +func (self *Env) CallCode(caller vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { if self.vmTest && self.depth > 0 { caller.ReturnGas(gas, price) return nil, nil } - exe := self.vm(caller.Address(), data, gas, price, value) + + caddr := caller.Address() + exe := self.vm(&caddr, data, gas, price, value) return exe.Call(addr, caller) } -func (self *Env) Create(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { +func (self *Env) Create(caller vm.ContextRef, addr *common.Address, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { exe := self.vm(addr, data, gas, price, value) if self.vmTest { caller.ReturnGas(gas, price) @@ -132,8 +135,8 @@ func (self *Env) Create(caller vm.ContextRef, addr, data []byte, gas, price, val func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, state.Logs, *big.Int, error) { var ( - to = FromHex(exec["address"]) - from = FromHex(exec["caller"]) + to = common.HexToAddress(exec["address"]) + from = common.HexToAddress(exec["caller"]) data = FromHex(exec["data"]) gas = common.Big(exec["gas"]) price = common.Big(exec["gasPrice"]) @@ -156,14 +159,18 @@ func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, state.Log func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, state.Logs, *big.Int, error) { var ( keyPair, _ = crypto.NewKeyPairFromSec([]byte(common.Hex2Bytes(tx["secretKey"]))) - to = FromHex(tx["to"]) data = FromHex(tx["data"]) gas = common.Big(tx["gasLimit"]) price = common.Big(tx["gasPrice"]) value = common.Big(tx["value"]) - caddr = FromHex(env["currentCoinbase"]) + caddr = common.HexToAddress(env["currentCoinbase"]) ) + var to *common.Address + if len(tx["to"]) > 2 { + t := common.HexToAddress(tx["to"]) + to = &t + } // Set pre compiled contracts vm.Precompiled = vm.PrecompiledContracts() @@ -171,9 +178,9 @@ func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, state. coinbase := statedb.GetOrNewStateObject(caddr) coinbase.SetGasPool(common.Big(env["currentGasLimit"])) - message := NewMessage(keyPair.Address(), to, data, value, gas, price) + message := NewMessage(common.BytesToAddress(keyPair.Address()), to, data, value, gas, price) vmenv := NewEnvFromMap(statedb, env, tx) - vmenv.origin = keyPair.Address() + vmenv.origin = common.BytesToAddress(keyPair.Address()) ret, _, err := core.ApplyMessage(vmenv, message, coinbase) if core.IsNonceErr(err) || core.IsInvalidTxErr(err) { statedb.Set(snapshot) @@ -184,20 +191,21 @@ func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, state. } type Message struct { - from, to []byte + from common.Address + to *common.Address value, gas, price *big.Int data []byte } -func NewMessage(from, to, data []byte, value, gas, price *big.Int) Message { +func NewMessage(from common.Address, to *common.Address, data []byte, value, gas, price *big.Int) Message { return Message{from, to, value, gas, price, data} } -func (self Message) Hash() []byte { return nil } -func (self Message) From() []byte { return self.from } -func (self Message) To() []byte { return self.to } -func (self Message) GasPrice() *big.Int { return self.price } -func (self Message) Gas() *big.Int { return self.gas } -func (self Message) Value() *big.Int { return self.value } -func (self Message) Nonce() uint64 { return 0 } -func (self Message) Data() []byte { return self.data } +func (self Message) Hash() []byte { return nil } +func (self Message) From() (common.Address, error) { return self.from, nil } +func (self Message) To() *common.Address { return self.to } +func (self Message) GasPrice() *big.Int { return self.price } +func (self Message) Gas() *big.Int { return self.gas } +func (self Message) Value() *big.Int { return self.value } +func (self Message) Nonce() uint64 { return 0 } +func (self Message) Data() []byte { return self.data } diff --git a/tests/vm/gh_test.go b/tests/vm/gh_test.go index 24718de7b..68600d304 100644 --- a/tests/vm/gh_test.go +++ b/tests/vm/gh_test.go @@ -6,8 +6,9 @@ import ( "strconv" "testing" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/tests/helper" @@ -39,7 +40,7 @@ func (self Log) Topics() [][]byte { } func StateObjectFromAccount(db common.Database, addr string, account Account) *state.StateObject { - obj := state.NewStateObject(common.Hex2Bytes(addr), db) + obj := state.NewStateObject(common.HexToAddress(addr), db) obj.SetBalance(common.Big(account.Balance)) if common.IsHex(account.Code) { @@ -81,12 +82,12 @@ func RunVmTest(p string, t *testing.T) { for name, test := range tests { db, _ := ethdb.NewMemDatabase() - statedb := state.New(nil, db) + statedb := state.New(common.Hash{}, db) for addr, account := range test.Pre { obj := StateObjectFromAccount(db, addr, account) statedb.SetStateObject(obj) for a, v := range account.Storage { - obj.SetState(helper.FromHex(a), common.NewValue(helper.FromHex(v))) + obj.SetState(common.HexToHash(a), common.NewValue(helper.FromHex(v))) } } @@ -134,30 +135,31 @@ func RunVmTest(p string, t *testing.T) { } for addr, account := range test.Post { - obj := statedb.GetStateObject(helper.FromHex(addr)) + obj := statedb.GetStateObject(common.HexToAddress(addr)) if obj == nil { continue } if len(test.Exec) == 0 { if obj.Balance().Cmp(common.Big(account.Balance)) != 0 { - t.Errorf("%s's : (%x) balance failed. Expected %v, got %v => %v\n", name, obj.Address()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(common.Big(account.Balance), obj.Balance())) + t.Errorf("%s's : (%x) balance failed. Expected %v, got %v => %v\n", name, obj.Address().Bytes()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(common.Big(account.Balance), obj.Balance())) } } for addr, value := range account.Storage { - v := obj.GetState(helper.FromHex(addr)).Bytes() + v := obj.GetState(common.HexToHash(addr)).Bytes() vexp := helper.FromHex(value) if bytes.Compare(v, vexp) != 0 { - t.Errorf("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address()[0:4], addr, vexp, v, common.BigD(vexp), common.BigD(v)) + t.Errorf("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address().Bytes()[0:4], addr, vexp, v, common.BigD(vexp), common.BigD(v)) } } } if !isVmTest { statedb.Sync() - if !bytes.Equal(common.Hex2Bytes(test.PostStateRoot), statedb.Root()) { + //if !bytes.Equal(common.Hex2Bytes(test.PostStateRoot), statedb.Root()) { + if common.HexToHash(test.PostStateRoot) != statedb.Root() { t.Errorf("%s's : Post state root error. Expected %s, got %x", name, test.PostStateRoot, statedb.Root()) } } @@ -166,16 +168,30 @@ func RunVmTest(p string, t *testing.T) { if len(test.Logs) != len(logs) { t.Errorf("log length mismatch. Expected %d, got %d", len(test.Logs), len(logs)) } else { - /* - fmt.Println("A", test.Logs) - fmt.Println("B", logs) - for i, log := range test.Logs { - genBloom := common.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 256) - if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) { - t.Errorf("bloom mismatch") + for i, log := range test.Logs { + if common.HexToAddress(log.AddressF) != logs[i].Address() { + t.Errorf("'%s' log address expected %v got %x", name, log.AddressF, logs[i].Address()) + } + + if !bytes.Equal(logs[i].Data(), helper.FromHex(log.DataF)) { + t.Errorf("'%s' log data expected %v got %x", name, log.DataF, logs[i].Data()) + } + + if len(log.TopicsF) != len(logs[i].Topics()) { + t.Errorf("'%s' log topics length expected %d got %d", name, len(log.TopicsF), logs[i].Topics()) + } else { + for j, topic := range log.TopicsF { + if common.HexToHash(topic) != logs[i].Topics()[j] { + t.Errorf("'%s' log topic[%d] expected %v got %x", name, j, topic, logs[i].Topics()[j]) } } - */ + } + genBloom := common.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 256) + + if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) { + t.Errorf("'%s' bloom mismatch", name) + } + } } } //statedb.Trie().PrintRoot() diff --git a/vm/common.go b/vm/common.go index 90c3361de..5441a4ac5 100644 --- a/vm/common.go +++ b/vm/common.go @@ -18,8 +18,23 @@ type Type byte const ( StdVmTy Type = iota JitVmTy - MaxVmTy + + MaxCallDepth = 1025 + + LogTyPretty byte = 0x1 + LogTyDiff byte = 0x2 +) + +var ( + Pow256 = common.BigPow(2, 256) + + U256 = common.U256 + S256 = common.S256 + + Zero = common.Big0 + + max = big.NewInt(math.MaxInt64) ) func NewVm(env Environment) VirtualMachine { @@ -34,67 +49,6 @@ func NewVm(env Environment) VirtualMachine { } } -var ( - GasQuickStep = big.NewInt(2) - GasFastestStep = big.NewInt(3) - GasFastStep = big.NewInt(5) - GasMidStep = big.NewInt(8) - GasSlowStep = big.NewInt(10) - GasExtStep = big.NewInt(20) - - GasStorageGet = big.NewInt(50) - GasStorageAdd = big.NewInt(20000) - GasStorageMod = big.NewInt(5000) - GasLogBase = big.NewInt(375) - GasLogTopic = big.NewInt(375) - GasLogByte = big.NewInt(8) - GasCreate = big.NewInt(32000) - GasCreateByte = big.NewInt(200) - GasCall = big.NewInt(40) - GasCallValueTransfer = big.NewInt(9000) - GasStipend = big.NewInt(2300) - GasCallNewAccount = big.NewInt(25000) - GasReturn = big.NewInt(0) - GasStop = big.NewInt(0) - GasJumpDest = big.NewInt(1) - - RefundStorage = big.NewInt(15000) - RefundSuicide = big.NewInt(24000) - - GasMemWord = big.NewInt(3) - GasQuadCoeffDenom = big.NewInt(512) - GasContractByte = big.NewInt(200) - GasTransaction = big.NewInt(21000) - GasTxDataNonzeroByte = big.NewInt(68) - GasTxDataZeroByte = big.NewInt(4) - GasTx = big.NewInt(21000) - GasExp = big.NewInt(10) - GasExpByte = big.NewInt(10) - - GasSha3Base = big.NewInt(30) - GasSha3Word = big.NewInt(6) - GasSha256Base = big.NewInt(60) - GasSha256Word = big.NewInt(12) - GasRipemdBase = big.NewInt(600) - GasRipemdWord = big.NewInt(12) - GasEcrecover = big.NewInt(3000) - GasIdentityBase = big.NewInt(15) - GasIdentityWord = big.NewInt(3) - GasCopyWord = big.NewInt(3) - - Pow256 = common.BigPow(2, 256) - - LogTyPretty byte = 0x1 - LogTyDiff byte = 0x2 - - U256 = common.U256 - S256 = common.S256 - - Zero = common.Big0 -) - -const MaxCallDepth = 1025 - func calcMemSize(off, l *big.Int) *big.Int { if l.Cmp(common.Big0) == 0 { return common.Big0 diff --git a/vm/context.go b/vm/context.go index 1c2f665a4..ea70f2376 100644 --- a/vm/context.go +++ b/vm/context.go @@ -9,7 +9,7 @@ import ( type ContextRef interface { ReturnGas(*big.Int, *big.Int) - Address() []byte + Address() common.Address SetCode([]byte) } @@ -18,7 +18,7 @@ type Context struct { self ContextRef Code []byte - CodeAddr []byte + CodeAddr *common.Address value, Gas, UsedGas, Price *big.Int @@ -100,7 +100,7 @@ func (c *Context) ReturnGas(gas, price *big.Int) { /* * Set / Get */ -func (c *Context) Address() []byte { +func (c *Context) Address() common.Address { return c.self.Address() } @@ -108,7 +108,7 @@ func (self *Context) SetCode(code []byte) { self.Code = code } -func (self *Context) SetCallCode(addr, code []byte) { +func (self *Context) SetCallCode(addr *common.Address, code []byte) { self.Code = code self.CodeAddr = addr } diff --git a/vm/environment.go b/vm/environment.go index 83faaa23e..5d493166c 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -3,19 +3,21 @@ package vm import ( "errors" "fmt" + "io" "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/state" ) type Environment interface { State() *state.StateDB - Origin() []byte + Origin() common.Address BlockNumber() *big.Int - GetHash(n uint64) []byte - Coinbase() []byte + GetHash(n uint64) common.Hash + Coinbase() common.Address Time() int64 Difficulty() *big.Int GasLimit() *big.Int @@ -27,16 +29,16 @@ type Environment interface { Depth() int SetDepth(i int) - Call(me ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) - CallCode(me ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) - Create(me ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, ContextRef) + Call(me ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) + CallCode(me ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) + Create(me ContextRef, addr *common.Address, data []byte, gas, price, value *big.Int) ([]byte, error, ContextRef) } type Account interface { SubBalance(amount *big.Int) AddBalance(amount *big.Int) Balance() *big.Int - Address() []byte + Address() common.Address } // generic transfer method @@ -53,17 +55,17 @@ func Transfer(from, to Account, amount *big.Int) error { } type Log struct { - address []byte - topics [][]byte + address common.Address + topics []common.Hash data []byte log uint64 } -func (self *Log) Address() []byte { +func (self *Log) Address() common.Address { return self.address } -func (self *Log) Topics() [][]byte { +func (self *Log) Topics() []common.Hash { return self.topics } @@ -75,10 +77,16 @@ func (self *Log) Number() uint64 { return self.log } +func (self *Log) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, []interface{}{self.address, self.topics, self.data}) +} + +/* func (self *Log) RlpData() interface{} { return []interface{}{self.address, common.ByteSliceToInterface(self.topics), self.data} } +*/ func (self *Log) String() string { - return fmt.Sprintf("[A=%x T=%x D=%x]", self.address, self.topics, self.data) + return fmt.Sprintf("{%x %x %x}", self.address, self.data, self.topics) } @@ -7,6 +7,55 @@ type req struct { gas *big.Int } +var ( + GasQuickStep = big.NewInt(2) + GasFastestStep = big.NewInt(3) + GasFastStep = big.NewInt(5) + GasMidStep = big.NewInt(8) + GasSlowStep = big.NewInt(10) + GasExtStep = big.NewInt(20) + + GasStorageGet = big.NewInt(50) + GasStorageAdd = big.NewInt(20000) + GasStorageMod = big.NewInt(5000) + GasLogBase = big.NewInt(375) + GasLogTopic = big.NewInt(375) + GasLogByte = big.NewInt(8) + GasCreate = big.NewInt(32000) + GasCreateByte = big.NewInt(200) + GasCall = big.NewInt(40) + GasCallValueTransfer = big.NewInt(9000) + GasStipend = big.NewInt(2300) + GasCallNewAccount = big.NewInt(25000) + GasReturn = big.NewInt(0) + GasStop = big.NewInt(0) + GasJumpDest = big.NewInt(1) + + RefundStorage = big.NewInt(15000) + RefundSuicide = big.NewInt(24000) + + GasMemWord = big.NewInt(3) + GasQuadCoeffDenom = big.NewInt(512) + GasContractByte = big.NewInt(200) + GasTransaction = big.NewInt(21000) + GasTxDataNonzeroByte = big.NewInt(68) + GasTxDataZeroByte = big.NewInt(4) + GasTx = big.NewInt(21000) + GasExp = big.NewInt(10) + GasExpByte = big.NewInt(10) + + GasSha3Base = big.NewInt(30) + GasSha3Word = big.NewInt(6) + GasSha256Base = big.NewInt(60) + GasSha256Word = big.NewInt(12) + GasRipemdBase = big.NewInt(600) + GasRipemdWord = big.NewInt(12) + GasEcrecover = big.NewInt(3000) + GasIdentityBase = big.NewInt(15) + GasIdentityWord = big.NewInt(3) + GasCopyWord = big.NewInt(3) +) + var _baseCheck = map[OpCode]req{ // Req stack Gas price ADD: {2, GasFastestStep}, @@ -33,10 +33,7 @@ func New(env Environment) *Vm { } func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { - //func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) { self.env.SetDepth(self.env.Depth() + 1) - - //context := NewContext(caller, me, code, gas, price) var ( caller = context.caller code = context.Code @@ -44,7 +41,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { price = context.Price ) - self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address()[:4], context.Address(), len(code), context.Gas, callData).Endl() + self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address().Bytes()[:4], context.Address(), len(code), context.Gas, callData).Endl() if self.Recoverable { // Recover from any require exception @@ -57,13 +54,14 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { ret = context.Return(nil) err = fmt.Errorf("%v", r) - } }() } - if p := Precompiled[string(context.CodeAddr)]; p != nil { - return self.RunPrecompiled(p, callData, context) + if context.CodeAddr != nil { + if p := Precompiled[context.CodeAddr.Str()]; p != nil { + return self.RunPrecompiled(p, callData, context) + } } var ( @@ -394,11 +392,11 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { self.Printf(" => (%v) %x", size, data) // 0x30 range case ADDRESS: - stack.push(common.BigD(context.Address())) + stack.push(common.Bytes2Big(context.Address().Bytes())) self.Printf(" => %x", context.Address()) case BALANCE: - addr := stack.pop().Bytes() + addr := common.BigToAddress(stack.pop()) balance := statedb.GetBalance(addr) stack.push(balance) @@ -407,12 +405,12 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { case ORIGIN: origin := self.env.Origin() - stack.push(common.BigD(origin)) + stack.push(origin.Big()) self.Printf(" => %x", origin) case CALLER: caller := context.caller.Address() - stack.push(common.BigD(caller)) + stack.push(common.Bytes2Big(caller.Bytes())) self.Printf(" => %x", caller) case CALLVALUE: @@ -458,7 +456,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { case CODESIZE, EXTCODESIZE: var code []byte if op == EXTCODESIZE { - addr := stack.pop().Bytes() + addr := common.BigToAddress(stack.pop()) code = statedb.GetCode(addr) } else { @@ -472,7 +470,8 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { case CODECOPY, EXTCODECOPY: var code []byte if op == EXTCODECOPY { - code = statedb.GetCode(stack.pop().Bytes()) + addr := common.BigToAddress(stack.pop()) + code = statedb.GetCode(addr) } else { code = context.Code } @@ -502,7 +501,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { n := new(big.Int).Sub(self.env.BlockNumber(), common.Big257) if num.Cmp(n) > 0 && num.Cmp(self.env.BlockNumber()) < 0 { - stack.push(common.BigD(self.env.GetHash(num.Uint64()))) + stack.push(self.env.GetHash(num.Uint64()).Big()) } else { stack.push(common.Big0) } @@ -511,7 +510,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { case COINBASE: coinbase := self.env.Coinbase() - stack.push(common.BigD(coinbase)) + stack.push(coinbase.Big()) self.Printf(" => 0x%x", coinbase) case TIMESTAMP: @@ -562,10 +561,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { self.Printf(" => [%d]", n) case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) - topics := make([][]byte, n) + topics := make([]common.Hash, n) mStart, mSize := stack.pop(), stack.pop() for i := 0; i < n; i++ { - topics[i] = common.LeftPadBytes(stack.pop().Bytes(), 32) + topics[i] = common.BigToHash(stack.pop()) //common.LeftPadBytes(stack.pop().Bytes(), 32) } data := mem.Get(mStart.Int64(), mSize.Int64()) @@ -592,16 +591,18 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { self.Printf(" => [%v] 0x%x", off, val) case SLOAD: - loc := stack.pop() - val := common.BigD(statedb.GetState(context.Address(), loc.Bytes())) + loc := common.BigToHash(stack.pop()) + val := common.Bytes2Big(statedb.GetState(context.Address(), loc)) stack.push(val) - self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) + self.Printf(" {0x%x : 0x%x}", loc, val.Bytes()) case SSTORE: - loc, val := stack.pop(), stack.pop() - statedb.SetState(context.Address(), loc.Bytes(), val) + loc := common.BigToHash(stack.pop()) + val := stack.pop() + + statedb.SetState(context.Address(), loc, val) - self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) + self.Printf(" {0x%x : 0x%x}", loc, val.Bytes()) case JUMP: jump(pc, stack.pop()) @@ -634,7 +635,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { offset, size = stack.pop(), stack.pop() input = mem.Get(offset.Int64(), size.Int64()) gas = new(big.Int).Set(context.Gas) - addr []byte + addr common.Address ) self.Endl() @@ -654,7 +655,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { } addr = ref.Address() - stack.push(common.BigD(addr)) + stack.push(addr.Big()) } @@ -668,7 +669,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { // pop return size and offset retOffset, retSize := stack.pop(), stack.pop() - address := common.Address(addr.Bytes()) + address := common.BigToAddress(addr) self.Printf(" => %x", address).Endl() // Get the arguments from the memory @@ -706,10 +707,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) { return context.Return(ret), nil case SUICIDE: - receiver := statedb.GetOrNewStateObject(stack.pop().Bytes()) + receiver := statedb.GetOrNewStateObject(common.BigToAddress(stack.pop())) balance := statedb.GetBalance(context.Address()) - self.Printf(" => (%x) %v", receiver.Address()[:4], balance) + self.Printf(" => (%x) %v", receiver.Address().Bytes()[:4], balance) receiver.AddBalance(balance) @@ -769,7 +770,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo var g *big.Int y, x := stack.data[stack.len()-2], stack.data[stack.len()-1] - val := statedb.GetState(context.Address(), x.Bytes()) + val := statedb.GetState(context.Address(), common.BigToHash(x)) if len(val) == 0 && len(y.Bytes()) > 0 { // 0 => non 0 g = GasStorageAdd @@ -821,7 +822,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo gas.Add(gas, stack.data[stack.len()-1]) if op == CALL { - if self.env.State().GetStateObject(stack.data[stack.len()-2].Bytes()) == nil { + if self.env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil { gas.Add(gas, GasCallNewAccount) } } diff --git a/whisper/envelope.go b/whisper/envelope.go index 577638046..9ec9fc318 100644 --- a/whisper/envelope.go +++ b/whisper/envelope.go @@ -6,9 +6,9 @@ import ( "fmt" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rlp" ) diff --git a/whisper/peer.go b/whisper/peer.go index 4bd9428f5..ee5bffd0b 100644 --- a/whisper/peer.go +++ b/whisper/peer.go @@ -77,12 +77,11 @@ func (self *peer) broadcast(envelopes []*Envelope) error { } if i > 0 { - if err := p2p.EncodeMsg(self.ws, envelopesMsg, envs[:i]...); err != nil { + if err := p2p.Send(self.ws, envelopesMsg, envs[:i]); err != nil { return err } self.peer.DebugDetailln("broadcasted", i, "message(s)") } - return nil } @@ -92,7 +91,7 @@ func (self *peer) addKnown(envelope *Envelope) { func (self *peer) handleStatus() error { ws := self.ws - if err := ws.WriteMsg(self.statusMsg()); err != nil { + if err := p2p.SendItems(ws, statusMsg, protocolVersion); err != nil { return err } msg, err := ws.ReadMsg() @@ -115,7 +114,3 @@ func (self *peer) handleStatus() error { } return msg.Discard() // ignore anything after protocol version } - -func (self *peer) statusMsg() p2p.Msg { - return p2p.NewMsg(statusMsg, protocolVersion) -} diff --git a/xeth/state.go b/xeth/state.go index 7d9ceab1b..f645a9cac 100644 --- a/xeth/state.go +++ b/xeth/state.go @@ -19,7 +19,7 @@ func (self *State) State() *state.StateDB { } func (self *State) Get(addr string) *Object { - return &Object{self.state.GetStateObject(common.FromHex(addr))} + return &Object{self.state.GetStateObject(common.HexToAddress(addr))} } func (self *State) SafeGet(addr string) *Object { @@ -27,9 +27,9 @@ func (self *State) SafeGet(addr string) *Object { } func (self *State) safeGet(addr string) *state.StateObject { - object := self.state.GetStateObject(common.FromHex(addr)) + object := self.state.GetStateObject(common.HexToAddress(addr)) if object == nil { - object = state.NewStateObject(common.FromHex(addr), self.xeth.eth.StateDb()) + object = state.NewStateObject(common.HexToAddress(addr), self.xeth.eth.StateDb()) } return object diff --git a/xeth/types.go b/xeth/types.go index 6b3b6d29f..b4ba7bab0 100644 --- a/xeth/types.go +++ b/xeth/types.go @@ -91,12 +91,12 @@ func NewBlock(block *types.Block) *Block { return &Block{ ref: block, Size: block.Size().String(), Number: int(block.NumberU64()), GasUsed: block.GasUsed().String(), - GasLimit: block.GasLimit().String(), Hash: common.ToHex(block.Hash()), + GasLimit: block.GasLimit().String(), Hash: block.Hash().Hex(), Transactions: txlist, Uncles: ulist, Time: block.Time(), - Coinbase: common.ToHex(block.Coinbase()), - PrevHash: common.ToHex(block.ParentHash()), - Bloom: common.ToHex(block.Bloom()), + Coinbase: block.Coinbase().Hex(), + PrevHash: block.ParentHash().Hex(), + Bloom: common.ToHex(block.Bloom().Bytes()), Raw: block.String(), } } @@ -110,7 +110,7 @@ func (self *Block) ToString() string { } func (self *Block) GetTransaction(hash string) *Transaction { - tx := self.ref.Transaction(common.FromHex(hash)) + tx := self.ref.Transaction(common.HexToHash(hash)) if tx == nil { return nil } @@ -135,12 +135,12 @@ type Transaction struct { } func NewTx(tx *types.Transaction) *Transaction { - hash := common.ToHex(tx.Hash()) - receiver := common.ToHex(tx.To()) + hash := tx.Hash().Hex() + receiver := tx.To().Hex() if len(receiver) == 0 { - receiver = common.ToHex(core.AddressFromMessage(tx)) + receiver = core.AddressFromMessage(tx).Hex() } - sender := common.ToHex(tx.From()) + sender, _ := tx.From() createsContract := core.MessageCreatesContract(tx) var data string @@ -150,7 +150,7 @@ func NewTx(tx *types.Transaction) *Transaction { data = common.ToHex(tx.Data()) } - return &Transaction{ref: tx, Hash: hash, Value: common.CurrencyToString(tx.Value()), Address: receiver, Contract: createsContract, Gas: tx.Gas().String(), GasPrice: tx.GasPrice().String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: common.ToHex(tx.Data())} + return &Transaction{ref: tx, Hash: hash, Value: common.CurrencyToString(tx.Value()), Address: receiver, Contract: createsContract, Gas: tx.Gas().String(), GasPrice: tx.GasPrice().String(), Data: data, Sender: sender.Hex(), CreatesContract: createsContract, RawData: common.ToHex(tx.Data())} } func (self *Transaction) ToString() string { diff --git a/xeth/xeth.go b/xeth/xeth.go index 115bd787a..686ed4432 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -116,14 +116,14 @@ func (self *XEth) State() *State { return self.state } func (self *XEth) Whisper() *Whisper { return self.whisper } func (self *XEth) BlockByHash(strHash string) *Block { - hash := common.FromHex(strHash) + hash := common.HexToHash(strHash) block := self.chainManager.GetBlock(hash) return NewBlock(block) } func (self *XEth) EthBlockByHash(strHash string) *types.Block { - hash := common.FromHex(strHash) + hash := common.HexToHash(strHash) block := self.chainManager.GetBlock(hash) return block @@ -293,9 +293,9 @@ func (self *XEth) PushTx(encodedTx string) (string, error) { if tx.To() == nil { addr := core.AddressFromMessage(tx) - return common.ToHex(addr), nil + return addr.Hex(), nil } - return common.ToHex(tx.Hash()), nil + return tx.Hash().Hex(), nil } var ( @@ -306,8 +306,8 @@ var ( func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) { statedb := self.State().State() //self.chainManager.TransState() msg := callmsg{ - from: statedb.GetOrNewStateObject(common.FromHex(fromStr)), - to: common.FromHex(toStr), + from: statedb.GetOrNewStateObject(common.HexToAddress(fromStr)), + to: common.HexToAddress(toStr), gas: common.Big(gasStr), gasPrice: common.Big(gasPriceStr), value: common.Big(valueStr), @@ -330,8 +330,8 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { var ( - from []byte - to []byte + from = common.HexToAddress(fromStr) + to = common.HexToAddress(toStr) value = common.NewValue(valueStr) gas = common.NewValue(gasStr) price = common.NewValue(gasPriceStr) @@ -339,10 +339,8 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt contractCreation bool ) - from = common.FromHex(fromStr) data = common.FromHex(codeStr) - to = common.FromHex(toStr) - if len(to) == 0 { + if len(toStr) == 0 { contractCreation = true } @@ -368,21 +366,19 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt if contractCreation { addr := core.AddressFromMessage(tx) pipelogger.Infof("Contract addr %x\n", addr) - } - if types.IsContractAddr(to) { - return common.ToHex(core.AddressFromMessage(tx)), nil + return core.AddressFromMessage(tx).Hex(), nil } - return common.ToHex(tx.Hash()), nil + return tx.Hash().Hex(), nil } -func (self *XEth) sign(tx *types.Transaction, from []byte, didUnlock bool) error { - sig, err := self.accountManager.Sign(accounts.Account{Address: from}, tx.Hash()) +func (self *XEth) sign(tx *types.Transaction, from common.Address, didUnlock bool) error { + sig, err := self.accountManager.Sign(accounts.Account{Address: from.Bytes()}, tx.Hash().Bytes()) if err == accounts.ErrLocked { if didUnlock { return fmt.Errorf("sender account still locked after successful unlock") } - if !self.frontend.UnlockAccount(from) { + if !self.frontend.UnlockAccount(from.Bytes()) { return fmt.Errorf("could not unlock sender account") } // retry signing, the account should now be unlocked. @@ -397,17 +393,17 @@ func (self *XEth) sign(tx *types.Transaction, from []byte, didUnlock bool) error // callmsg is the message type used for call transations. type callmsg struct { from *state.StateObject - to []byte + to common.Address gas, gasPrice *big.Int value *big.Int data []byte } // accessor boilerplate to implement core.Message -func (m callmsg) From() []byte { return m.from.Address() } -func (m callmsg) Nonce() uint64 { return m.from.Nonce() } -func (m callmsg) To() []byte { return m.to } -func (m callmsg) GasPrice() *big.Int { return m.gasPrice } -func (m callmsg) Gas() *big.Int { return m.gas } -func (m callmsg) Value() *big.Int { return m.value } -func (m callmsg) Data() []byte { return m.data } +func (m callmsg) From() (common.Address, error) { return m.from.Address(), nil } +func (m callmsg) Nonce() uint64 { return m.from.Nonce() } +func (m callmsg) To() *common.Address { return &m.to } +func (m callmsg) GasPrice() *big.Int { return m.gasPrice } +func (m callmsg) Gas() *big.Int { return m.gas } +func (m callmsg) Value() *big.Int { return m.value } +func (m callmsg) Data() []byte { return m.data } |