From 740081e2f7f3f76f7522753fd3c714e57ea22f3f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 21 Aug 2014 21:06:42 +0200 Subject: [PATCH 01/58] Storage at changed to return bytes --- README.md | 2 +- ethpipe/js_pipe.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ae624d84a..a80ed34b0 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 0.6.4". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 0.6.5". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go index b32e94a10..eeece5179 100644 --- a/ethpipe/js_pipe.go +++ b/ethpipe/js_pipe.go @@ -99,7 +99,8 @@ func (self *JSPipe) NumberToHuman(balance string) string { func (self *JSPipe) StorageAt(addr, storageAddr string) string { storage := self.World().SafeGet(ethutil.Hex2Bytes(addr)).Storage(ethutil.Hex2Bytes(storageAddr)) - return storage.BigInt().String() + + return ethutil.Bytes2Hex(storage.Bytes()) } func (self *JSPipe) TxCountAt(address string) int { From 93008e279d947e872099c8029b54f7431178bb29 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 22 Aug 2014 10:58:14 +0200 Subject: [PATCH 02/58] Removed old chain code --- ethchain/block_chain.go | 155 ----------------------------------- ethchain/state_transition.go | 2 +- peer.go | 57 +------------ 3 files changed, 5 insertions(+), 209 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 3445bbb87..3b2914a37 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -2,12 +2,10 @@ package ethchain import ( "bytes" - "math" "math/big" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" - "github.com/ethereum/eth-go/ethwire" ) var chainlogger = ethlog.NewLogger("CHAIN") @@ -110,99 +108,6 @@ func (bc *BlockChain) CalculateBlockTD(block *Block) *big.Int { return blockDiff } -func (bc *BlockChain) FindCanonicalChainFromMsg(msg *ethwire.Msg, commonBlockHash []byte) bool { - var blocks []*Block - for i := 0; i < (msg.Data.Len() - 1); i++ { - block := NewBlockFromRlpValue(msg.Data.Get(i)) - blocks = append(blocks, block) - } - return bc.FindCanonicalChain(blocks, commonBlockHash) -} - -// Is tasked by finding the CanonicalChain and resetting the chain if we are not the Conical one -// Return true if we are the using the canonical chain false if not -func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte) bool { - // 1. Calculate TD of the current chain - // 2. Calculate TD of the new chain - // Reset state to the correct one - - chainDifficulty := new(big.Int) - - // Calculate the entire chain until the block we both have - // Start with the newest block we got, all the way back to the common block we both know - for _, block := range blocks { - if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - chainlogger.Infoln("We have found the common parent block, breaking") - break - } - chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) - } - - chainlogger.Infoln("Incoming chain difficulty:", chainDifficulty) - - curChainDifficulty := new(big.Int) - block := bc.CurrentBlock - for i := 0; block != nil; block = bc.GetBlock(block.PrevHash) { - i++ - if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - chainlogger.Infoln("Found the common parent block") - break - } - anOtherBlock := bc.GetBlock(block.PrevHash) - if anOtherBlock == nil { - // We do not want to count the genesis block for difficulty since that's not being sent - chainlogger.Infoln("Found genesis block. Stop") - break - } - curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) - } - - chainlogger.Infoln("Current chain difficulty:", curChainDifficulty) - if chainDifficulty.Cmp(curChainDifficulty) == 1 { - chainlogger.Infof("Resetting to block %x. Changing chain.") - bc.ResetTillBlockHash(commonBlockHash) - return false - } else { - chainlogger.Infoln("Current chain is longest chain. Ignoring incoming chain.") - return true - } -} -func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { - lastBlock := bc.CurrentBlock - var returnTo *Block - // Reset to Genesis if that's all the origin there is. - if bytes.Compare(hash, bc.genesisBlock.Hash()) == 0 { - returnTo = bc.genesisBlock - bc.CurrentBlock = bc.genesisBlock - bc.LastBlockHash = bc.genesisBlock.Hash() - bc.LastBlockNumber = 1 - } else { - returnTo = bc.GetBlock(hash) - bc.CurrentBlock = returnTo - bc.LastBlockHash = returnTo.Hash() - bc.LastBlockNumber = returnTo.Number.Uint64() - } - - // Manually reset the last sync block - err := ethutil.Config.Db.Delete(lastBlock.Hash()) - if err != nil { - return err - } - - var block *Block - for ; block != nil; block = bc.GetBlock(block.PrevHash) { - if bytes.Compare(block.Hash(), hash) == 0 { - chainlogger.Infoln("We have arrived at the the common parent block, breaking") - break - } - err = ethutil.Config.Db.Delete(block.Hash()) - if err != nil { - return err - } - } - chainlogger.Infoln("Split chain deleted and reverted to common parent block.") - return nil -} func (bc *BlockChain) GenesisBlock() *Block { return bc.genesisBlock @@ -228,66 +133,6 @@ func (self *BlockChain) GetChainHashesFromHash(hash []byte, max uint64) (chain [ return } -// Get chain return blocks from hash up to max in RLP format -func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { - var chain []interface{} - // Get the current hash to start with - currentHash := bc.CurrentBlock.Hash() - // Get the last number on the block chain - lastNumber := bc.CurrentBlock.Number.Uint64() - // Get the parents number - parentNumber := bc.GetBlock(hash).Number.Uint64() - // Get the min amount. We might not have max amount of blocks - count := uint64(math.Min(float64(lastNumber-parentNumber), float64(max))) - startNumber := parentNumber + count - - num := lastNumber - for num > startNumber { - num-- - - block := bc.GetBlock(currentHash) - if block == nil { - break - } - currentHash = block.PrevHash - } - - for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ { - // Get the block of the chain - block := bc.GetBlock(currentHash) - if block == nil { - chainlogger.Debugf("Unexpected error during GetChainFromHash: Unable to find %x\n", currentHash) - break - } - - currentHash = block.PrevHash - - chain = append(chain, block.Value().Val) - - num-- - } - - return chain -} - -func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block { - genHash := bc.genesisBlock.Hash() - - block := bc.GetBlock(hash) - var blocks []*Block - - for i := 0; i < amount && block != nil; block = bc.GetBlock(block.PrevHash) { - blocks = append([]*Block{block}, blocks...) - - if bytes.Compare(genHash, block.Hash()) == 0 { - break - } - i++ - } - - return blocks -} - func AddTestNetFunds(block *Block) { for _, addr := range []string{ "51ba59315b3a95761d0863b05ccc7a7f54703d99", diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 9fbc160a5..80f9fda5e 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -140,7 +140,7 @@ func (self *StateTransition) preCheck() (err error) { } func (self *StateTransition) TransitionState() (err error) { - statelogger.Infof("(~) %x\n", self.tx.Hash()) + statelogger.Debugf("(~) %x\n", self.tx.Hash()) /* defer func() { diff --git a/peer.go b/peer.go index ab17466e1..79a58d28e 100644 --- a/peer.go +++ b/peer.go @@ -474,7 +474,7 @@ func (p *Peer) HandleInbound() { for it.Next() { block := ethchain.NewBlockFromRlpValue(it.Value()) - blockPool.SetBlock(block) + blockPool.SetBlock(block, p) p.lastBlockReceived = time.Now() } @@ -507,6 +507,7 @@ func (self *Peer) FetchHashes() { if self.td.Cmp(blockPool.td) >= 0 { peerlogger.Debugf("Requesting hashes from %x\n", self.lastReceivedHash) + blockPool.td = self.td if !blockPool.HasLatestHash() { self.QueueMessage(ethwire.NewMessage(ethwire.MsgGetBlockHashesTy, []interface{}{self.lastReceivedHash, uint32(200)})) @@ -625,7 +626,6 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { usedPub := 0 // This peer is already added to the peerlist so we expect to find a double pubkey at least once - eachPeer(p.ethereum.Peers(), func(peer *Peer, e *list.Element) { if bytes.Compare(p.pubkey, peer.pubkey) == 0 { usedPub++ @@ -644,7 +644,6 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { return } - // [PROTOCOL_VERSION, NETWORK_ID, CLIENT_ID, CAPS, PORT, PUBKEY] p.versionKnown = true // If this is an inbound connection send an ack back @@ -680,15 +679,8 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { ethlogger.Infof("Added peer (%s) %d / %d (TD = %v ~ %x)\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers, p.td, p.bestHash) - /* - // Catch up with the connected peer - if !p.ethereum.IsUpToDate() { - peerlogger.Debugln("Already syncing up with a peer; sleeping") - time.Sleep(10 * time.Second) - } - */ - //p.SyncWithPeerToLastKnown() - + // Compare the total TD with the blockchain TD. If remote is higher + // fetch hashes from highest TD node. if p.td.Cmp(p.ethereum.BlockChain().TD) > 0 { p.ethereum.blockPool.AddHash(p.lastReceivedHash) p.FetchHashes() @@ -714,47 +706,6 @@ func (p *Peer) String() string { return fmt.Sprintf("[%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.version, p.caps) } -func (p *Peer) SyncWithPeerToLastKnown() { - p.catchingUp = false - p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) -} - -func (p *Peer) FindCommonParentBlock() { - if p.catchingUp { - return - } - - p.catchingUp = true - if p.blocksRequested == 0 { - p.blocksRequested = 20 - } - blocks := p.ethereum.BlockChain().GetChain(p.ethereum.BlockChain().CurrentBlock.Hash(), p.blocksRequested) - - var hashes []interface{} - for _, block := range blocks { - hashes = append(hashes, block.Hash()) - } - - msgInfo := append(hashes, uint64(len(hashes))) - - peerlogger.DebugDetailf("Asking for block from %x (%d total) from %s\n", p.ethereum.BlockChain().CurrentBlock.Hash(), len(hashes), p.conn.RemoteAddr().String()) - - msg := ethwire.NewMessage(ethwire.MsgGetChainTy, msgInfo) - p.QueueMessage(msg) -} -func (p *Peer) CatchupWithPeer(blockHash []byte) { - if !p.catchingUp { - // Make sure nobody else is catching up when you want to do this - p.catchingUp = true - msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(100)}) - p.QueueMessage(msg) - - peerlogger.DebugDetailf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr()) - - msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{}) - p.QueueMessage(msg) - } -} func (p *Peer) RlpData() []interface{} { return []interface{}{p.host, p.port, p.pubkey} From 42d43147cac99469eb3f445342fe9e1ebeb5222e Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 22 Aug 2014 10:58:49 +0200 Subject: [PATCH 03/58] Changed log statements --- ethstate/state.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethstate/state.go b/ethstate/state.go index cf060e795..2f7f00a32 100644 --- a/ethstate/state.go +++ b/ethstate/state.go @@ -103,7 +103,7 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { func (self *State) NewStateObject(addr []byte) *StateObject { addr = ethutil.Address(addr) - statelogger.Infof("(+) %x\n", addr) + statelogger.Debugf("(+) %x\n", addr) stateObject := NewStateObject(addr) self.stateObjects[string(addr)] = stateObject From a9f9a594160405737657083476535f3e48df1558 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 22 Aug 2014 10:58:57 +0200 Subject: [PATCH 04/58] Extra checks --- block_pool.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/block_pool.go b/block_pool.go index 3225bdff2..2be2bc787 100644 --- a/block_pool.go +++ b/block_pool.go @@ -49,11 +49,11 @@ func (self *BlockPool) AddHash(hash []byte) { } } -func (self *BlockPool) SetBlock(b *ethchain.Block) { +func (self *BlockPool) SetBlock(b *ethchain.Block, peer *Peer) { hash := string(b.Hash()) - if self.pool[string(hash)] == nil { - self.pool[hash] = &block{nil, nil} + if self.pool[hash] == nil { + self.pool[hash] = &block{peer, nil} } self.pool[hash].block = b @@ -65,6 +65,10 @@ func (self *BlockPool) CheckLinkAndProcess(f func(block *ethchain.Block)) bool { if self.IsLinked() { for i, hash := range self.hashPool { + if self.pool[string(hash)] == nil { + continue + } + block := self.pool[string(hash)].block if block != nil { f(block) @@ -84,7 +88,7 @@ func (self *BlockPool) CheckLinkAndProcess(f func(block *ethchain.Block)) bool { } func (self *BlockPool) IsLinked() bool { - if len(self.hashPool) == 0 { + if len(self.hashPool) == 0 || self.pool[string(self.hashPool[0])] == nil { return false } @@ -104,7 +108,7 @@ func (self *BlockPool) Take(amount int, peer *Peer) (hashes [][]byte) { j := 0 for i := 0; i < len(self.hashPool) && j < num; i++ { hash := string(self.hashPool[i]) - if self.pool[hash].peer == nil || self.pool[hash].peer == peer { + if self.pool[hash] != nil && (self.pool[hash].peer == nil || self.pool[hash].peer == peer) && self.pool[hash].block == nil { self.pool[hash].peer = peer hashes = append(hashes, self.hashPool[i]) From 836ed9d6b70e3ae928624f9ed81ed206a66b85b8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 22 Aug 2014 11:34:59 +0200 Subject: [PATCH 05/58] Write Protocol version to the db so we can perform sanity checks --- ethereum.go | 12 +++++++++++- ethutil/value.go | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ethereum.go b/ethereum.go index 1e1891589..4c5e13b6d 100644 --- a/ethereum.go +++ b/ethereum.go @@ -90,7 +90,6 @@ type Ethereum struct { } func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager *ethcrypto.KeyManager, caps Caps, usePnp bool) (*Ethereum, error) { - var err error var nat NAT @@ -101,6 +100,8 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager } } + bootstrapDb(db) + ethutil.Config.Db = db nonce, _ := ethutil.RandomUint64() @@ -534,3 +535,12 @@ out: } } } + +func bootstrapDb(db ethutil.Database) { + d, _ := db.Get([]byte("ProtocolVersion")) + protov := ethutil.NewValue(d).Uint() + + if protov == 0 { + db.Put([]byte("ProtocolVersion"), ethutil.NewValue(ProtocolVersion).Bytes()) + } +} diff --git a/ethutil/value.go b/ethutil/value.go index 608d332ba..b336345ca 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -141,6 +141,8 @@ func (val *Value) Bytes() []byte { return []byte(s) } else if s, ok := val.Val.(*big.Int); ok { return s.Bytes() + } else { + return big.NewInt(val.Int()).Bytes() } return []byte{} From be9bfb5536c7410bdd9cb3fbd13fb622bfc00a57 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 22 Aug 2014 14:52:20 +0200 Subject: [PATCH 06/58] Minor improvement catching up * When catching up check linked up the chain of hashes --- block_pool.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/block_pool.go b/block_pool.go index 2be2bc787..e3f0f6ff0 100644 --- a/block_pool.go +++ b/block_pool.go @@ -1,6 +1,7 @@ package eth import ( + "fmt" "math" "math/big" "sync" @@ -51,6 +52,7 @@ func (self *BlockPool) AddHash(hash []byte) { func (self *BlockPool) SetBlock(b *ethchain.Block, peer *Peer) { hash := string(b.Hash()) + fmt.Printf("::SetBlock %x\n", hash) if self.pool[hash] == nil { self.pool[hash] = &block{peer, nil} @@ -88,13 +90,19 @@ func (self *BlockPool) CheckLinkAndProcess(f func(block *ethchain.Block)) bool { } func (self *BlockPool) IsLinked() bool { - if len(self.hashPool) == 0 || self.pool[string(self.hashPool[0])] == nil { + if len(self.hashPool) == 0 { return false } - block := self.pool[string(self.hashPool[0])].block - if block != nil { - return self.eth.BlockChain().HasBlock(block.PrevHash) + for i := 0; i < len(self.hashPool); i++ { + item := self.pool[string(self.hashPool[i])] + if item != nil && item.block != nil { + if self.eth.BlockChain().HasBlock(item.block.PrevHash) { + self.hashPool = self.hashPool[i:] + + return true + } + } } return false From 56103f07517fe32522e510213c02ea982dfcef42 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 22 Aug 2014 17:10:18 +0200 Subject: [PATCH 07/58] Log --- block_pool.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/block_pool.go b/block_pool.go index e3f0f6ff0..25627eb5c 100644 --- a/block_pool.go +++ b/block_pool.go @@ -1,7 +1,6 @@ package eth import ( - "fmt" "math" "math/big" "sync" @@ -52,7 +51,6 @@ func (self *BlockPool) AddHash(hash []byte) { func (self *BlockPool) SetBlock(b *ethchain.Block, peer *Peer) { hash := string(b.Hash()) - fmt.Printf("::SetBlock %x\n", hash) if self.pool[hash] == nil { self.pool[hash] = &block{peer, nil} From d9d4f63cd4e3c9388ea8425e9d41f63af030c77c Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 22 Aug 2014 17:57:33 +0200 Subject: [PATCH 08/58] Don't add ... --- ethvm/vm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethvm/vm.go b/ethvm/vm.go index 873a80c44..347ebcfe6 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -631,12 +631,12 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { require(1) stack.Pop() case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: - n := int(op - DUP1 + 1) + n := int(op - DUP1) stack.Dupn(n) self.Printf(" => [%d] 0x%x", n, stack.Peek().Bytes()) case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: - n := int(op - SWAP1 + 1) + n := int(op - SWAP1) x, y := stack.Swapn(n) self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes()) From 962255b373a0c8d7c2459cb25aaaa0dc4e492ecf Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 23 Aug 2014 11:00:33 +0200 Subject: [PATCH 09/58] Removed old code --- ethchain/block_chain.go | 2 +- ethdb/database.go | 13 +++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 3b2914a37..74f47aa90 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -176,7 +176,7 @@ func (bc *BlockChain) setLastBlock() { } func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { - ethutil.Config.Db.Put([]byte("LastKnownTotalDifficulty"), td.Bytes()) + ethutil.Config.Db.Put([]byte("LTD"), td.Bytes()) bc.TD = td } diff --git a/ethdb/database.go b/ethdb/database.go index 09e9d8c7d..e4b069930 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -2,9 +2,10 @@ package ethdb import ( "fmt" + "path" + "github.com/ethereum/eth-go/ethutil" "github.com/syndtr/goleveldb/leveldb" - "path" ) type LDBDatabase struct { @@ -45,7 +46,7 @@ func (db *LDBDatabase) Db() *leveldb.DB { } func (db *LDBDatabase) LastKnownTD() []byte { - data, _ := db.db.Get([]byte("LastKnownTotalDifficulty"), nil) + data, _ := db.db.Get([]byte("LTD"), nil) if len(data) == 0 { data = []byte{0x0} @@ -54,14 +55,6 @@ func (db *LDBDatabase) LastKnownTD() []byte { return data } -/* -func (db *LDBDatabase) GetKeys() []*ethutil.Key { - data, _ := db.Get([]byte("KeyRing")) - - return []*ethutil.Key{ethutil.NewKeyFromBytes(data)} -} -*/ - func (db *LDBDatabase) Close() { // Close the leveldb database db.db.Close() From fcc6f183a4122d161b0a438984f200a3b3c0dcc8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 23 Aug 2014 19:00:52 +0200 Subject: [PATCH 10/58] Changed level --- ethreact/reactor.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ethreact/reactor.go b/ethreact/reactor.go index 7fe2356db..2edcbbbd9 100644 --- a/ethreact/reactor.go +++ b/ethreact/reactor.go @@ -1,8 +1,9 @@ package ethreact import ( - "github.com/ethereum/eth-go/ethlog" "sync" + + "github.com/ethereum/eth-go/ethlog" ) var logger = ethlog.NewLogger("REACTOR") @@ -32,7 +33,7 @@ func (e *EventHandler) Post(event Event) { select { case ch <- event: default: - logger.Warnf("subscribing channel %d to event %s blocked. skipping\n", i, event.Name) + logger.Debugf("subscribing channel %d to event %s blocked. skipping\n", i, event.Name) } } } From cdbc3ecc2a738a4b8803c40dfc510fd099ce8584 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 24 Aug 2014 00:16:32 +0200 Subject: [PATCH 11/58] Serpent! :-) --- ethutil/script.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ethutil/script.go b/ethutil/script.go index b796e7c1e..bd087e7e0 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -2,9 +2,11 @@ package ethutil import ( "fmt" + "strings" + "github.com/obscuren/mutan" "github.com/obscuren/mutan/backends" - "strings" + "github.com/obscuren/serpent-go" ) // General compile function @@ -14,15 +16,13 @@ func Compile(script string, silent bool) (ret []byte, err error) { if len(line) > 1 && line[0:2] == "#!" { switch line { - /* - case "#!serpent": - byteCode, err := serpent.Compile(script) - if err != nil { - return nil, err - } + case "#!serpent": + byteCode, err := serpent.Compile(script) + if err != nil { + return nil, err + } - return byteCode, nil - */ + return byteCode, nil } } else { From 3f904bf3acb5779f68834ebca95825ea1990f85b Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 25 Aug 2014 11:29:42 +0200 Subject: [PATCH 12/58] Implemented POST --- ethchain/state_transition.go | 9 ++ ethstate/state_object.go | 6 + ethvm/closure.go | 1 + ethvm/types.go | 2 + ethvm/vm.go | 277 +++++++++++++++++++++++++---------- natpmp.go | 1 - 6 files changed, 217 insertions(+), 79 deletions(-) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 80f9fda5e..1c7eae675 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -278,6 +278,15 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context ret, _, err = callerClosure.Call(vm, self.tx.Data) + if err == nil { + // Execute POSTs + for e := vm.Queue().Front(); e != nil; e = e.Next() { + msg := e.Value.(*ethvm.Message) + + msg.Exec(transactor) + } + } + return } diff --git a/ethstate/state_object.go b/ethstate/state_object.go index 67d09edd8..bf4e92583 100644 --- a/ethstate/state_object.go +++ b/ethstate/state_object.go @@ -245,6 +245,7 @@ func (self *StateObject) Copy() *StateObject { stateObject.InitCode = ethutil.CopyBytes(self.InitCode) stateObject.storage = self.storage.Copy() stateObject.gasPool.Set(self.gasPool) + stateObject.remove = self.remove return stateObject } @@ -271,6 +272,11 @@ func (c *StateObject) Init() Code { return c.InitCode } +// To satisfy ClosureRef +func (self *StateObject) Object() *StateObject { + return self +} + // Debug stuff func (self *StateObject) CreateOutputForDiff() { fmt.Printf("%x %x %x %x\n", self.Address(), self.State.Root(), self.Balance.Bytes(), self.Nonce) diff --git a/ethvm/closure.go b/ethvm/closure.go index 54bfd05f4..c047a83b7 100644 --- a/ethvm/closure.go +++ b/ethvm/closure.go @@ -12,6 +12,7 @@ import ( type ClosureRef interface { ReturnGas(*big.Int, *big.Int) Address() []byte + Object() *ethstate.StateObject GetStorage(*big.Int) *ethutil.Value SetStorage(*big.Int, *ethutil.Value) } diff --git a/ethvm/types.go b/ethvm/types.go index 36ba395d6..bb6735993 100644 --- a/ethvm/types.go +++ b/ethvm/types.go @@ -145,6 +145,7 @@ const ( CREATE = 0xf0 CALL = 0xf1 RETURN = 0xf2 + POST = 0xf3 // 0x70 range - other LOG = 0xfe // XXX Unofficial @@ -438,6 +439,7 @@ var OpCodes = map[string]byte{ "CREATE": 0xf0, "CALL": 0xf1, "RETURN": 0xf2, + "POST": 0xf3, // 0x70 range - other "LOG": 0xfe, diff --git a/ethvm/vm.go b/ethvm/vm.go index 347ebcfe6..924a861ca 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -1,6 +1,7 @@ package ethvm import ( + "container/list" "fmt" "math" "math/big" @@ -18,11 +19,6 @@ type Debugger interface { } type Vm struct { - // Stack for processing contracts - stack *Stack - // non-persistent key/value memory storage - mem map[string]*big.Int - env Environment Verbose bool @@ -40,6 +36,8 @@ type Vm struct { Fn string Recoverable bool + + queue *list.List } type Environment interface { @@ -66,7 +64,7 @@ func New(env Environment) *Vm { lt = LogTyDiff } - return &Vm{env: env, logTy: lt, Recoverable: true} + return &Vm{env: env, logTy: lt, Recoverable: true, queue: list.New()} } func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { @@ -215,6 +213,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64() } + // BUG This will break on overflows. https://github.com/ethereum/eth-go/issues/47 newMemSize = (newMemSize + 31) / 32 * 32 if newMemSize > uint64(mem.Len()) { m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32 @@ -711,6 +710,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { err error value = stack.Pop() size, offset = stack.Popn() + input = mem.Get(offset.Int64(), size.Int64()) + gas = new(big.Int).Set(closure.Gas) // Snapshot the current stack so we are able to // revert back to it later. @@ -726,37 +727,10 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" (*) %x", addr).Endl() - msg := self.env.State().Manifest().AddMessage(ðstate.Message{ - To: addr, From: closure.Address(), - Origin: self.env.Origin(), - Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), - Value: value, - }) - - // Create a new contract - contract := self.env.State().NewStateObject(addr) - if contract.Balance.Cmp(value) >= 0 { - closure.object.SubAmount(value) - contract.AddAmount(value) - - // Set the init script - initCode := mem.Get(offset.Int64(), size.Int64()) - msg.Input = initCode - - // Transfer all remaining gas to the new - // contract so it may run the init script - gas := new(big.Int).Set(closure.Gas) - closure.UseGas(closure.Gas) - - // Create the closure - c := NewClosure(msg, closure, contract, initCode, gas, closure.Price) - // Call the closure and set the return value as - // main script. - contract.Code, _, err = c.Call(self, nil) - } else { - err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance) - } + closure.UseGas(closure.Gas) + msg := NewMessage(self, addr, input, gas, closure.Price, value) + ret, err := msg.Exec(closure) if err != nil { stack.Push(ethutil.BigFalse) @@ -765,10 +739,55 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf("CREATE err %v", err) } else { - stack.Push(ethutil.BigD(addr)) + msg.object.Code = ret - msg.Output = contract.Code + stack.Push(ethutil.BigD(addr)) } + /* + msg := self.env.State().Manifest().AddMessage(ðstate.Message{ + To: addr, From: closure.Address(), + Origin: self.env.Origin(), + Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), + Value: value, + }) + + // Create a new contract + contract := self.env.State().NewStateObject(addr) + if contract.Balance.Cmp(value) >= 0 { + closure.object.SubAmount(value) + contract.AddAmount(value) + + // Set the init script + initCode := mem.Get(offset.Int64(), size.Int64()) + msg.Input = initCode + + // Transfer all remaining gas to the new + // contract so it may run the init script + gas := new(big.Int).Set(closure.Gas) + closure.UseGas(closure.Gas) + + // Create the closure + c := NewClosure(msg, closure, contract, initCode, gas, closure.Price) + // Call the closure and set the return value as + // main script. + contract.Code, _, err = c.Call(self, nil) + } else { + err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance) + } + + if err != nil { + stack.Push(ethutil.BigFalse) + + // Revert the state as it was before. + self.env.State().Set(snapshot) + + self.Printf("CREATE err %v", err) + } else { + stack.Push(ethutil.BigD(addr)) + + msg.Output = contract.Code + } + */ self.Endl() // Debug hook @@ -791,51 +810,88 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) - msg := self.env.State().Manifest().AddMessage(ðstate.Message{ - To: addr.Bytes(), From: closure.Address(), - Input: args, - Origin: self.env.Origin(), - Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), - Value: value, - }) - - if closure.object.Balance.Cmp(value) < 0 { - vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance) - - closure.ReturnGas(gas, nil) + snapshot := self.env.State().Copy() + msg := NewMessage(self, addr.Bytes(), args, gas, closure.Price, value) + ret, err := msg.Exec(closure) + if err != nil { stack.Push(ethutil.BigFalse) + + self.env.State().Set(snapshot) } else { - snapshot := self.env.State().Copy() + stack.Push(ethutil.BigTrue) - stateObject := self.env.State().GetOrNewStateObject(addr.Bytes()) - - closure.object.SubAmount(value) - stateObject.AddAmount(value) - - // Create a new callable closure - c := NewClosure(msg, closure, stateObject, stateObject.Code, gas, closure.Price) - // Executer the closure and get the return value (if any) - ret, _, err := c.Call(self, args) - if err != nil { - stack.Push(ethutil.BigFalse) - - vmlogger.Debugf("Closure execution failed. %v\n", err) - - self.env.State().Set(snapshot) - } else { - stack.Push(ethutil.BigTrue) - - mem.Set(retOffset.Int64(), retSize.Int64(), ret) - } - - msg.Output = ret - - // Debug hook - if self.Dbg != nil { - self.Dbg.SetCode(closure.Code) - } + mem.Set(retOffset.Int64(), retSize.Int64(), ret) } + + // Debug hook + if self.Dbg != nil { + self.Dbg.SetCode(closure.Code) + } + + /* + msg := self.env.State().Manifest().AddMessage(ðstate.Message{ + To: addr.Bytes(), From: closure.Address(), + Input: args, + Origin: self.env.Origin(), + Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), + Value: value, + }) + + if closure.object.Balance.Cmp(value) < 0 { + vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance) + + closure.ReturnGas(gas, nil) + + stack.Push(ethutil.BigFalse) + } else { + snapshot := self.env.State().Copy() + + stateObject := self.env.State().GetOrNewStateObject(addr.Bytes()) + + closure.object.SubAmount(value) + stateObject.AddAmount(value) + + // Create a new callable closure + c := NewClosure(msg, closure, stateObject, stateObject.Code, gas, closure.Price) + // Executer the closure and get the return value (if any) + ret, _, err := c.Call(self, args) + if err != nil { + stack.Push(ethutil.BigFalse) + + vmlogger.Debugf("Closure execution failed. %v\n", err) + + self.env.State().Set(snapshot) + } else { + stack.Push(ethutil.BigTrue) + + mem.Set(retOffset.Int64(), retSize.Int64(), ret) + } + + msg.Output = ret + + // Debug hook + if self.Dbg != nil { + self.Dbg.SetCode(closure.Code) + } + } + */ + case POST: + require(6) + + self.Endl() + + gas := stack.Pop() + // Pop gas and value of the stack. + value, addr := stack.Popn() + // Pop input size and offset + inSize, inOffset := stack.Popn() + // Get the arguments from the memory + args := mem.Get(inOffset.Int64(), inSize.Int64()) + + msg := NewMessage(self, addr.Bytes(), args, gas, closure.Price, value) + + msg.Postpone() case RETURN: require(2) size, offset := stack.Popn() @@ -887,6 +943,10 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } } +func (self *Vm) Queue() *list.List { + return self.queue +} + func (self *Vm) Printf(format string, v ...interface{}) *Vm { if self.Verbose && self.logTy == LogTyPretty { self.logStr += fmt.Sprintf(format, v...) @@ -918,3 +978,64 @@ func ensure256(x *big.Int) { x.SetInt64(0) } } + +type Message struct { + vm *Vm + closure *Closure + address, input []byte + gas, price, value *big.Int + object *ethstate.StateObject +} + +func NewMessage(vm *Vm, address, input []byte, gas, gasPrice, value *big.Int) *Message { + return &Message{vm: vm, address: address, input: input, gas: gas, price: gasPrice, value: value} +} + +func (self *Message) Postpone() { + self.vm.queue.PushBack(self) +} + +func (self *Message) Exec(caller ClosureRef) (ret []byte, err error) { + queue := self.vm.queue + self.vm.queue = list.New() + + defer func() { + if err == nil { + queue.PushBackList(self.vm.queue) + } + + self.vm.queue = queue + }() + + msg := self.vm.env.State().Manifest().AddMessage(ðstate.Message{ + To: self.address, From: caller.Address(), + Input: self.input, + Origin: self.vm.env.Origin(), + Block: self.vm.env.BlockHash(), Timestamp: self.vm.env.Time(), Coinbase: self.vm.env.Coinbase(), Number: self.vm.env.BlockNumber(), + Value: self.value, + }) + + object := caller.Object() + if object.Balance.Cmp(self.value) < 0 { + caller.ReturnGas(self.gas, self.price) + + err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, object.Balance) + } else { + stateObject := self.vm.env.State().GetOrNewStateObject(self.address) + self.object = stateObject + + caller.Object().SubAmount(self.value) + stateObject.AddAmount(self.value) + + // Create a new callable closure + c := NewClosure(msg, caller, object, object.Code, self.gas, self.price) + // Executer the closure and get the return value (if any) + ret, _, err = c.Call(self.vm, self.input) + + msg.Output = ret + + return ret, err + } + + return +} diff --git a/natpmp.go b/natpmp.go index badbaf9eb..489342a4b 100644 --- a/natpmp.go +++ b/natpmp.go @@ -1,7 +1,6 @@ package eth import ( - //natpmp "code.google.com/p/go-nat-pmp" "fmt" "net" From 6afc16399f9624663579ad72950b4ea3b887db57 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 25 Aug 2014 12:53:06 +0200 Subject: [PATCH 13/58] Block size --- ethchain/block.go | 7 ++++++- ethpipe/js_types.go | 3 ++- ethutil/size.go | 15 +++++++++++++++ ethutil/size_test.go | 12 ++++++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 ethutil/size.go create mode 100644 ethutil/size_test.go diff --git a/ethchain/block.go b/ethchain/block.go index 5765abd51..d2d012e55 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -351,7 +351,7 @@ func (block *Block) header() []interface{} { func (block *Block) String() string { return fmt.Sprintf(` - BLOCK(%x): + BLOCK(%x): Size: %v PrevHash: %x UncleSha: %x Coinbase: %x @@ -368,6 +368,7 @@ func (block *Block) String() string { NumTx: %v `, block.Hash(), + block.Size(), block.PrevHash, block.UncleSha, block.Coinbase, @@ -384,3 +385,7 @@ func (block *Block) String() string { len(block.transactions), ) } + +func (self *Block) Size() ethutil.StorageSize { + return ethutil.StorageSize(len(self.RlpEncode())) +} diff --git a/ethpipe/js_types.go b/ethpipe/js_types.go index 0fb3a3876..d9cbef12d 100644 --- a/ethpipe/js_types.go +++ b/ethpipe/js_types.go @@ -14,6 +14,7 @@ import ( // Block interface exposed to QML type JSBlock struct { ref *ethchain.Block + Size string `json:"size"` Number int `json:"number"` Hash string `json:"hash"` Transactions string `json:"transactions"` @@ -40,7 +41,7 @@ func NewJSBlock(block *ethchain.Block) *JSBlock { return nil } - return &JSBlock{ref: block, Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)} + return &JSBlock{ref: block, Size: block.Size().String(), Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)} } func (self *JSBlock) ToString() string { diff --git a/ethutil/size.go b/ethutil/size.go new file mode 100644 index 000000000..b4426465e --- /dev/null +++ b/ethutil/size.go @@ -0,0 +1,15 @@ +package ethutil + +import "fmt" + +type StorageSize float64 + +func (self StorageSize) String() string { + if self > 1000000 { + return fmt.Sprintf("%.2f mB", self/1000000) + } else if self > 1000 { + return fmt.Sprintf("%.2f kB", self/1000) + } else { + return fmt.Sprintf("%.2f B", self) + } +} diff --git a/ethutil/size_test.go b/ethutil/size_test.go new file mode 100644 index 000000000..82aa1c653 --- /dev/null +++ b/ethutil/size_test.go @@ -0,0 +1,12 @@ +package ethutil + +import ( + "fmt" + "testing" +) + +func TestSize(t *testing.T) { + fmt.Println(StorageSize(2381273)) + fmt.Println(StorageSize(2192)) + fmt.Println(StorageSize(12)) +} From 627b7c9fd75c84e0ca3af110b8f64ab5bbda963e Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 7 Sep 2014 10:07:51 +0200 Subject: [PATCH 14/58] Updated to latest sha3 implementation. Fixes #48 --- ethcrypto/crypto.go | 5 +++-- ethcrypto/crypto_test.go | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 ethcrypto/crypto_test.go diff --git a/ethcrypto/crypto.go b/ethcrypto/crypto.go index 19f8c9e55..f5f0f7e68 100644 --- a/ethcrypto/crypto.go +++ b/ethcrypto/crypto.go @@ -1,9 +1,10 @@ package ethcrypto import ( + "crypto/sha256" + "code.google.com/p/go.crypto/ripemd160" "code.google.com/p/go.crypto/sha3" - "crypto/sha256" "github.com/ethereum/eth-go/ethutil" ) @@ -21,7 +22,7 @@ func Ripemd160(data []byte) []byte { } func Sha3Bin(data []byte) []byte { - d := sha3.NewKeccak256() + d := sha3.New256() d.Write(data) return d.Sum(nil) diff --git a/ethcrypto/crypto_test.go b/ethcrypto/crypto_test.go new file mode 100644 index 000000000..8418c9a5a --- /dev/null +++ b/ethcrypto/crypto_test.go @@ -0,0 +1,16 @@ +package ethcrypto + +import ( + "bytes" + "testing" + + "github.com/ethereum/eth-go/ethutil" +) + +func TestSha3(t *testing.T) { + const exp = "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532" + sha3_256 := Sha3Bin([]byte("abc")) + if bytes.Compare(sha3_256, ethutil.Hex2Bytes(exp)) != 0 { + t.Errorf("Sha3_256 failed. Incorrect result %x", sha3_256) + } +} From ff27df78fc5d638b562bae9b4515eb5f5735d45d Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 7 Sep 2014 10:18:54 +0200 Subject: [PATCH 15/58] Added new list type which can embed any slice type --- ethutil/list.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 ethutil/list.go diff --git a/ethutil/list.go b/ethutil/list.go new file mode 100644 index 000000000..18bf04792 --- /dev/null +++ b/ethutil/list.go @@ -0,0 +1,42 @@ +package ethutil + +import "reflect" + +// The list type is an anonymous slice handler which can be used +// for containing any slice type to use in an environment which +// does not support slice types (e.g., JavaScript, QML) +type List struct { + list reflect.Value + Length int +} + +// Initialise a new list. Panics if non-slice type is given. +func NewList(t interface{}) *List { + list := reflect.ValueOf(t) + if list.Kind() != reflect.Slice { + panic("list container initialized with a non-slice type") + } + + return &List{list, list.Len()} +} + +// Get N element from the embedded slice. Returns nil if OOB. +func (self *List) Get(i int) interface{} { + if self.list.Len() > i { + return self.list.Index(i).Interface() + } + + return nil +} + +// Appends value at the end of the slice. Panics when incompatible value +// is given. +func (self *List) Append(v interface{}) { + self.list = reflect.Append(self.list, reflect.ValueOf(v)) + self.Length = self.list.Len() +} + +// Returns the underlying slice as interface. +func (self *List) Interface() interface{} { + return self.list.Interface() +} From adabd71a4ad808faf13f0253ad248bc746308db5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 7 Sep 2014 22:34:24 +0200 Subject: [PATCH 16/58] Changed back to FIPS 180 --- ethcrypto/crypto.go | 21 +++------------------ ethcrypto/crypto_test.go | 1 + 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/ethcrypto/crypto.go b/ethcrypto/crypto.go index f5f0f7e68..1f500f2db 100644 --- a/ethcrypto/crypto.go +++ b/ethcrypto/crypto.go @@ -1,28 +1,13 @@ package ethcrypto import ( - "crypto/sha256" - - "code.google.com/p/go.crypto/ripemd160" - "code.google.com/p/go.crypto/sha3" + //"code.google.com/p/go.crypto/sha3" "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/sha3" ) -func Sha256Bin(data []byte) []byte { - hash := sha256.Sum256(data) - - return hash[:] -} - -func Ripemd160(data []byte) []byte { - ripemd := ripemd160.New() - ripemd.Write(data) - - return ripemd.Sum(nil) -} - func Sha3Bin(data []byte) []byte { - d := sha3.New256() + d := sha3.NewKeccak256() d.Write(data) return d.Sum(nil) diff --git a/ethcrypto/crypto_test.go b/ethcrypto/crypto_test.go index 8418c9a5a..7323e1646 100644 --- a/ethcrypto/crypto_test.go +++ b/ethcrypto/crypto_test.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum/eth-go/ethutil" ) +// FIPS 202 test (reverted back to FIPS 180) func TestSha3(t *testing.T) { const exp = "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532" sha3_256 := Sha3Bin([]byte("abc")) From 250d40bca01ae92ef5db6258b519e5903929f764 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 8 Sep 2014 00:48:39 +0200 Subject: [PATCH 17/58] Reset the transient state when a new block's been found --- ethchain/state_manager.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 08bd22d29..33af259cf 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -237,6 +237,8 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // Add the block to the chain sm.bc.Add(block) + sm.transState = state.Copy() + // Create a bloom bin for this block filter := sm.createBloomFilter(state) // Persist the data From 0b6b6b52fe1518efef4bcfe9e224cf9209dd8e56 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 8 Sep 2014 00:48:59 +0200 Subject: [PATCH 18/58] Contract creation address are empty again --- ethchain/transaction.go | 5 +++-- ethchain/transaction_pool.go | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index e1b48a3d3..e7e8f3a9f 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -13,7 +13,8 @@ import ( var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} func IsContractAddr(addr []byte) bool { - return bytes.Compare(addr, ContractAddr) == 0 + return len(addr) == 0 + //return bytes.Compare(addr, ContractAddr) == 0 } type Transaction struct { @@ -31,7 +32,7 @@ type Transaction struct { } func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { - return &Transaction{Recipient: ContractAddr, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} + return &Transaction{Recipient: nil, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} } func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index b0d62fd91..bd8b27a6d 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -72,8 +72,6 @@ type TxPool struct { func NewTxPool(ethereum EthManager) *TxPool { return &TxPool{ - //server: s, - mutex: sync.Mutex{}, pool: list.New(), queueChan: make(chan *Transaction, txPoolQueueSize), quit: make(chan bool), From a63b74e345e83d08b7a85b0602c5087ca4b06075 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 8 Sep 2014 00:49:25 +0200 Subject: [PATCH 19/58] New OPCODES * EXT- CODECOPY, CODESIZE --- ethvm/types.go | 49 +++++++++++++++++++++++++++++++------------------ ethvm/vm.go | 34 ++++++++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/ethvm/types.go b/ethvm/types.go index bb6735993..9cddd7c33 100644 --- a/ethvm/types.go +++ b/ethvm/types.go @@ -49,6 +49,8 @@ const ( CODESIZE = 0x38 CODECOPY = 0x39 GASPRICE = 0x3a + EXTCODECOPY = 0x3b + EXTCODESIZE = 0x3c // 0x40 range - block operations PREVHASH = 0x40 @@ -142,10 +144,11 @@ const ( SWAP16 = 0x9f // 0xf0 range - closures - CREATE = 0xf0 - CALL = 0xf1 - RETURN = 0xf2 - POST = 0xf3 + CREATE = 0xf0 + CALL = 0xf1 + RETURN = 0xf2 + POST = 0xf3 + CALLSTATELESS = 0xf4 // 0x70 range - other LOG = 0xfe // XXX Unofficial @@ -197,12 +200,14 @@ var opCodeToString = map[OpCode]string{ GASPRICE: "TXGASPRICE", // 0x40 range - block operations - PREVHASH: "PREVHASH", - COINBASE: "COINBASE", - TIMESTAMP: "TIMESTAMP", - NUMBER: "NUMBER", - DIFFICULTY: "DIFFICULTY", - GASLIMIT: "GASLIMIT", + PREVHASH: "PREVHASH", + COINBASE: "COINBASE", + TIMESTAMP: "TIMESTAMP", + NUMBER: "NUMBER", + DIFFICULTY: "DIFFICULTY", + GASLIMIT: "GASLIMIT", + EXTCODESIZE: "EXTCODESIZE", + EXTCODECOPY: "EXTCODECOPY", // 0x50 range - 'storage' and execution POP: "POP", @@ -288,9 +293,11 @@ var opCodeToString = map[OpCode]string{ SWAP16: "SWAP16", // 0xf0 range - CREATE: "CREATE", - CALL: "CALL", - RETURN: "RETURN", + CREATE: "CREATE", + CALL: "CALL", + RETURN: "RETURN", + POST: "POST", + CALLSTATELESS: "CALLSTATELESS", // 0x70 range - other LOG: "LOG", @@ -343,7 +350,12 @@ var OpCodes = map[string]byte{ "CALLVALUE": 0x34, "CALLDATALOAD": 0x35, "CALLDATASIZE": 0x36, - "GASPRICE": 0x38, + "CALLDATACOPY": 0x37, + "CODESIZE": 0x38, + "CODECOPY": 0x39, + "GASPRICE": 0x3a, + "EXTCODECOPY": 0x3b, + "EXTCODESIZE": 0x3c, // 0x40 range - block operations "PREVHASH": 0x40, @@ -436,10 +448,11 @@ var OpCodes = map[string]byte{ "SWAP16": 0x9f, // 0xf0 range - closures - "CREATE": 0xf0, - "CALL": 0xf1, - "RETURN": 0xf2, - "POST": 0xf3, + "CREATE": 0xf0, + "CALL": 0xf1, + "RETURN": 0xf2, + "POST": 0xf3, + "CALLSTATELESS": 0xf4, // 0x70 range - other "LOG": 0xfe, diff --git a/ethvm/vm.go b/ethvm/vm.go index 924a861ca..2acf52f92 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -197,6 +197,10 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { require(3) newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() + case EXTCODECOPY: + require(4) + + newMemSize = stack.data[stack.Len()-1].Uint64() + stack.data[stack.Len()-4].Uint64() case CALL: require(7) gas.Set(GasCall) @@ -550,14 +554,32 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { code := closure.Args[cOff : cOff+l] mem.Set(mOff, l, code) - case CODESIZE: - l := big.NewInt(int64(len(closure.Code))) + case CODESIZE, EXTCODESIZE: + var code []byte + if op == EXTCODECOPY { + addr := stack.Pop().Bytes() + + code = self.env.State().GetCode(addr) + } else { + code = closure.Code + } + + l := big.NewInt(int64(len(code))) stack.Push(l) self.Printf(" => %d", l) - case CODECOPY: + case CODECOPY, EXTCODECOPY: + var code []byte + if op == EXTCODECOPY { + addr := stack.Pop().Bytes() + + code = self.env.State().GetCode(addr) + } else { + code = closure.Code + } + var ( - size = int64(len(closure.Code)) + size = int64(len(code)) mOff = stack.Pop().Int64() cOff = stack.Pop().Int64() l = stack.Pop().Int64() @@ -570,9 +592,9 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { l = 0 } - code := closure.Code[cOff : cOff+l] + codeCopy := code[cOff : cOff+l] - mem.Set(mOff, l, code) + mem.Set(mOff, l, codeCopy) case GASPRICE: stack.Push(closure.Price) From 0fea62ec6d33a83e602c804ee4b5b0a7896fd9c6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 8 Sep 2014 00:49:47 +0200 Subject: [PATCH 20/58] Make use of new list type for transactions instead of json --- ethpipe/js_types.go | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/ethpipe/js_types.go b/ethpipe/js_types.go index d9cbef12d..8d2805f3d 100644 --- a/ethpipe/js_types.go +++ b/ethpipe/js_types.go @@ -1,7 +1,6 @@ package ethpipe import ( - "encoding/json" "strconv" "strings" @@ -13,16 +12,17 @@ import ( // Block interface exposed to QML type JSBlock struct { + //Transactions string `json:"transactions"` ref *ethchain.Block - Size string `json:"size"` - Number int `json:"number"` - Hash string `json:"hash"` - Transactions string `json:"transactions"` - Time int64 `json:"time"` - Coinbase string `json:"coinbase"` - Name string `json:"name"` - GasLimit string `json:"gasLimit"` - GasUsed string `json:"gasUsed"` + Size string `json:"size"` + Number int `json:"number"` + Hash string `json:"hash"` + Transactions *ethutil.List `json:"transactions"` + Time int64 `json:"time"` + Coinbase string `json:"coinbase"` + Name string `json:"name"` + GasLimit string `json:"gasLimit"` + GasUsed string `json:"gasUsed"` } // Creates a new QML Block from a chain block @@ -36,12 +36,16 @@ func NewJSBlock(block *ethchain.Block) *JSBlock { ptxs = append(ptxs, *NewJSTx(tx)) } - txJson, err := json.Marshal(ptxs) - if err != nil { - return nil - } + /* + txJson, err := json.Marshal(ptxs) + if err != nil { + return nil + } + return &JSBlock{ref: block, Size: block.Size().String(), Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)} + */ + list := ethutil.NewList(ptxs) - return &JSBlock{ref: block, Size: block.Size().String(), Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)} + return &JSBlock{ref: block, Size: block.Size().String(), Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: list, Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)} } func (self *JSBlock) ToString() string { From d91357d00ca080c63d81570504e5c45fb15e3841 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 8 Sep 2014 00:50:04 +0200 Subject: [PATCH 21/58] Added GetCode method --- ethstate/state.go | 9 +++++++++ ethstate/state_object.go | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/ethstate/state.go b/ethstate/state.go index 2f7f00a32..42bbf021b 100644 --- a/ethstate/state.go +++ b/ethstate/state.go @@ -49,6 +49,15 @@ func (self *State) GetNonce(addr []byte) uint64 { return 0 } +func (self *State) GetCode(addr []byte) []byte { + stateObject := self.GetStateObject(addr) + if stateObject != nil { + return stateObject.Code + } + + return nil +} + // // Setting, updating & deleting state object methods // diff --git a/ethstate/state_object.go b/ethstate/state_object.go index bf4e92583..6fc0696a8 100644 --- a/ethstate/state_object.go +++ b/ethstate/state_object.go @@ -297,8 +297,12 @@ func (c *StateObject) RlpEncode() []byte { } else { root = "" } + var codeHash []byte + if len(c.Code) > 0 { + codeHash = ethcrypto.Sha3Bin(c.Code) + } - return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, ethcrypto.Sha3Bin(c.Code)}) + return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, codeHash}) } func (c *StateObject) RlpDecode(data []byte) { From 29499900160cc2ee88968b74035f0a5c2d4c5af6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 10 Sep 2014 00:19:20 +0200 Subject: [PATCH 22/58] Added CALLSTATELESS --- ethchain/state_transition.go | 2 +- ethvm/vm.go | 28 +++++++++++++++++++++------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 1c7eae675..c1180a641 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -283,7 +283,7 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context for e := vm.Queue().Front(); e != nil; e = e.Next() { msg := e.Value.(*ethvm.Message) - msg.Exec(transactor) + msg.Exec(msg.Addr(), transactor) } } diff --git a/ethvm/vm.go b/ethvm/vm.go index 2acf52f92..9518540e0 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -201,7 +201,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { require(4) newMemSize = stack.data[stack.Len()-1].Uint64() + stack.data[stack.Len()-4].Uint64() - case CALL: + case CALL, CALLSTATELESS: require(7) gas.Set(GasCall) addStepGasUsage(stack.data[stack.Len()-1]) @@ -752,7 +752,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { closure.UseGas(closure.Gas) msg := NewMessage(self, addr, input, gas, closure.Price, value) - ret, err := msg.Exec(closure) + ret, err := msg.Exec(addr, closure) if err != nil { stack.Push(ethutil.BigFalse) @@ -816,7 +816,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { if self.Dbg != nil { self.Dbg.SetCode(closure.Code) } - case CALL: + case CALL, CALLSTATELESS: require(7) self.Endl() @@ -834,8 +834,15 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { snapshot := self.env.State().Copy() - msg := NewMessage(self, addr.Bytes(), args, gas, closure.Price, value) - ret, err := msg.Exec(closure) + var executeAddr []byte + if op == CALLSTATELESS { + executeAddr = closure.Address() + } else { + executeAddr = addr.Bytes() + } + + msg := NewMessage(self, executeAddr, args, gas, closure.Price, value) + ret, err := msg.Exec(addr.Bytes(), closure) if err != nil { stack.Push(ethutil.BigFalse) @@ -1017,7 +1024,11 @@ func (self *Message) Postpone() { self.vm.queue.PushBack(self) } -func (self *Message) Exec(caller ClosureRef) (ret []byte, err error) { +func (self *Message) Addr() []byte { + return self.address +} + +func (self *Message) Exec(codeAddr []byte, caller ClosureRef) (ret []byte, err error) { queue := self.vm.queue self.vm.queue = list.New() @@ -1049,8 +1060,11 @@ func (self *Message) Exec(caller ClosureRef) (ret []byte, err error) { caller.Object().SubAmount(self.value) stateObject.AddAmount(self.value) + // Retrieve the executing code + code := self.vm.env.State().GetCode(codeAddr) + // Create a new callable closure - c := NewClosure(msg, caller, object, object.Code, self.gas, self.price) + c := NewClosure(msg, caller, object, code, self.gas, self.price) // Executer the closure and get the return value (if any) ret, _, err = c.Call(self.vm, self.input) From 7dacd7eb7818a336b3be99aea834093cf40a1b08 Mon Sep 17 00:00:00 2001 From: Cayman Nava Date: Sat, 6 Sep 2014 13:51:13 -0700 Subject: [PATCH 23/58] add pushtx to api Previously the software assumed use of an internal private key for use in all broadcasted transactions. This addition lets nodes relay pre-signed transactions originating from sources other than the node itself. --- ethpipe/js_pipe.go | 6 ++++++ ethpipe/pipe.go | 9 +++++++++ ethrpc/packages.go | 21 +++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go index eeece5179..47cac2ca2 100644 --- a/ethpipe/js_pipe.go +++ b/ethpipe/js_pipe.go @@ -225,6 +225,12 @@ func (self *JSPipe) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr return NewJSReciept(contractCreation, tx.CreationAddress(), tx.Hash(), keyPair.Address()), nil } +func (self *JSPipe) PushTx(txStr string) (*JSReceipt, error) { + tx := ethchain.NewTransactionFromBytes(ethutil.Hex2Bytes(txStr)) + self.obj.TxPool().QueueTransaction(tx) + return NewJSReciept(tx.CreatesContract(), tx.CreationAddress(), tx.Hash(), tx.Sender()), nil +} + func (self *JSPipe) CompileMutan(code string) string { data, err := self.Pipe.CompileMutan(code) if err != nil { diff --git a/ethpipe/pipe.go b/ethpipe/pipe.go index 800a71139..b7d3be041 100644 --- a/ethpipe/pipe.go +++ b/ethpipe/pipe.go @@ -149,6 +149,15 @@ func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price return tx.Hash(), nil } +func (self *Pipe) PushTx(tx *ethchain.Transaction) ([]byte, error) { + self.obj.TxPool().QueueTransaction(tx) + if tx.Recipient == nil { + logger.Infof("Contract addr %x", tx.CreationAddress()) + return tx.CreationAddress(), nil + } + return tx.Hash(), nil +} + func (self *Pipe) CompileMutan(code string) ([]byte, error) { data, err := ethutil.Compile(code, false) if err != nil { diff --git a/ethrpc/packages.go b/ethrpc/packages.go index f2e57fa49..087167a42 100644 --- a/ethrpc/packages.go +++ b/ethrpc/packages.go @@ -145,6 +145,27 @@ func (p *EthereumApi) Create(args *NewTxArgs, reply *string) error { return nil } +type PushTxArgs struct { + Tx string +} + +func (a *PushTxArgs) requirementsPushTx() error { + if a.Tx == "" { + return NewErrorResponse("PushTx requires a 'tx' as argument") + } + return nil +} + +func (p *EthereumApi) PushTx(args *PushTxArgs, reply *string) error { + err := args.requirementsPushTx() + if err != nil { + return err + } + result, _ := p.pipe.PushTx(args.Tx) + *reply = NewSuccessRes(result) + return nil +} + func (p *EthereumApi) GetKey(args interface{}, reply *string) error { *reply = NewSuccessRes(p.pipe.Key()) return nil From 2f362509b813573f533a5be437c140355ddec7fc Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 10 Sep 2014 11:22:19 +0200 Subject: [PATCH 24/58] New p2p protocol. NOTE: Needs major refactoring. See #50 --- ethwire/messaging.go | 32 +++++------ peer.go | 127 ++++++++++++++++++++++++++++++------------- 2 files changed, 103 insertions(+), 56 deletions(-) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index 7ac0188a1..c93c717a2 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -27,24 +27,20 @@ const ( // Values are given explicitly instead of by iota because these values are // defined by the wire protocol spec; it is easier for humans to ensure // correctness when values are explicit. - MsgHandshakeTy = 0x00 - MsgDiscTy = 0x01 - MsgPingTy = 0x02 - MsgPongTy = 0x03 - MsgGetPeersTy = 0x10 - MsgPeersTy = 0x11 + MsgHandshakeTy = 0x00 + MsgDiscTy = 0x01 + MsgPingTy = 0x02 + MsgPongTy = 0x03 + MsgGetPeersTy = 0x04 + MsgPeersTy = 0x05 + + MsgStatusTy = 0x10 + MsgGetTxsTy = 0x11 MsgTxTy = 0x12 - MsgGetChainTy = 0x14 - MsgNotInChainTy = 0x15 - MsgGetTxsTy = 0x16 - MsgGetBlockHashesTy = 0x17 - MsgBlockHashesTy = 0x18 - MsgGetBlocksTy = 0x19 - MsgBlockTy = 0x13 - - MsgOldBlockTy = 0xbb - - MsgTalkTy = 0xff + MsgGetBlockHashesTy = 0x13 + MsgBlockHashesTy = 0x14 + MsgGetBlocksTy = 0x15 + MsgBlockTy = 0x16 ) var msgTypeToString = map[MsgType]string{ @@ -56,9 +52,7 @@ var msgTypeToString = map[MsgType]string{ MsgPeersTy: "Peers", MsgTxTy: "Transactions", MsgBlockTy: "Blocks", - MsgGetChainTy: "Get chain", MsgGetTxsTy: "Get Txs", - MsgNotInChainTy: "Not in chain", MsgGetBlockHashesTy: "Get block hashes", MsgBlockHashesTy: "Block hashes", MsgGetBlocksTy: "Get blocks", diff --git a/peer.go b/peer.go index 79a58d28e..a7259d712 100644 --- a/peer.go +++ b/peer.go @@ -25,6 +25,8 @@ const ( outputBufferSize = 50 // Current protocol version ProtocolVersion = 28 + // Current P2P version + P2PVersion = 0 // Interval for ping/pong message pingPongTimer = 2 * time.Second ) @@ -122,6 +124,7 @@ type Peer struct { // This flag is used by writeMessage to check if messages are allowed // to be send or not. If no version is known all messages are ignored. versionKnown bool + statusKnown bool // Last received pong message lastPong int64 @@ -271,6 +274,14 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { default: // Anything but ack is allowed return } + } else { + if !p.statusKnown { + switch msg.Type { + case ethwire.MsgStatusTy: // Ok + default: // Anything but ack is allowed + return + } + } } peerlogger.DebugDetailf("(%v) <= %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data) @@ -356,9 +367,9 @@ func (p *Peer) HandleInbound() { // Version message p.handleHandshake(msg) - if p.caps.IsCap(CapPeerDiscTy) { - p.QueueMessage(ethwire.NewMessage(ethwire.MsgGetPeersTy, "")) - } + //if p.caps.IsCap(CapPeerDiscTy) { + p.QueueMessage(ethwire.NewMessage(ethwire.MsgGetPeersTy, "")) + //} case ethwire.MsgDiscTy: p.Stop() @@ -396,6 +407,10 @@ func (p *Peer) HandleInbound() { // Connect to the list of peers p.ethereum.ProcessPeerList(peers) + + case ethwire.MsgStatusTy: + // Handle peer's status msg + p.handleStatus(msg) case ethwire.MsgGetTxsTy: // Get the current transactions of the pool txs := p.ethereum.TxPool().CurrentTransactions() @@ -581,6 +596,7 @@ func (p *Peer) Stop() { p.ethereum.RemovePeer(p) } +/* func (p *Peer) pushHandshake() error { pubkey := p.ethereum.KeyManager().PublicKey() msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ @@ -592,6 +608,7 @@ func (p *Peer) pushHandshake() error { return nil } +*/ func (p *Peer) peersMessage() *ethwire.Msg { outPeers := make([]interface{}, len(p.ethereum.InOutPeers())) @@ -612,13 +629,72 @@ func (p *Peer) pushPeers() { p.QueueMessage(p.peersMessage()) } +func (p *Peer) pushHandshake() error { + pubkey := p.ethereum.KeyManager().PublicKey() + msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ + uint32(0), []byte(p.version), []string{"eth"}, p.port, pubkey[1:], + }) + + p.QueueMessage(msg) + + return nil +} + +func (self *Peer) pushStatus() { + const netVersion = 0 + msg := ethwire.NewMessage(ethwire.MsgStatusTy, []interface{}{ + uint32(ProtocolVersion), + netVersion, + self.ethereum.BlockChain().TD.Uint64(), + self.ethereum.BlockChain().CurrentBlock.Hash(), + self.ethereum.BlockChain().Genesis().Hash(), + }) + + self.QueueMessage(msg) +} + +func (self *Peer) handleStatus(msg *ethwire.Msg) { + c := msg.Data + // Set the peer's caps + //p.caps = Caps(c.Get(3).Byte()) + + // Get the td and last hash + self.td = c.Get(6).BigInt() + self.bestHash = c.Get(7).Bytes() + self.lastReceivedHash = self.bestHash + + // Compare the total TD with the blockchain TD. If remote is higher + // fetch hashes from highest TD node. + if self.td.Cmp(self.ethereum.BlockChain().TD) > 0 { + self.ethereum.blockPool.AddHash(self.lastReceivedHash) + self.FetchHashes() + } + + ethlogger.Infof("Peer is [ETH] capable. (TD = %v ~ %x", self.td, self.bestHash) +} + func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data - // Set pubkey - p.pubkey = c.Get(5).Bytes() + var ( + p2pVersion = c.Get(0).Uint() + clientId = c.Get(1).Str() + caps = c.Get(2).Raw() + port = c.Get(3).Uint() + pub = c.Get(4).Bytes() + ) - if p.pubkey == nil { + fmt.Println("PEER CAPS", caps) + + // Check correctness of p2p protocol version + if p2pVersion != P2PVersion { + peerlogger.Debugf("Invalid P2P version. Require protocol %d, received %d\n", P2PVersion, p2pVersion) + p.Stop() + return + } + + // Handle the pub key (validation, uniqueness) + if pub == nil || len(pub) == 0 { peerlogger.Warnln("Pubkey required, not supplied in handshake.") p.Stop() return @@ -627,7 +703,7 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { usedPub := 0 // This peer is already added to the peerlist so we expect to find a double pubkey at least once eachPeer(p.ethereum.Peers(), func(peer *Peer, e *list.Element) { - if bytes.Compare(p.pubkey, peer.pubkey) == 0 { + if bytes.Compare(pub, peer.pubkey) == 0 { usedPub++ } }) @@ -637,18 +713,11 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.Stop() return } - - if c.Get(0).Uint() != ProtocolVersion { - peerlogger.Debugf("Invalid peer version. Require protocol: %d. Received: %d\n", ProtocolVersion, c.Get(0).Uint()) - p.Stop() - return - } - - p.versionKnown = true + p.pubkey = pub // If this is an inbound connection send an ack back if p.inbound { - p.port = uint16(c.Get(4).Uint()) + p.port = uint16(port) // Self connect detection pubkey := p.ethereum.KeyManager().PublicKey() @@ -659,34 +728,18 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { } } + p.SetVersion(clientId) - // Set the peer's caps - p.caps = Caps(c.Get(3).Byte()) - - // Get a reference to the peers version - versionString := c.Get(2).Str() - if len(versionString) > 0 { - p.SetVersion(c.Get(2).Str()) - } - - // Get the td and last hash - p.td = c.Get(6).BigInt() - p.bestHash = c.Get(7).Bytes() - p.lastReceivedHash = p.bestHash + p.versionKnown = true p.ethereum.PushPeer(p) p.ethereum.reactor.Post("peerList", p.ethereum.Peers()) - ethlogger.Infof("Added peer (%s) %d / %d (TD = %v ~ %x)\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers, p.td, p.bestHash) - - // Compare the total TD with the blockchain TD. If remote is higher - // fetch hashes from highest TD node. - if p.td.Cmp(p.ethereum.BlockChain().TD) > 0 { - p.ethereum.blockPool.AddHash(p.lastReceivedHash) - p.FetchHashes() - } + ethlogger.Infof("Added peer (%s) %d / %d \n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers) peerlogger.Debugln(p) + + p.pushStatus() } func (p *Peer) String() string { From c0187930dc352c645c223e17364623a68413cb74 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 10 Sep 2014 11:39:11 +0200 Subject: [PATCH 25/58] Removed some commented code --- ethvm/vm.go | 91 -------------------------------------------- ethwire/messaging.go | 1 + peer.go | 2 +- 3 files changed, 2 insertions(+), 92 deletions(-) diff --git a/ethvm/vm.go b/ethvm/vm.go index 9518540e0..fba8c4a0e 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -765,51 +765,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(ethutil.BigD(addr)) } - /* - msg := self.env.State().Manifest().AddMessage(ðstate.Message{ - To: addr, From: closure.Address(), - Origin: self.env.Origin(), - Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), - Value: value, - }) - // Create a new contract - contract := self.env.State().NewStateObject(addr) - if contract.Balance.Cmp(value) >= 0 { - closure.object.SubAmount(value) - contract.AddAmount(value) - - // Set the init script - initCode := mem.Get(offset.Int64(), size.Int64()) - msg.Input = initCode - - // Transfer all remaining gas to the new - // contract so it may run the init script - gas := new(big.Int).Set(closure.Gas) - closure.UseGas(closure.Gas) - - // Create the closure - c := NewClosure(msg, closure, contract, initCode, gas, closure.Price) - // Call the closure and set the return value as - // main script. - contract.Code, _, err = c.Call(self, nil) - } else { - err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance) - } - - if err != nil { - stack.Push(ethutil.BigFalse) - - // Revert the state as it was before. - self.env.State().Set(snapshot) - - self.Printf("CREATE err %v", err) - } else { - stack.Push(ethutil.BigD(addr)) - - msg.Output = contract.Code - } - */ self.Endl() // Debug hook @@ -858,53 +814,6 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { self.Dbg.SetCode(closure.Code) } - /* - msg := self.env.State().Manifest().AddMessage(ðstate.Message{ - To: addr.Bytes(), From: closure.Address(), - Input: args, - Origin: self.env.Origin(), - Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), - Value: value, - }) - - if closure.object.Balance.Cmp(value) < 0 { - vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance) - - closure.ReturnGas(gas, nil) - - stack.Push(ethutil.BigFalse) - } else { - snapshot := self.env.State().Copy() - - stateObject := self.env.State().GetOrNewStateObject(addr.Bytes()) - - closure.object.SubAmount(value) - stateObject.AddAmount(value) - - // Create a new callable closure - c := NewClosure(msg, closure, stateObject, stateObject.Code, gas, closure.Price) - // Executer the closure and get the return value (if any) - ret, _, err := c.Call(self, args) - if err != nil { - stack.Push(ethutil.BigFalse) - - vmlogger.Debugf("Closure execution failed. %v\n", err) - - self.env.State().Set(snapshot) - } else { - stack.Push(ethutil.BigTrue) - - mem.Set(retOffset.Int64(), retSize.Int64(), ret) - } - - msg.Output = ret - - // Debug hook - if self.Dbg != nil { - self.Dbg.SetCode(closure.Code) - } - } - */ case POST: require(6) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index c93c717a2..67a866f73 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -49,6 +49,7 @@ var msgTypeToString = map[MsgType]string{ MsgPingTy: "Ping", MsgPongTy: "Pong", MsgGetPeersTy: "Get peers", + MsgStatusTy: "Status", MsgPeersTy: "Peers", MsgTxTy: "Transactions", MsgBlockTy: "Blocks", diff --git a/peer.go b/peer.go index a7259d712..5ca3ed641 100644 --- a/peer.go +++ b/peer.go @@ -694,7 +694,7 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { } // Handle the pub key (validation, uniqueness) - if pub == nil || len(pub) == 0 { + if len(pub) == 0 { peerlogger.Warnln("Pubkey required, not supplied in handshake.") p.Stop() return From 10564723b9ffa14904907a0ebc984fa25e4f1eab Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 13 Sep 2014 13:14:24 +0200 Subject: [PATCH 26/58] added string casting --- ethutil/value.go | 10 ++++++---- ethutil/value_test.go | 6 ++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/ethutil/value.go b/ethutil/value.go index b336345ca..e8148b990 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -1,9 +1,11 @@ package ethutil import ( + "bytes" "fmt" "math/big" "reflect" + "strconv" ) // Data values are returned by the rlp decoder. The data values represents @@ -93,6 +95,9 @@ func (val *Value) Int() int64 { return new(big.Int).SetBytes(Val).Int64() } else if Val, ok := val.Val.(*big.Int); ok { return Val.Int64() + } else if Val, ok := val.Val.(string); ok { + n, _ := strconv.Atoi(Val) + return int64(n) } return 0 @@ -246,10 +251,7 @@ func (val *Value) Cmp(o *Value) bool { } func (self *Value) DeepCmp(o *Value) bool { - a := NewValue(self.BigInt()) - b := NewValue(o.BigInt()) - - return a.Cmp(b) + return bytes.Compare(self.Bytes(), o.Bytes()) == 0 } func (val *Value) Encode() []byte { diff --git a/ethutil/value_test.go b/ethutil/value_test.go index 710cbd887..5452a0790 100644 --- a/ethutil/value_test.go +++ b/ethutil/value_test.go @@ -2,6 +2,7 @@ package ethutil import ( "bytes" + "fmt" "math/big" "testing" ) @@ -78,3 +79,8 @@ func TestMath(t *testing.T) { t.Error("Expected 0, got", a) } } + +func TestString(t *testing.T) { + a := NewValue("10") + fmt.Println("VALUE WITH STRING:", a.Int()) +} From 2fb57b2ea7b7f697ddc4811c471d87116eae07cc Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 14 Sep 2014 00:13:23 +0200 Subject: [PATCH 27/58] Reworked filters --- ethchain/filter.go | 3 ++ ethereum.go | 59 ++++++++++++++++++++++++++++ ethpipe/js_pipe.go | 97 +--------------------------------------------- ethutil/list.go | 4 ++ 4 files changed, 68 insertions(+), 95 deletions(-) diff --git a/ethchain/filter.go b/ethchain/filter.go index 5ed9af977..d9f1796f4 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -23,6 +23,9 @@ type Filter struct { max int altered []data + + BlockCallback func(*Block) + MessageCallback func(ethstate.Messages) } // Create a new filter which uses a bloom filter on blocks to figure out whether a particular block diff --git a/ethereum.go b/ethereum.go index 4c5e13b6d..fdfb59b09 100644 --- a/ethereum.go +++ b/ethereum.go @@ -16,6 +16,7 @@ import ( "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethrpc" + "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" ) @@ -87,6 +88,8 @@ type Ethereum struct { clientIdentity ethwire.ClientIdentity isUpToDate bool + + filters map[int]*ethchain.Filter } func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager *ethcrypto.KeyManager, caps Caps, usePnp bool) (*Ethereum, error) { @@ -116,6 +119,7 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager keyManager: keyManager, clientIdentity: clientIdentity, isUpToDate: true, + filters: make(map[int]*ethchain.Filter), } ethereum.reactor = ethreact.New() @@ -386,6 +390,7 @@ func (s *Ethereum) Start(seed bool) { // Start the reaping processes go s.ReapDeadPeerHandler() go s.update() + go s.filterLoop() if seed { s.Seed() @@ -536,6 +541,60 @@ out: } } +var filterId = 0 + +func (self *Ethereum) InstallFilter(object map[string]interface{}) (*ethchain.Filter, int) { + defer func() { filterId++ }() + + filter := ethchain.NewFilterFromMap(object, self) + self.filters[filterId] = filter + + return filter, filterId +} + +func (self *Ethereum) UninstallFilter(id int) { + delete(self.filters, id) +} + +func (self *Ethereum) GetFilter(id int) *ethchain.Filter { + return self.filters[id] +} + +func (self *Ethereum) filterLoop() { + blockChan := make(chan ethreact.Event, 5) + messageChan := make(chan ethreact.Event, 5) + // Subscribe to events + reactor := self.Reactor() + reactor.Subscribe("newBlock", blockChan) + reactor.Subscribe("messages", messageChan) +out: + for { + select { + case <-self.quit: + break out + case block := <-blockChan: + if block, ok := block.Resource.(*ethchain.Block); ok { + for _, filter := range self.filters { + if filter.BlockCallback != nil { + filter.BlockCallback(block) + } + } + } + case msg := <-messageChan: + if messages, ok := msg.Resource.(ethstate.Messages); ok { + for _, filter := range self.filters { + if filter.MessageCallback != nil { + msgs := filter.FilterMessages(messages) + if len(msgs) > 0 { + filter.MessageCallback(msgs) + } + } + } + } + } + } +} + func bootstrapDb(db ethutil.Database) { d, _ := db.Get([]byte("ProtocolVersion")) protov := ethutil.NewValue(d).Uint() diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go index eeece5179..7ee183c84 100644 --- a/ethpipe/js_pipe.go +++ b/ethpipe/js_pipe.go @@ -3,12 +3,10 @@ package ethpipe import ( "bytes" "encoding/json" - "fmt" "sync/atomic" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethcrypto" - "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" ) @@ -234,102 +232,11 @@ func (self *JSPipe) CompileMutan(code string) string { return ethutil.Bytes2Hex(data) } -func (self *JSPipe) Watch(object map[string]interface{}) *JSFilter { - return NewJSFilterFromMap(object, self.Pipe.obj) - /*} else if str, ok := object.(string); ok { - println("str") - return NewJSFilterFromString(str, self.Pipe.obj) - */ -} - -func (self *JSPipe) Messages(object map[string]interface{}) string { - filter := self.Watch(object) - filter.Uninstall() - - return filter.Messages() - -} - -type JSFilter struct { - eth ethchain.EthManager - *ethchain.Filter - quit chan bool - - BlockCallback func(*ethchain.Block) - MessageCallback func(ethstate.Messages) -} - -func NewJSFilterFromMap(object map[string]interface{}, eth ethchain.EthManager) *JSFilter { - filter := &JSFilter{eth, ethchain.NewFilterFromMap(object, eth), make(chan bool), nil, nil} - - go filter.mainLoop() - - return filter -} - -func NewJSFilterFromString(str string, eth ethchain.EthManager) *JSFilter { - return nil -} - -func (self *JSFilter) MessagesToJson(messages ethstate.Messages) string { +func ToJSMessages(messages ethstate.Messages) *ethutil.List { var msgs []JSMessage for _, m := range messages { msgs = append(msgs, NewJSMessage(m)) } - // Return an empty array instead of "null" - if len(msgs) == 0 { - return "[]" - } - - b, err := json.Marshal(msgs) - if err != nil { - return "{\"error\":" + err.Error() + "}" - } - - return string(b) -} - -func (self *JSFilter) Messages() string { - return self.MessagesToJson(self.Find()) -} - -func (self *JSFilter) mainLoop() { - blockChan := make(chan ethreact.Event, 5) - messageChan := make(chan ethreact.Event, 5) - // Subscribe to events - reactor := self.eth.Reactor() - reactor.Subscribe("newBlock", blockChan) - reactor.Subscribe("messages", messageChan) -out: - for { - select { - case <-self.quit: - break out - case block := <-blockChan: - if block, ok := block.Resource.(*ethchain.Block); ok { - if self.BlockCallback != nil { - self.BlockCallback(block) - } - } - case msg := <-messageChan: - if messages, ok := msg.Resource.(ethstate.Messages); ok { - if self.MessageCallback != nil { - println("messages!") - msgs := self.FilterMessages(messages) - if len(msgs) > 0 { - self.MessageCallback(msgs) - } - } - } - } - } -} - -func (self *JSFilter) Changed(object interface{}) { - fmt.Printf("%T\n", object) -} - -func (self *JSFilter) Uninstall() { - self.quit <- true + return ethutil.NewList(msgs) } diff --git a/ethutil/list.go b/ethutil/list.go index 18bf04792..0aa657a14 100644 --- a/ethutil/list.go +++ b/ethutil/list.go @@ -20,6 +20,10 @@ func NewList(t interface{}) *List { return &List{list, list.Len()} } +func EmptyList() *List { + return NewList([]interface{}{}) +} + // Get N element from the embedded slice. Returns nil if OOB. func (self *List) Get(i int) interface{} { if self.list.Len() > i { From 954ba211bf8ee63872b5e4d20b6aafb4400507c6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 14 Sep 2014 12:02:35 +0200 Subject: [PATCH 28/58] Fixed contract validation address in tx pool --- ethchain/transaction_pool.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index bd8b27a6d..9a6322432 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -99,7 +99,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { return fmt.Errorf("[TXPL] No last block on the block chain") } - if len(tx.Recipient) != 20 { + if len(tx.Recipient) != 0 && len(tx.Recipient) != 20 { return fmt.Errorf("[TXPL] Invalid recipient. len = %d", len(tx.Recipient)) } @@ -148,7 +148,10 @@ out: // Call blocking version. pool.addTransaction(tx) - txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) + tmp := make([]byte, 4) + copy(tmp, tx.Recipient) + + txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash()) // Notify the subscribers pool.Ethereum.Reactor().Post("newTx:pre", tx) From f63cb278038dddd09aa4527529c43fdb8320f2fa Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 14 Sep 2014 13:42:02 +0200 Subject: [PATCH 29/58] tmp --- peer.go | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/peer.go b/peer.go index 5ca3ed641..28b193e82 100644 --- a/peer.go +++ b/peer.go @@ -182,6 +182,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { inbound: false, connected: 0, disconnect: 0, + port: 30303, caps: caps, version: ethereum.ClientIdentity().String(), } @@ -629,17 +630,6 @@ func (p *Peer) pushPeers() { p.QueueMessage(p.peersMessage()) } -func (p *Peer) pushHandshake() error { - pubkey := p.ethereum.KeyManager().PublicKey() - msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(0), []byte(p.version), []string{"eth"}, p.port, pubkey[1:], - }) - - p.QueueMessage(msg) - - return nil -} - func (self *Peer) pushStatus() { const netVersion = 0 msg := ethwire.NewMessage(ethwire.MsgStatusTy, []interface{}{ @@ -673,8 +663,21 @@ func (self *Peer) handleStatus(msg *ethwire.Msg) { ethlogger.Infof("Peer is [ETH] capable. (TD = %v ~ %x", self.td, self.bestHash) } +func (p *Peer) pushHandshake() error { + pubkey := p.ethereum.KeyManager().PublicKey() + fmt.Println("pubkey", pubkey) + msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ + uint32(0), []byte(p.version), []string{"eth"}, uint32(p.port), pubkey[1:], + }) + + p.QueueMessage(msg) + + return nil +} + func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data + fmt.Println(c, c.Len()) var ( p2pVersion = c.Get(0).Uint() @@ -684,8 +687,6 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { pub = c.Get(4).Bytes() ) - fmt.Println("PEER CAPS", caps) - // Check correctness of p2p protocol version if p2pVersion != P2PVersion { peerlogger.Debugf("Invalid P2P version. Require protocol %d, received %d\n", P2PVersion, p2pVersion) @@ -735,7 +736,7 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.ethereum.PushPeer(p) p.ethereum.reactor.Post("peerList", p.ethereum.Peers()) - ethlogger.Infof("Added peer (%s) %d / %d \n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers) + ethlogger.Infof("Added peer (%s) %d / %d (%v)\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers, caps) peerlogger.Debugln(p) From 9e89dacc6439e915784c43eaa273307f24b40be9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 14 Sep 2014 13:42:13 +0200 Subject: [PATCH 30/58] log removed --- peer.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/peer.go b/peer.go index 28b193e82..7178c4f38 100644 --- a/peer.go +++ b/peer.go @@ -665,7 +665,6 @@ func (self *Peer) handleStatus(msg *ethwire.Msg) { func (p *Peer) pushHandshake() error { pubkey := p.ethereum.KeyManager().PublicKey() - fmt.Println("pubkey", pubkey) msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ uint32(0), []byte(p.version), []string{"eth"}, uint32(p.port), pubkey[1:], }) @@ -677,7 +676,6 @@ func (p *Peer) pushHandshake() error { func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data - fmt.Println(c, c.Len()) var ( p2pVersion = c.Get(0).Uint() From 742a9b00bc1d587669f1b1bf78a27040e7d474a4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 14 Sep 2014 13:47:29 +0200 Subject: [PATCH 31/58] tmp --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index 7178c4f38..ad76b8f37 100644 --- a/peer.go +++ b/peer.go @@ -666,7 +666,7 @@ func (self *Peer) handleStatus(msg *ethwire.Msg) { func (p *Peer) pushHandshake() error { pubkey := p.ethereum.KeyManager().PublicKey() msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(0), []byte(p.version), []string{"eth"}, uint32(p.port), pubkey[1:], + uint32(0), []byte(p.version), []string{"eth"}, uint32(30303) /*p.port*/, pubkey[1:], }) p.QueueMessage(msg) From 86d1a26b13a55723a89f7a9101200711a51afbc3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 14 Sep 2014 14:09:46 +0200 Subject: [PATCH 32/58] fixed status message --- peer.go | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/peer.go b/peer.go index ad76b8f37..21d918d2e 100644 --- a/peer.go +++ b/peer.go @@ -634,8 +634,8 @@ func (self *Peer) pushStatus() { const netVersion = 0 msg := ethwire.NewMessage(ethwire.MsgStatusTy, []interface{}{ uint32(ProtocolVersion), - netVersion, - self.ethereum.BlockChain().TD.Uint64(), + uint32(netVersion), + self.ethereum.BlockChain().TD, self.ethereum.BlockChain().CurrentBlock.Hash(), self.ethereum.BlockChain().Genesis().Hash(), }) @@ -645,13 +645,22 @@ func (self *Peer) pushStatus() { func (self *Peer) handleStatus(msg *ethwire.Msg) { c := msg.Data - // Set the peer's caps - //p.caps = Caps(c.Get(3).Byte()) + + var ( + protoVersion = c.Get(0).Uint() + netVersion = c.Get(1).Uint() + td = c.Get(2).BigInt() + bestHash = c.Get(3).Bytes() + genesis = c.Get(4).Bytes() + ) + ethlogger.Infof("gen = %x\n", genesis) // Get the td and last hash - self.td = c.Get(6).BigInt() - self.bestHash = c.Get(7).Bytes() - self.lastReceivedHash = self.bestHash + self.td = td + self.bestHash = bestHash + self.lastReceivedHash = bestHash + + self.statusKnown = true // Compare the total TD with the blockchain TD. If remote is higher // fetch hashes from highest TD node. @@ -660,13 +669,14 @@ func (self *Peer) handleStatus(msg *ethwire.Msg) { self.FetchHashes() } - ethlogger.Infof("Peer is [ETH] capable. (TD = %v ~ %x", self.td, self.bestHash) + ethlogger.Infof("Peer is [ETH] capable. (TD = %v ~ %x) %d / %d", self.td, self.bestHash, protoVersion, netVersion) + } func (p *Peer) pushHandshake() error { pubkey := p.ethereum.KeyManager().PublicKey() msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(0), []byte(p.version), []string{"eth"}, uint32(30303) /*p.port*/, pubkey[1:], + P2PVersion, []byte(p.version), []interface{}{"eth"}, uint32(30303) /*p.port*/, pubkey[1:], }) p.QueueMessage(msg) From 74ef22d8247c08b6b827f5e9f1001f8bcce9d0e0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 14 Sep 2014 14:30:33 +0200 Subject: [PATCH 33/58] add it to the list --- block_pool.go | 1 + peer.go | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/block_pool.go b/block_pool.go index 25627eb5c..38827242d 100644 --- a/block_pool.go +++ b/block_pool.go @@ -53,6 +53,7 @@ func (self *BlockPool) SetBlock(b *ethchain.Block, peer *Peer) { hash := string(b.Hash()) if self.pool[hash] == nil { + self.hashPool = append(self.hashPool, b.Hash()) self.pool[hash] = &block{peer, nil} } diff --git a/peer.go b/peer.go index 21d918d2e..4cc62887c 100644 --- a/peer.go +++ b/peer.go @@ -486,7 +486,6 @@ func (p *Peer) HandleInbound() { blockPool := p.ethereum.blockPool it := msg.Data.NewIterator() - for it.Next() { block := ethchain.NewBlockFromRlpValue(it.Value()) From 4db4ec1621767513ed2bd99d835c3e2f1c2b0e7e Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 15 Sep 2014 01:10:50 +0200 Subject: [PATCH 34/58] Added unique set --- ethutil/set.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 ethutil/set.go diff --git a/ethutil/set.go b/ethutil/set.go new file mode 100644 index 000000000..80e2edde2 --- /dev/null +++ b/ethutil/set.go @@ -0,0 +1,32 @@ +package ethutil + +type Settable interface { + AsSet() UniqueSet +} + +type UniqueSet map[interface{}]struct{} + +func NewSet(v ...interface{}) UniqueSet { + set := make(UniqueSet) + for _, val := range v { + set.Insert(val) + } + + return set +} + +func (self UniqueSet) Insert(k interface{}) UniqueSet { + self[k] = struct{}{} + + return self +} + +func (self UniqueSet) Include(k interface{}) bool { + _, ok := self[k] + + return ok +} + +func Set(s Settable) UniqueSet { + return s.AsSet() +} From 2f614900e82036e3e8f6f6a714efc43e09aca830 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 15 Sep 2014 01:11:01 +0200 Subject: [PATCH 35/58] Updated GHOST --- ethchain/block.go | 13 ++++++- ethchain/block_chain.go | 2 +- ethchain/error.go | 18 +++++++++ ethchain/state_manager.go | 79 +++++++++++++++++---------------------- ethminer/miner.go | 2 +- ethvm/vm.go | 57 ++++++++++++++++++---------- peer.go | 2 +- 7 files changed, 104 insertions(+), 69 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index d2d012e55..fde6ff04a 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -31,11 +31,22 @@ func (bi *BlockInfo) RlpEncode() []byte { return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent}) } +type Blocks []*Block + +func (self Blocks) AsSet() ethutil.UniqueSet { + set := make(ethutil.UniqueSet) + for _, block := range self { + set.Insert(block.Hash()) + } + + return set +} + type Block struct { // Hash to the previous block PrevHash []byte // Uncles of this block - Uncles []*Block + Uncles Blocks UncleSha []byte // The coin base address Coinbase []byte diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 74f47aa90..2d88a0f53 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -60,7 +60,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { if bc.CurrentBlock != nil { var mul *big.Int - if block.Time < lastBlockTime+42 { + if block.Time < lastBlockTime+5 { mul = big.NewInt(1) } else { mul = big.NewInt(-1) diff --git a/ethchain/error.go b/ethchain/error.go index 2cf09a1ec..82949141a 100644 --- a/ethchain/error.go +++ b/ethchain/error.go @@ -25,6 +25,24 @@ func IsParentErr(err error) bool { return ok } +type UncleErr struct { + Message string +} + +func (err *UncleErr) Error() string { + return err.Message +} + +func UncleError(str string) error { + return &UncleErr{Message: str} +} + +func IsUncleErr(err error) bool { + _, ok := err.(*UncleErr) + + return ok +} + // Block validation error. If any validation fails, this error will be thrown type ValidationErr struct { Message string diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 33af259cf..a165ed79d 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -219,7 +219,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // I'm not sure, but I don't know if there should be thrown // any errors at this time. - if err = sm.AccumelateRewards(state, block); err != nil { + if err = sm.AccumelateRewards(state, block, parent); err != nil { statelogger.Errorln("Error accumulating reward", err) return err } @@ -334,35 +334,43 @@ func (sm *StateManager) ValidateBlock(block *Block) error { return nil } -func CalculateBlockReward(block *Block, uncleLength int) *big.Int { - base := new(big.Int) - for i := 0; i < uncleLength; i++ { - base.Add(base, UncleInclusionReward) +func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent *Block) error { + reward := new(big.Int) + + knownUncles := ethutil.Set(parent.Uncles) + nonces := ethutil.NewSet(block.Nonce) + for _, uncle := range block.Uncles { + if nonces.Include(uncle.Nonce) { + // Error not unique + return UncleError("Uncle not unique") + } + + uncleParent := sm.bc.GetBlock(uncle.PrevHash) + if uncleParent == nil { + return UncleError("Uncle's parent unknown") + } + + if uncleParent.Number.Cmp(new(big.Int).Sub(parent.Number, big.NewInt(6))) < 0 { + return UncleError("Uncle too old") + } + + if knownUncles.Include(uncle.Hash()) { + return UncleError("Uncle in chain") + } + + r := new(big.Int) + r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16)) + + uncleAccount := state.GetAccount(uncle.Coinbase) + uncleAccount.AddAmount(r) + + reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32))) } - return base.Add(base, BlockReward) -} - -func CalculateUncleReward(block *Block) *big.Int { - return UncleReward -} - -func (sm *StateManager) AccumelateRewards(state *ethstate.State, block *Block) error { // Get the account associated with the coinbase account := state.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address - account.AddAmount(CalculateBlockReward(block, len(block.Uncles))) - - addr := make([]byte, len(block.Coinbase)) - copy(addr, block.Coinbase) - state.UpdateStateObject(account) - - for _, uncle := range block.Uncles { - uncleAccount := state.GetAccount(uncle.Coinbase) - uncleAccount.AddAmount(CalculateUncleReward(uncle)) - - state.UpdateStateObject(uncleAccount) - } + account.AddAmount(reward) return nil } @@ -375,14 +383,6 @@ func (sm *StateManager) Stop() { func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { bloomf := NewBloomFilter(nil) - /* - for addr, stateObject := range state.Manifest().ObjectChanges { - // Set the bloom filter's bin - bloomf.Set([]byte(addr)) - - sm.Ethereum.Reactor().Post("object:"+addr, stateObject) - } - */ for _, msg := range state.Manifest().Messages { bloomf.Set(msg.To) bloomf.Set(msg.From) @@ -390,17 +390,6 @@ func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { sm.Ethereum.Reactor().Post("messages", state.Manifest().Messages) - /* - for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges { - for addr, value := range mappedObjects { - // Set the bloom filter's bin - bloomf.Set(ethcrypto.Sha3Bin([]byte(stateObjectAddr + addr))) - - sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, ðstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value}) - } - } - */ - return bloomf } @@ -420,7 +409,7 @@ func (sm *StateManager) GetMessages(block *Block) (messages []*ethstate.Message, sm.ApplyDiff(state, parent, block) - sm.AccumelateRewards(state, block) + sm.AccumelateRewards(state, block, parent) return state.Manifest().Messages, nil } diff --git a/ethminer/miner.go b/ethminer/miner.go index 799db79f1..083d9ecde 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -187,7 +187,7 @@ func (self *Miner) mineNewBlock() { self.block.SetReceipts(receipts, txs) // Accumulate the rewards included for this block - stateManager.AccumelateRewards(self.block.State(), self.block) + stateManager.AccumelateRewards(self.block.State(), self.block, parent) self.block.State().Update() diff --git a/ethvm/vm.go b/ethvm/vm.go index fba8c4a0e..2c516f4f8 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -3,7 +3,6 @@ package ethvm import ( "container/list" "fmt" - "math" "math/big" "github.com/ethereum/eth-go/ethcrypto" @@ -67,6 +66,19 @@ func New(env Environment) *Vm { return &Vm{env: env, logTy: lt, Recoverable: true, queue: list.New()} } +func calcMemSize(off, l *big.Int) *big.Int { + if l.Cmp(ethutil.Big0) == 0 { + return ethutil.Big0 + } + + return new(big.Int).Add(off, l) +} + +// Simple helper +func u256(n int64) *big.Int { + return big.NewInt(n) +} + func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { if self.Recoverable { // Recover from any require exception @@ -147,7 +159,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { addStepGasUsage(GasStep) - var newMemSize uint64 = 0 + var newMemSize *big.Int = ethutil.Big0 switch op { case STOP: gas.Set(ethutil.Big0) @@ -171,57 +183,62 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { gas.Set(GasBalance) case MSTORE: require(2) - newMemSize = stack.Peek().Uint64() + 32 + newMemSize = calcMemSize(stack.Peek(), u256(32)) case MLOAD: require(1) - newMemSize = stack.Peek().Uint64() + 32 + newMemSize = calcMemSize(stack.Peek(), u256(32)) case MSTORE8: require(2) - newMemSize = stack.Peek().Uint64() + 1 + newMemSize = calcMemSize(stack.Peek(), u256(1)) case RETURN: require(2) - newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64() + newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) case SHA3: require(2) gas.Set(GasSha) - newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64() + newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) case CALLDATACOPY: require(3) - newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() + newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) case CODECOPY: require(3) - newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() + newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) case EXTCODECOPY: require(4) - newMemSize = stack.data[stack.Len()-1].Uint64() + stack.data[stack.Len()-4].Uint64() + newMemSize = calcMemSize(stack.data[stack.Len()-1], stack.data[stack.Len()-4]) case CALL, CALLSTATELESS: require(7) gas.Set(GasCall) addStepGasUsage(stack.data[stack.Len()-1]) - x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() - y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() + x := calcMemSize(stack.data[stack.Len()-6], stack.data[stack.Len()-7]) + y := calcMemSize(stack.data[stack.Len()-4], stack.data[stack.Len()-5]) - newMemSize = uint64(math.Max(float64(x), float64(y))) + newMemSize = ethutil.BigMax(x, y) case CREATE: require(3) gas.Set(GasCreate) - newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64() + newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3]) } - // BUG This will break on overflows. https://github.com/ethereum/eth-go/issues/47 - newMemSize = (newMemSize + 31) / 32 * 32 - if newMemSize > uint64(mem.Len()) { - m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32 - addStepGasUsage(big.NewInt(int64(m))) + if newMemSize.Cmp(ethutil.Big0) > 0 { + //newMemSize = (newMemSize + 31) / 32 * 32 + newMemSize = newMemSize.Add(newMemSize, u256(31)).Div(newMemSize, u256(32)).Mul(newMemSize, u256(32)) + //if newMemSize > uint64(mem.Len()) { + if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { + newMemSize = newMemSize.Sub(newMemSize, u256(int64(mem.Len()))) + memGasUsage := newMemSize.Mul(GasMemory, newMemSize).Div(newMemSize, u256(32)) + //m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32 + addStepGasUsage(memGasUsage) + } } if !closure.UseGas(gas) { @@ -235,7 +252,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf("(pc) %-3d -o- %-14s", pc, op.String()) self.Printf(" (g) %-3v (%v)", gas, closure.Gas) - mem.Resize(newMemSize) + mem.Resize(newMemSize.Uint64()) switch op { case LOG: diff --git a/peer.go b/peer.go index 4cc62887c..349d02097 100644 --- a/peer.go +++ b/peer.go @@ -675,7 +675,7 @@ func (self *Peer) handleStatus(msg *ethwire.Msg) { func (p *Peer) pushHandshake() error { pubkey := p.ethereum.KeyManager().PublicKey() msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - P2PVersion, []byte(p.version), []interface{}{"eth"}, uint32(30303) /*p.port*/, pubkey[1:], + P2PVersion, []byte(p.version), []interface{}{"eth"}, p.port, pubkey[1:], }) p.QueueMessage(msg) From 33a0dec8a157b9687ca6038f4deb011f3f1f7bdc Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 15 Sep 2014 15:42:12 +0200 Subject: [PATCH 36/58] Improved catching up and refactored --- block_pool.go | 65 ++++++++++++--------------------------- ethchain/block.go | 33 +++++++++++++++++--- ethchain/block_chain.go | 27 ++++++++-------- ethchain/state_manager.go | 8 +++-- ethstate/dump.go | 2 +- ethstate/state.go | 5 +-- ethstate/state_object.go | 15 ++++++--- ethutil/bytes.go | 16 ++++++++++ ethutil/rlp.go | 2 ++ ethutil/set.go | 16 ++++++---- peer.go | 46 ++++++++++++--------------- 11 files changed, 129 insertions(+), 106 deletions(-) diff --git a/block_pool.go b/block_pool.go index 38827242d..0a668e111 100644 --- a/block_pool.go +++ b/block_pool.go @@ -52,59 +52,34 @@ func (self *BlockPool) AddHash(hash []byte) { func (self *BlockPool) SetBlock(b *ethchain.Block, peer *Peer) { hash := string(b.Hash()) - if self.pool[hash] == nil { + if self.pool[hash] == nil && !self.eth.BlockChain().HasBlock(b.Hash()) { self.hashPool = append(self.hashPool, b.Hash()) - self.pool[hash] = &block{peer, nil} + self.pool[hash] = &block{peer, b} + } else if self.pool[hash] != nil { + self.pool[hash].block = b } - - self.pool[hash].block = b } -func (self *BlockPool) CheckLinkAndProcess(f func(block *ethchain.Block)) bool { - self.mut.Lock() - defer self.mut.Unlock() +func (self *BlockPool) CheckLinkAndProcess(f func(block *ethchain.Block)) { - if self.IsLinked() { - for i, hash := range self.hashPool { - if self.pool[string(hash)] == nil { - continue - } - - block := self.pool[string(hash)].block - if block != nil { - f(block) - - delete(self.pool, string(hash)) - } else { - self.hashPool = self.hashPool[i:] - - return false - } - } - - return true - } - - return false -} - -func (self *BlockPool) IsLinked() bool { - if len(self.hashPool) == 0 { - return false - } - - for i := 0; i < len(self.hashPool); i++ { - item := self.pool[string(self.hashPool[i])] - if item != nil && item.block != nil { - if self.eth.BlockChain().HasBlock(item.block.PrevHash) { - self.hashPool = self.hashPool[i:] - - return true - } + var blocks ethchain.Blocks + for _, item := range self.pool { + if item.block != nil { + blocks = append(blocks, item.block) } } - return false + ethchain.BlockBy(ethchain.Number).Sort(blocks) + for _, block := range blocks { + if self.eth.BlockChain().HasBlock(block.PrevHash) { + f(block) + + hash := block.Hash() + self.hashPool = ethutil.DeleteFromByteSlice(self.hashPool, hash) + delete(self.pool, string(hash)) + } + + } } func (self *BlockPool) Take(amount int, peer *Peer) (hashes [][]byte) { diff --git a/ethchain/block.go b/ethchain/block.go index fde6ff04a..157be2a52 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "math/big" + "sort" _ "strconv" "time" @@ -42,9 +43,32 @@ func (self Blocks) AsSet() ethutil.UniqueSet { return set } +type BlockBy func(b1, b2 *Block) bool + +func (self BlockBy) Sort(blocks Blocks) { + bs := blockSorter{ + blocks: blocks, + by: self, + } + sort.Sort(bs) +} + +type blockSorter struct { + blocks Blocks + by func(b1, b2 *Block) bool +} + +func (self blockSorter) Len() int { return len(self.blocks) } +func (self blockSorter) Swap(i, j int) { + self.blocks[i], self.blocks[j] = self.blocks[j], self.blocks[i] +} +func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) } + +func Number(b1, b2 *Block) bool { return b1.Number.Cmp(b2.Number) < 0 } + type Block struct { // Hash to the previous block - PrevHash []byte + PrevHash ethutil.Bytes // Uncles of this block Uncles Blocks UncleSha []byte @@ -68,7 +92,7 @@ type Block struct { // Extra data Extra string // Block Nonce for verification - Nonce []byte + Nonce ethutil.Bytes // List of transactions and/or contracts transactions []*Transaction receipts []*Receipt @@ -117,8 +141,9 @@ func CreateBlock(root interface{}, } // Returns a hash of the block -func (block *Block) Hash() []byte { - return ethcrypto.Sha3Bin(block.Value().Encode()) +func (block *Block) Hash() ethutil.Bytes { + return ethcrypto.Sha3Bin(ethutil.NewValue(block.header()).Encode()) + //return ethcrypto.Sha3Bin(block.Value().Encode()) } func (block *Block) HashNoNonce() []byte { diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 2d88a0f53..5d0d652df 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -58,24 +58,20 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { block.MinGasPrice = big.NewInt(10000000000000) - if bc.CurrentBlock != nil { - var mul *big.Int - if block.Time < lastBlockTime+5 { - mul = big.NewInt(1) - } else { - mul = big.NewInt(-1) - } - + parent := bc.CurrentBlock + if parent != nil { diff := new(big.Int) - diff.Add(diff, bc.CurrentBlock.Difficulty) - diff.Div(diff, big.NewInt(1024)) - diff.Mul(diff, mul) - diff.Add(diff, bc.CurrentBlock.Difficulty) + + adjust := new(big.Int).Rsh(parent.Difficulty, 10) + if block.Time >= lastBlockTime+5 { + diff.Sub(parent.Difficulty, adjust) + } else { + diff.Add(parent.Difficulty, adjust) + } block.Difficulty = diff - block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) - block.GasLimit = block.CalcGasLimit(bc.CurrentBlock) + } return block @@ -159,6 +155,9 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockHash = block.Hash() bc.LastBlockNumber = block.Number.Uint64() + if bc.LastBlockNumber == 0 { + bc.genesisBlock = block + } } else { AddTestNetFunds(bc.genesisBlock) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a165ed79d..1ccaa560f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -217,13 +217,13 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { return err } - // I'm not sure, but I don't know if there should be thrown - // any errors at this time. if err = sm.AccumelateRewards(state, block, parent); err != nil { statelogger.Errorln("Error accumulating reward", err) return err } + state.Update() + if !block.State().Cmp(state) { err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root) return @@ -335,7 +335,7 @@ func (sm *StateManager) ValidateBlock(block *Block) error { } func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent *Block) error { - reward := new(big.Int) + reward := new(big.Int).Set(BlockReward) knownUncles := ethutil.Set(parent.Uncles) nonces := ethutil.NewSet(block.Nonce) @@ -358,6 +358,8 @@ func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent * return UncleError("Uncle in chain") } + nonces.Insert(uncle.Nonce) + r := new(big.Int) r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16)) diff --git a/ethstate/dump.go b/ethstate/dump.go index be60a05fc..cdd4228b8 100644 --- a/ethstate/dump.go +++ b/ethstate/dump.go @@ -28,7 +28,7 @@ func (self *State) Dump() []byte { self.Trie.NewIterator().Each(func(key string, value *ethutil.Value) { stateObject := NewStateObjectFromBytes([]byte(key), value.Bytes()) - account := Account{Balance: stateObject.Balance.String(), Nonce: stateObject.Nonce, CodeHash: ethutil.Bytes2Hex(stateObject.CodeHash)} + account := Account{Balance: stateObject.Balance.String(), Nonce: stateObject.Nonce, CodeHash: ethutil.Bytes2Hex(stateObject.codeHash)} account.Storage = make(map[string]string) stateObject.EachStorage(func(key string, value *ethutil.Value) { diff --git a/ethstate/state.go b/ethstate/state.go index 42bbf021b..0e87659fc 100644 --- a/ethstate/state.go +++ b/ethstate/state.go @@ -3,7 +3,6 @@ package ethstate import ( "math/big" - "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" @@ -66,7 +65,9 @@ func (self *State) GetCode(addr []byte) []byte { func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() - ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Code), stateObject.Code) + if len(stateObject.CodeHash()) > 0 { + ethutil.Config.Db.Put(stateObject.CodeHash(), stateObject.Code) + } self.Trie.Update(string(addr), string(stateObject.RlpEncode())) } diff --git a/ethstate/state_object.go b/ethstate/state_object.go index 6fc0696a8..be083e80a 100644 --- a/ethstate/state_object.go +++ b/ethstate/state_object.go @@ -32,7 +32,7 @@ type StateObject struct { address []byte // Shared attributes Balance *big.Int - CodeHash []byte + codeHash []byte Nonce uint64 // Contract related attributes State *State @@ -236,7 +236,7 @@ func (self *StateObject) RefundGas(gas, price *big.Int) { func (self *StateObject) Copy() *StateObject { stateObject := NewStateObject(self.Address()) stateObject.Balance.Set(self.Balance) - stateObject.CodeHash = ethutil.CopyBytes(self.CodeHash) + stateObject.codeHash = ethutil.CopyBytes(self.codeHash) stateObject.Nonce = self.Nonce if self.State != nil { stateObject.State = self.State.Copy() @@ -297,12 +297,17 @@ func (c *StateObject) RlpEncode() []byte { } else { root = "" } + + return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, c.CodeHash()}) +} + +func (c *StateObject) CodeHash() ethutil.Bytes { var codeHash []byte if len(c.Code) > 0 { codeHash = ethcrypto.Sha3Bin(c.Code) } - return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, codeHash}) + return codeHash } func (c *StateObject) RlpDecode(data []byte) { @@ -314,9 +319,9 @@ func (c *StateObject) RlpDecode(data []byte) { c.storage = make(map[string]*ethutil.Value) c.gasPool = new(big.Int) - c.CodeHash = decoder.Get(3).Bytes() + c.codeHash = decoder.Get(3).Bytes() - c.Code, _ = ethutil.Config.Db.Get(c.CodeHash) + c.Code, _ = ethutil.Config.Db.Get(c.codeHash) } // Storage change object. Used by the manifest for notifying changes to diff --git a/ethutil/bytes.go b/ethutil/bytes.go index e38f89454..f151d16ee 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -9,6 +9,22 @@ import ( "strings" ) +type Bytes []byte + +func (self Bytes) String() string { + return string(self) +} + +func DeleteFromByteSlice(s [][]byte, hash []byte) [][]byte { + for i, h := range s { + if bytes.Compare(h, hash) == 0 { + return append(s[:i], s[i+1:]...) + } + } + + return s +} + // Number to bytes // // Returns the number in bytes with the specified base diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 17ff627eb..febfb78e1 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -124,6 +124,8 @@ func Encode(object interface{}) []byte { } else { buff.Write(Encode(t.Bytes())) } + case Bytes: + buff.Write(Encode([]byte(t))) case []byte: if len(t) == 1 && t[0] <= 0x7f { buff.Write(t) diff --git a/ethutil/set.go b/ethutil/set.go index 80e2edde2..7955edac0 100644 --- a/ethutil/set.go +++ b/ethutil/set.go @@ -4,9 +4,13 @@ type Settable interface { AsSet() UniqueSet } -type UniqueSet map[interface{}]struct{} +type Stringable interface { + String() string +} -func NewSet(v ...interface{}) UniqueSet { +type UniqueSet map[string]struct{} + +func NewSet(v ...Stringable) UniqueSet { set := make(UniqueSet) for _, val := range v { set.Insert(val) @@ -15,14 +19,14 @@ func NewSet(v ...interface{}) UniqueSet { return set } -func (self UniqueSet) Insert(k interface{}) UniqueSet { - self[k] = struct{}{} +func (self UniqueSet) Insert(k Stringable) UniqueSet { + self[k.String()] = struct{}{} return self } -func (self UniqueSet) Include(k interface{}) bool { - _, ok := self[k] +func (self UniqueSet) Include(k Stringable) bool { + _, ok := self[k.String()] return ok } diff --git a/peer.go b/peer.go index 349d02097..32885aed8 100644 --- a/peer.go +++ b/peer.go @@ -24,7 +24,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 28 + ProtocolVersion = 32 // Current P2P version P2PVersion = 0 // Interval for ping/pong message @@ -276,13 +276,15 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { return } } else { - if !p.statusKnown { - switch msg.Type { - case ethwire.MsgStatusTy: // Ok - default: // Anything but ack is allowed - return + /* + if !p.statusKnown { + switch msg.Type { + case ethwire.MsgStatusTy: // Ok + default: // Anything but ack is allowed + return + } } - } + */ } peerlogger.DebugDetailf("(%v) <= %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data) @@ -488,19 +490,25 @@ func (p *Peer) HandleInbound() { it := msg.Data.NewIterator() for it.Next() { block := ethchain.NewBlockFromRlpValue(it.Value()) + //fmt.Printf("%v %x - %x\n", block.Number, block.Hash()[0:4], block.PrevHash[0:4]) blockPool.SetBlock(block, p) p.lastBlockReceived = time.Now() } - linked := blockPool.CheckLinkAndProcess(func(block *ethchain.Block) { - p.ethereum.StateManager().Process(block, false) + blockPool.CheckLinkAndProcess(func(block *ethchain.Block) { + err := p.ethereum.StateManager().Process(block, false) + if err != nil { + peerlogger.Infoln(err) + } }) - if !linked { - p.FetchBlocks() - } + /* + if !linked { + p.FetchBlocks() + } + */ } } } @@ -596,20 +604,6 @@ func (p *Peer) Stop() { p.ethereum.RemovePeer(p) } -/* -func (p *Peer) pushHandshake() error { - pubkey := p.ethereum.KeyManager().PublicKey() - msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(ProtocolVersion), uint32(0), []byte(p.version), byte(p.caps), p.port, pubkey[1:], - p.ethereum.BlockChain().TD.Uint64(), p.ethereum.BlockChain().CurrentBlock.Hash(), - }) - - p.QueueMessage(msg) - - return nil -} -*/ - func (p *Peer) peersMessage() *ethwire.Msg { outPeers := make([]interface{}, len(p.ethereum.InOutPeers())) // Serialise each peer From 399256b38403f2e95312250d49fca3cada8956b8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 15 Sep 2014 22:11:05 +0200 Subject: [PATCH 37/58] VM execution fixes Refactoring caused executing issues --- ethchain/block_chain.go | 8 +++---- ethchain/state_manager.go | 19 ++++++++++----- ethereum.go | 3 ++- ethvm/stack.go | 6 ++--- ethvm/vm.go | 49 ++++++++++++++++++++------------------- ethwire/messaging.go | 4 +++- peer.go | 19 +++++++-------- 7 files changed, 57 insertions(+), 51 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 5d0d652df..1e29f1188 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -148,6 +148,9 @@ func AddTestNetFunds(block *Block) { } func (bc *BlockChain) setLastBlock() { + // Prep genesis + AddTestNetFunds(bc.genesisBlock) + data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) if len(data) != 0 { block := NewBlockFromBytes(data) @@ -155,12 +158,7 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockHash = block.Hash() bc.LastBlockNumber = block.Number.Uint64() - if bc.LastBlockNumber == 0 { - bc.genesisBlock = block - } } else { - AddTestNetFunds(bc.genesisBlock) - bc.genesisBlock.state.Trie.Sync() // Prepare the genesis block bc.Add(bc.genesisBlock) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 1ccaa560f..b0ea754f4 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -5,6 +5,7 @@ import ( "container/list" "fmt" "math/big" + "os" "sync" "time" @@ -154,6 +155,10 @@ done: if i < len(block.Receipts()) { original := block.Receipts()[i] if !original.Cmp(receipt) { + if ethutil.Config.Diff { + os.Exit(1) + } + return nil, nil, nil, fmt.Errorf("err diff #%d (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash()) } } @@ -307,14 +312,16 @@ func (sm *StateManager) ValidateBlock(block *Block) error { // Check each uncle's previous hash. In order for it to be valid // is if it has the same block hash as the current - previousBlock := sm.bc.GetBlock(block.PrevHash) - for _, uncle := range block.Uncles { - if bytes.Compare(uncle.PrevHash, previousBlock.PrevHash) != 0 { - return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x", previousBlock.PrevHash, uncle.PrevHash) + parent := sm.bc.GetBlock(block.PrevHash) + /* + for _, uncle := range block.Uncles { + if bytes.Compare(uncle.PrevHash,parent.PrevHash) != 0 { + return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x",parent.PrevHash, uncle.PrevHash) + } } - } + */ - diff := block.Time - previousBlock.Time + diff := block.Time - parent.Time if diff < 0 { return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Time, sm.bc.CurrentBlock.Time) } diff --git a/ethereum.go b/ethereum.go index fdfb59b09..8d62fa9f2 100644 --- a/ethereum.go +++ b/ethereum.go @@ -23,7 +23,8 @@ import ( const ( seedTextFileUri string = "http://www.ethereum.org/servers.poc3.txt" - seedNodeAddress = "54.76.56.74:30303" + //seedNodeAddress = "54.76.56.74:30303" + seedNodeAddress = "localhost:30303" ) var ethlogger = ethlog.NewLogger("SERV") diff --git a/ethvm/stack.go b/ethvm/stack.go index 82dd612c2..4ac023fb9 100644 --- a/ethvm/stack.go +++ b/ethvm/stack.go @@ -65,13 +65,13 @@ func (st *Stack) Peekn() (*big.Int, *big.Int) { } func (st *Stack) Swapn(n int) (*big.Int, *big.Int) { - st.data[n], st.data[0] = st.data[0], st.data[n] + st.data[len(st.data)-n], st.data[len(st.data)-1] = st.data[len(st.data)-1], st.data[len(st.data)-n] - return st.data[n], st.data[0] + return st.data[len(st.data)-n], st.data[len(st.data)-1] } func (st *Stack) Dupn(n int) *big.Int { - st.Push(st.data[n]) + st.Push(st.data[len(st.data)-n]) return st.Peek() } diff --git a/ethvm/vm.go b/ethvm/vm.go index 2c516f4f8..cfba3820b 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -63,7 +63,7 @@ func New(env Environment) *Vm { lt = LogTyDiff } - return &Vm{env: env, logTy: lt, Recoverable: true, queue: list.New()} + return &Vm{env: env, logTy: lt, Recoverable: false, queue: list.New()} } func calcMemSize(off, l *big.Int) *big.Int { @@ -132,15 +132,13 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // XXX Leave this Println intact. Don't change this to the log system. // Used for creating diffs between implementations if self.logTy == LogTyDiff { - /* - switch op { - case STOP, RETURN, SUICIDE: - closure.object.EachStorage(func(key string, value *ethutil.Value) { - value.Decode() - fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) - }) - } - */ + switch op { + case STOP, RETURN, SUICIDE: + closure.object.EachStorage(func(key string, value *ethutil.Value) { + value.Decode() + fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) + }) + } b := pc.Bytes() if len(b) == 0 { @@ -230,13 +228,15 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } if newMemSize.Cmp(ethutil.Big0) > 0 { - //newMemSize = (newMemSize + 31) / 32 * 32 - newMemSize = newMemSize.Add(newMemSize, u256(31)).Div(newMemSize, u256(32)).Mul(newMemSize, u256(32)) - //if newMemSize > uint64(mem.Len()) { + newMemSize.Add(newMemSize, u256(31)) + newMemSize.Div(newMemSize, u256(32)) + newMemSize.Mul(newMemSize, u256(32)) + if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { - newMemSize = newMemSize.Sub(newMemSize, u256(int64(mem.Len()))) - memGasUsage := newMemSize.Mul(GasMemory, newMemSize).Div(newMemSize, u256(32)) - //m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32 + memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len()))) + memGasUsage.Mul(GasMemory, memGasUsage) + memGasUsage.Div(memGasUsage, u256(32)) + addStepGasUsage(memGasUsage) } } @@ -669,12 +669,12 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { require(1) stack.Pop() case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: - n := int(op - DUP1) + n := int(op - DUP1 + 1) stack.Dupn(n) self.Printf(" => [%d] 0x%x", n, stack.Peek().Bytes()) case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: - n := int(op - SWAP1) + n := int(op - SWAP1 + 2) x, y := stack.Swapn(n) self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes()) @@ -694,12 +694,12 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => 0x%x", val) case MSTORE8: require(2) - val, mStart := stack.Popn() - //base.And(val, new(big.Int).SetInt64(0xff)) - //mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) - mem.store[mStart.Int64()] = byte(val.Int64() & 0xff) + off := stack.Pop() + val := stack.Pop() - self.Printf(" => 0x%x", val) + mem.store[off.Int64()] = byte(val.Int64() & 0xff) + + self.Printf(" => [%v] 0x%x", off, val) case SLOAD: require(1) loc := stack.Pop() @@ -955,6 +955,7 @@ func (self *Message) Addr() []byte { } func (self *Message) Exec(codeAddr []byte, caller ClosureRef) (ret []byte, err error) { + fmt.Printf("%x %x\n", codeAddr[0:4], self.address[0:4]) queue := self.vm.queue self.vm.queue = list.New() @@ -990,7 +991,7 @@ func (self *Message) Exec(codeAddr []byte, caller ClosureRef) (ret []byte, err e code := self.vm.env.State().GetCode(codeAddr) // Create a new callable closure - c := NewClosure(msg, caller, object, code, self.gas, self.price) + c := NewClosure(msg, caller, stateObject, code, self.gas, self.price) // Executer the closure and get the return value (if any) ret, _, err = c.Call(self.vm, self.input) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index 67a866f73..bee6dd526 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -282,8 +282,10 @@ func ReadMessages(conn net.Conn) (msgs []*Msg, err error) { var buff []byte var totalBytes int for { + // This is a bit of a cheat actually to make buffering extremely fast. + defer recover() // Give buffering some time - conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond)) + conn.SetReadDeadline(time.Now().Add(5 * time.Millisecond)) // Create a new temporarily buffer b := make([]byte, 1440) // Wait for a message from this peer diff --git a/peer.go b/peer.go index 32885aed8..69aa4b668 100644 --- a/peer.go +++ b/peer.go @@ -497,18 +497,16 @@ func (p *Peer) HandleInbound() { p.lastBlockReceived = time.Now() } + var err error blockPool.CheckLinkAndProcess(func(block *ethchain.Block) { - err := p.ethereum.StateManager().Process(block, false) - if err != nil { - peerlogger.Infoln(err) - } + err = p.ethereum.StateManager().Process(block, false) }) - /* - if !linked { - p.FetchBlocks() - } - */ + if err != nil { + peerlogger.Infoln(err) + } else { + p.FetchBlocks() + } } } } @@ -529,11 +527,10 @@ func (self *Peer) FetchHashes() { blockPool := self.ethereum.blockPool if self.td.Cmp(blockPool.td) >= 0 { - peerlogger.Debugf("Requesting hashes from %x\n", self.lastReceivedHash) blockPool.td = self.td if !blockPool.HasLatestHash() { - self.QueueMessage(ethwire.NewMessage(ethwire.MsgGetBlockHashesTy, []interface{}{self.lastReceivedHash, uint32(200)})) + self.QueueMessage(ethwire.NewMessage(ethwire.MsgGetBlockHashesTy, []interface{}{self.lastReceivedHash, uint32(256)})) } } } From d02024929a3e617c16c5b33e1d245f23fa4f6c7b Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 16 Sep 2014 11:35:26 +0200 Subject: [PATCH 38/58] require 5 for post --- ethereum.go | 3 +-- ethvm/vm.go | 11 +++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ethereum.go b/ethereum.go index 8d62fa9f2..fdfb59b09 100644 --- a/ethereum.go +++ b/ethereum.go @@ -23,8 +23,7 @@ import ( const ( seedTextFileUri string = "http://www.ethereum.org/servers.poc3.txt" - //seedNodeAddress = "54.76.56.74:30303" - seedNodeAddress = "localhost:30303" + seedNodeAddress = "54.76.56.74:30303" ) var ethlogger = ethlog.NewLogger("SERV") diff --git a/ethvm/vm.go b/ethvm/vm.go index cfba3820b..2a4fddbc5 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -63,7 +63,7 @@ func New(env Environment) *Vm { lt = LogTyDiff } - return &Vm{env: env, logTy: lt, Recoverable: false, queue: list.New()} + return &Vm{env: env, logTy: lt, Recoverable: true, queue: list.New()} } func calcMemSize(off, l *big.Int) *big.Int { @@ -200,7 +200,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) case CALLDATACOPY: - require(3) + require(2) newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) case CODECOPY: @@ -210,7 +210,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case EXTCODECOPY: require(4) - newMemSize = calcMemSize(stack.data[stack.Len()-1], stack.data[stack.Len()-4]) + newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4]) case CALL, CALLSTATELESS: require(7) gas.Set(GasCall) @@ -832,7 +832,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } case POST: - require(6) + require(5) self.Endl() @@ -872,6 +872,9 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { default: vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op) + // XXX Really? + closure.UseGas(closure.Gas) + return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) } From 74de0f1f2ab342466556baddbab166a284f86891 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 16 Sep 2014 16:06:38 +0200 Subject: [PATCH 39/58] Rewrote reading strategy --- ethwire/messaging.go | 251 ++++++++----------------------------------- 1 file changed, 43 insertions(+), 208 deletions(-) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index bee6dd526..99f6be8db 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -4,7 +4,6 @@ package ethwire import ( "bytes" - "errors" "fmt" "net" "time" @@ -78,194 +77,6 @@ func NewMessage(msgType MsgType, data interface{}) *Msg { type Messages []*Msg -// The connection object allows you to set up a connection to the Ethereum network. -// The Connection object takes care of all encoding and sending objects properly over -// the network. -type Connection struct { - conn net.Conn - nTimeout time.Duration - pendingMessages Messages -} - -// Create a new connection to the Ethereum network -func New(conn net.Conn) *Connection { - return &Connection{conn: conn, nTimeout: 500} -} - -// Read, reads from the network. It will block until the next message is received. -func (self *Connection) Read() *Msg { - if len(self.pendingMessages) == 0 { - self.readMessages() - } - - ret := self.pendingMessages[0] - self.pendingMessages = self.pendingMessages[1:] - - return ret - -} - -// Write to the Ethereum network specifying the type of the message and -// the data. Data can be of type RlpEncodable or []interface{}. Returns -// nil or if something went wrong an error. -func (self *Connection) Write(typ MsgType, v ...interface{}) error { - var pack []byte - - slice := [][]interface{}{[]interface{}{byte(typ)}} - for _, value := range v { - if encodable, ok := value.(ethutil.RlpEncodeDecode); ok { - slice = append(slice, encodable.RlpValue()) - } else if raw, ok := value.([]interface{}); ok { - slice = append(slice, raw) - } else { - panic(fmt.Sprintf("Unable to 'write' object of type %T", value)) - } - } - - // Encode the type and the (RLP encoded) data for sending over the wire - encoded := ethutil.NewValue(slice).Encode() - payloadLength := ethutil.NumberToBytes(uint32(len(encoded)), 32) - - // Write magic token and payload length (first 8 bytes) - pack = append(MagicToken, payloadLength...) - pack = append(pack, encoded...) - - // Write to the connection - _, err := self.conn.Write(pack) - if err != nil { - return err - } - - return nil -} - -func (self *Connection) readMessage(data []byte) (msg *Msg, remaining []byte, done bool, err error) { - if len(data) == 0 { - return nil, nil, true, nil - } - - if len(data) <= 8 { - return nil, remaining, false, errors.New("Invalid message") - } - - // Check if the received 4 first bytes are the magic token - if bytes.Compare(MagicToken, data[:4]) != 0 { - return nil, nil, false, fmt.Errorf("MagicToken mismatch. Received %v", data[:4]) - } - - messageLength := ethutil.BytesToNumber(data[4:8]) - remaining = data[8+messageLength:] - if int(messageLength) > len(data[8:]) { - return nil, nil, false, fmt.Errorf("message length %d, expected %d", len(data[8:]), messageLength) - } - - message := data[8 : 8+messageLength] - decoder := ethutil.NewValueFromBytes(message) - // Type of message - t := decoder.Get(0).Uint() - // Actual data - d := decoder.SliceFrom(1) - - msg = &Msg{ - Type: MsgType(t), - Data: d, - } - - return -} - -// The basic message reader waits for data on the given connection, decoding -// and doing a few sanity checks such as if there's a data type and -// unmarhals the given data -func (self *Connection) readMessages() (err error) { - // The recovering function in case anything goes horribly wrong - defer func() { - if r := recover(); r != nil { - err = fmt.Errorf("ethwire.ReadMessage error: %v", r) - } - }() - - // Buff for writing network message to - //buff := make([]byte, 1440) - var buff []byte - var totalBytes int - for { - // Give buffering some time - self.conn.SetReadDeadline(time.Now().Add(self.nTimeout * time.Millisecond)) - // Create a new temporarily buffer - b := make([]byte, 1440) - // Wait for a message from this peer - n, _ := self.conn.Read(b) - if err != nil && n == 0 { - if err.Error() != "EOF" { - fmt.Println("err now", err) - return err - } else { - break - } - - // Messages can't be empty - } else if n == 0 { - break - } - - buff = append(buff, b[:n]...) - totalBytes += n - } - - // Reslice buffer - buff = buff[:totalBytes] - msg, remaining, done, err := self.readMessage(buff) - for ; done != true; msg, remaining, done, err = self.readMessage(remaining) { - //log.Println("rx", msg) - - if msg != nil { - self.pendingMessages = append(self.pendingMessages, msg) - } - } - - return -} - -func ReadMessage(data []byte) (msg *Msg, remaining []byte, done bool, err error) { - if len(data) == 0 { - return nil, nil, true, nil - } - - if len(data) <= 8 { - return nil, remaining, false, errors.New("Invalid message") - } - - // Check if the received 4 first bytes are the magic token - if bytes.Compare(MagicToken, data[:4]) != 0 { - return nil, nil, false, fmt.Errorf("MagicToken mismatch. Received %v", data[:4]) - } - - messageLength := ethutil.BytesToNumber(data[4:8]) - remaining = data[8+messageLength:] - if int(messageLength) > len(data[8:]) { - return nil, nil, false, fmt.Errorf("message length %d, expected %d", len(data[8:]), messageLength) - } - - message := data[8 : 8+messageLength] - decoder := ethutil.NewValueFromBytes(message) - // Type of message - t := decoder.Get(0).Uint() - // Actual data - d := decoder.SliceFrom(1) - - msg = &Msg{ - Type: MsgType(t), - Data: d, - } - - return -} - -func bufferedRead(conn net.Conn) ([]byte, error) { - return nil, nil -} - // The basic message reader waits for data on the given connection, decoding // and doing a few sanity checks such as if there's a data type and // unmarhals the given data @@ -277,18 +88,17 @@ func ReadMessages(conn net.Conn) (msgs []*Msg, err error) { } }() - // Buff for writing network message to - //buff := make([]byte, 1440) - var buff []byte - var totalBytes int + var ( + buff []byte + messages [][]byte + msgLength int + ) + for { - // This is a bit of a cheat actually to make buffering extremely fast. - defer recover() // Give buffering some time conn.SetReadDeadline(time.Now().Add(5 * time.Millisecond)) // Create a new temporarily buffer b := make([]byte, 1440) - // Wait for a message from this peer n, _ := conn.Read(b) if err != nil && n == 0 { if err.Error() != "EOF" { @@ -297,25 +107,50 @@ func ReadMessages(conn net.Conn) (msgs []*Msg, err error) { } else { break } + } - // Messages can't be empty - } else if n == 0 { - break + if n == 0 { + continue + } + + if msgLength == 0 { + // Check if the received 4 first bytes are the magic token + if bytes.Compare(MagicToken, b[:4]) != 0 { + return nil, fmt.Errorf("MagicToken mismatch. Received %v", b[:4]) + } + + // Remove the token + b = b[4:] + // Read the length of the message + msgLength = int(ethutil.BytesToNumber(b[:4])) + + // Remove the length + b = b[4:] + + n -= 8 } buff = append(buff, b[:n]...) - totalBytes += n + + if len(buff) >= msgLength { + messages = append(messages, buff[:msgLength]) + buff = buff[msgLength:] + msgLength = 0 + + if len(buff) == 0 { + break + } + } } - // Reslice buffer - buff = buff[:totalBytes] - msg, remaining, done, err := ReadMessage(buff) - for ; done != true; msg, remaining, done, err = ReadMessage(remaining) { - //log.Println("rx", msg) + for _, m := range messages { + decoder := ethutil.NewValueFromBytes(m) + // Type of message + t := decoder.Get(0).Uint() + // Actual data + d := decoder.SliceFrom(1) - if msg != nil { - msgs = append(msgs, msg) - } + msgs = append(msgs, &Msg{Type: MsgType(t), Data: d}) } return From fb528c47c0c51a7a204a18227349e6500aba49ab Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 16 Sep 2014 16:19:48 +0200 Subject: [PATCH 40/58] Moved code --- ethwire/messages2.go | 199 +++++++++++++++++++++++++++++++++++++++++++ ethwire/messaging.go | 19 ++--- 2 files changed, 206 insertions(+), 12 deletions(-) create mode 100644 ethwire/messages2.go diff --git a/ethwire/messages2.go b/ethwire/messages2.go new file mode 100644 index 000000000..a52b79bd7 --- /dev/null +++ b/ethwire/messages2.go @@ -0,0 +1,199 @@ +package ethwire + +import ( + "bytes" + "errors" + "fmt" + "net" + "time" + + "github.com/ethereum/eth-go/ethutil" +) + +// The connection object allows you to set up a connection to the Ethereum network. +// The Connection object takes care of all encoding and sending objects properly over +// the network. +type Connection struct { + conn net.Conn + nTimeout time.Duration + pendingMessages Messages +} + +// Create a new connection to the Ethereum network +func New(conn net.Conn) *Connection { + return &Connection{conn: conn, nTimeout: 500} +} + +// Read, reads from the network. It will block until the next message is received. +func (self *Connection) Read() *Msg { + if len(self.pendingMessages) == 0 { + self.readMessages() + } + + ret := self.pendingMessages[0] + self.pendingMessages = self.pendingMessages[1:] + + return ret + +} + +// Write to the Ethereum network specifying the type of the message and +// the data. Data can be of type RlpEncodable or []interface{}. Returns +// nil or if something went wrong an error. +func (self *Connection) Write(typ MsgType, v ...interface{}) error { + var pack []byte + + slice := [][]interface{}{[]interface{}{byte(typ)}} + for _, value := range v { + if encodable, ok := value.(ethutil.RlpEncodeDecode); ok { + slice = append(slice, encodable.RlpValue()) + } else if raw, ok := value.([]interface{}); ok { + slice = append(slice, raw) + } else { + panic(fmt.Sprintf("Unable to 'write' object of type %T", value)) + } + } + + // Encode the type and the (RLP encoded) data for sending over the wire + encoded := ethutil.NewValue(slice).Encode() + payloadLength := ethutil.NumberToBytes(uint32(len(encoded)), 32) + + // Write magic token and payload length (first 8 bytes) + pack = append(MagicToken, payloadLength...) + pack = append(pack, encoded...) + + // Write to the connection + _, err := self.conn.Write(pack) + if err != nil { + return err + } + + return nil +} + +func (self *Connection) readMessage(data []byte) (msg *Msg, remaining []byte, done bool, err error) { + if len(data) == 0 { + return nil, nil, true, nil + } + + if len(data) <= 8 { + return nil, remaining, false, errors.New("Invalid message") + } + + // Check if the received 4 first bytes are the magic token + if bytes.Compare(MagicToken, data[:4]) != 0 { + return nil, nil, false, fmt.Errorf("MagicToken mismatch. Received %v", data[:4]) + } + + messageLength := ethutil.BytesToNumber(data[4:8]) + remaining = data[8+messageLength:] + if int(messageLength) > len(data[8:]) { + return nil, nil, false, fmt.Errorf("message length %d, expected %d", len(data[8:]), messageLength) + } + + message := data[8 : 8+messageLength] + decoder := ethutil.NewValueFromBytes(message) + // Type of message + t := decoder.Get(0).Uint() + // Actual data + d := decoder.SliceFrom(1) + + msg = &Msg{ + Type: MsgType(t), + Data: d, + } + + return +} + +// The basic message reader waits for data on the given connection, decoding +// and doing a few sanity checks such as if there's a data type and +// unmarhals the given data +func (self *Connection) readMessages() (err error) { + // The recovering function in case anything goes horribly wrong + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("ethwire.ReadMessage error: %v", r) + } + }() + + // Buff for writing network message to + //buff := make([]byte, 1440) + var buff []byte + var totalBytes int + for { + // Give buffering some time + self.conn.SetReadDeadline(time.Now().Add(self.nTimeout * time.Millisecond)) + // Create a new temporarily buffer + b := make([]byte, 1440) + // Wait for a message from this peer + n, _ := self.conn.Read(b) + if err != nil && n == 0 { + if err.Error() != "EOF" { + fmt.Println("err now", err) + return err + } else { + break + } + + // Messages can't be empty + } else if n == 0 { + break + } + + buff = append(buff, b[:n]...) + totalBytes += n + } + + // Reslice buffer + buff = buff[:totalBytes] + msg, remaining, done, err := self.readMessage(buff) + for ; done != true; msg, remaining, done, err = self.readMessage(remaining) { + //log.Println("rx", msg) + + if msg != nil { + self.pendingMessages = append(self.pendingMessages, msg) + } + } + + return +} + +func ReadMessage(data []byte) (msg *Msg, remaining []byte, done bool, err error) { + if len(data) == 0 { + return nil, nil, true, nil + } + + if len(data) <= 8 { + return nil, remaining, false, errors.New("Invalid message") + } + + // Check if the received 4 first bytes are the magic token + if bytes.Compare(MagicToken, data[:4]) != 0 { + return nil, nil, false, fmt.Errorf("MagicToken mismatch. Received %v", data[:4]) + } + + messageLength := ethutil.BytesToNumber(data[4:8]) + remaining = data[8+messageLength:] + if int(messageLength) > len(data[8:]) { + return nil, nil, false, fmt.Errorf("message length %d, expected %d", len(data[8:]), messageLength) + } + + message := data[8 : 8+messageLength] + decoder := ethutil.NewValueFromBytes(message) + // Type of message + t := decoder.Get(0).Uint() + // Actual data + d := decoder.SliceFrom(1) + + msg = &Msg{ + Type: MsgType(t), + Data: d, + } + + return +} + +func bufferedRead(conn net.Conn) ([]byte, error) { + return nil, nil +} diff --git a/ethwire/messaging.go b/ethwire/messaging.go index 99f6be8db..4f4393a9d 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -109,29 +109,24 @@ func ReadMessages(conn net.Conn) (msgs []*Msg, err error) { } } - if n == 0 { + if n == 0 && len(buff) == 0 { continue } + buff = append(buff, b[:n]...) if msgLength == 0 { // Check if the received 4 first bytes are the magic token - if bytes.Compare(MagicToken, b[:4]) != 0 { - return nil, fmt.Errorf("MagicToken mismatch. Received %v", b[:4]) + if bytes.Compare(MagicToken, buff[:4]) != 0 { + return nil, fmt.Errorf("MagicToken mismatch. Received %v", buff[:4]) } - // Remove the token - b = b[4:] // Read the length of the message - msgLength = int(ethutil.BytesToNumber(b[:4])) + msgLength = int(ethutil.BytesToNumber(buff[4:8])) - // Remove the length - b = b[4:] - - n -= 8 + // Remove the token and length + buff = buff[8:] } - buff = append(buff, b[:n]...) - if len(buff) >= msgLength { messages = append(messages, buff[:msgLength]) buff = buff[msgLength:] From 66e309c5c4fb1faebe7338053481024eeb55a2d1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 16 Sep 2014 16:36:18 +0200 Subject: [PATCH 41/58] Up deadline to reduce cpu load --- ethwire/messaging.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index 4f4393a9d..2161ce27f 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -96,7 +96,7 @@ func ReadMessages(conn net.Conn) (msgs []*Msg, err error) { for { // Give buffering some time - conn.SetReadDeadline(time.Now().Add(5 * time.Millisecond)) + conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) // Create a new temporarily buffer b := make([]byte, 1440) n, _ := conn.Read(b) From 1549a29c9d6452eefa615baedfccfc5b5f6b7745 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 16 Sep 2014 16:36:27 +0200 Subject: [PATCH 42/58] Connect to previous peer --- ethereum.go | 93 +++++++++++++++++++++++++++++++---------------------- peer.go | 12 +++++-- 2 files changed, 64 insertions(+), 41 deletions(-) diff --git a/ethereum.go b/ethereum.go index fdfb59b09..729f81926 100644 --- a/ethereum.go +++ b/ethereum.go @@ -2,9 +2,11 @@ package eth import ( "container/list" + "encoding/json" "fmt" "math/rand" "net" + "path" "strconv" "strings" "sync" @@ -31,9 +33,7 @@ var ethlogger = ethlog.NewLogger("SERV") func eachPeer(peers *list.List, callback func(*Peer, *list.Element)) { // Loop thru the peers and close them (if we had them) for e := peers.Front(); e != nil; e = e.Next() { - if peer, ok := e.Value.(*Peer); ok { - callback(peer, e) - } + callback(e.Value.(*Peer), e) } } @@ -399,47 +399,57 @@ func (s *Ethereum) Start(seed bool) { } func (s *Ethereum) Seed() { - ethlogger.Debugln("Retrieving seed nodes") - - // Eth-Go Bootstrapping - ips, er := net.LookupIP("seed.bysh.me") - if er == nil { - peers := []string{} + var ips []string + data, _ := ethutil.ReadAllFile(path.Join(ethutil.Config.ExecPath, "known_peers.json")) + json.Unmarshal([]byte(data), &ips) + if len(ips) > 0 { for _, ip := range ips { - node := fmt.Sprintf("%s:%d", ip.String(), 30303) - ethlogger.Debugln("Found DNS Go Peer:", node) - peers = append(peers, node) + ethlogger.Infoln("Connecting to previous peer ", ip) + s.ConnectToPeer(ip) } - s.ProcessPeerList(peers) - } + } else { + ethlogger.Debugln("Retrieving seed nodes") - // Official DNS Bootstrapping - _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") - if err == nil { - peers := []string{} - // Iterate SRV nodes - for _, n := range nodes { - target := n.Target - port := strconv.Itoa(int(n.Port)) - // Resolve target to ip (Go returns list, so may resolve to multiple ips?) - addr, err := net.LookupHost(target) - if err == nil { - for _, a := range addr { - // Build string out of SRV port and Resolved IP - peer := net.JoinHostPort(a, port) - ethlogger.Debugln("Found DNS Bootstrap Peer:", peer) - peers = append(peers, peer) - } - } else { - ethlogger.Debugln("Couldn't resolve :", target) + // Eth-Go Bootstrapping + ips, er := net.LookupIP("seed.bysh.me") + if er == nil { + peers := []string{} + for _, ip := range ips { + node := fmt.Sprintf("%s:%d", ip.String(), 30303) + ethlogger.Debugln("Found DNS Go Peer:", node) + peers = append(peers, node) } + s.ProcessPeerList(peers) } - // Connect to Peer list - s.ProcessPeerList(peers) - } - // XXX tmp - s.ConnectToPeer(seedNodeAddress) + // Official DNS Bootstrapping + _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") + if err == nil { + peers := []string{} + // Iterate SRV nodes + for _, n := range nodes { + target := n.Target + port := strconv.Itoa(int(n.Port)) + // Resolve target to ip (Go returns list, so may resolve to multiple ips?) + addr, err := net.LookupHost(target) + if err == nil { + for _, a := range addr { + // Build string out of SRV port and Resolved IP + peer := net.JoinHostPort(a, port) + ethlogger.Debugln("Found DNS Bootstrap Peer:", peer) + peers = append(peers, peer) + } + } else { + ethlogger.Debugln("Couldn't resolve :", target) + } + } + // Connect to Peer list + s.ProcessPeerList(peers) + } + + // XXX tmp + s.ConnectToPeer(seedNodeAddress) + } } func (s *Ethereum) peerHandler(listener net.Listener) { @@ -459,6 +469,13 @@ func (s *Ethereum) Stop() { // Close the database defer s.db.Close() + var ips []string + eachPeer(s.peers, func(p *Peer, e *list.Element) { + ips = append(ips, p.conn.RemoteAddr().String()) + }) + d, _ := json.MarshalIndent(ips, "", " ") + ethutil.WriteFile(path.Join(ethutil.Config.ExecPath, "known_peers.json"), d) + eachPeer(s.peers, func(p *Peer, e *list.Element) { p.Stop() }) diff --git a/peer.go b/peer.go index 69aa4b668..628953535 100644 --- a/peer.go +++ b/peer.go @@ -680,7 +680,7 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { var ( p2pVersion = c.Get(0).Uint() clientId = c.Get(1).Str() - caps = c.Get(2).Raw() + caps = c.Get(2) port = c.Get(3).Uint() pub = c.Get(4).Bytes() ) @@ -734,11 +734,17 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.ethereum.PushPeer(p) p.ethereum.reactor.Post("peerList", p.ethereum.Peers()) - ethlogger.Infof("Added peer (%s) %d / %d (%v)\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers, caps) + ethlogger.Infof("Added peer (%s) %d / %d (%v)\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers, caps.Raw()) peerlogger.Debugln(p) - p.pushStatus() + capsIt := caps.NewIterator() + for capsIt.Next() { + switch capsIt.Value().Str() { + case "eth": + p.pushStatus() + } + } } func (p *Peer) String() string { From fd041d91ee9f4be2d4705a32dc16698c89622c85 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 17 Sep 2014 15:57:07 +0200 Subject: [PATCH 43/58] Truncate when writing --- ethutil/path.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/path.go b/ethutil/path.go index 27022bcfa..cfbc38950 100644 --- a/ethutil/path.go +++ b/ethutil/path.go @@ -45,7 +45,7 @@ func ReadAllFile(filePath string) (string, error) { } func WriteFile(filePath string, content []byte) error { - fh, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, os.ModePerm) + fh, err := os.OpenFile(filePath, os.O_TRUNC|os.O_RDWR|os.O_CREATE, os.ModePerm) if err != nil { return err } From eb32fe20c8513b936faf908985d021caa87d5b0d Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 17 Sep 2014 15:57:32 +0200 Subject: [PATCH 44/58] Rewrite --- ethwire/messaging.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index 2161ce27f..b1cefc0ae 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -96,7 +96,7 @@ func ReadMessages(conn net.Conn) (msgs []*Msg, err error) { for { // Give buffering some time - conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + conn.SetReadDeadline(time.Now().Add(5 * time.Millisecond)) // Create a new temporarily buffer b := make([]byte, 1440) n, _ := conn.Read(b) @@ -110,6 +110,9 @@ func ReadMessages(conn net.Conn) (msgs []*Msg, err error) { } if n == 0 && len(buff) == 0 { + // If there's nothing on the wire wait for a bit + time.Sleep(200) + continue } From 9559b5322857edfc819f7888a791d4f2a396fd17 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 17 Sep 2014 15:57:44 +0200 Subject: [PATCH 45/58] Added Past peers option --- ethereum.go | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/ethereum.go b/ethereum.go index 729f81926..4cf1ce9e7 100644 --- a/ethereum.go +++ b/ethereum.go @@ -399,9 +399,7 @@ func (s *Ethereum) Start(seed bool) { } func (s *Ethereum) Seed() { - var ips []string - data, _ := ethutil.ReadAllFile(path.Join(ethutil.Config.ExecPath, "known_peers.json")) - json.Unmarshal([]byte(data), &ips) + ips := PastPeers() if len(ips) > 0 { for _, ip := range ips { ethlogger.Infoln("Connecting to previous peer ", ip) @@ -473,8 +471,11 @@ func (s *Ethereum) Stop() { eachPeer(s.peers, func(p *Peer, e *list.Element) { ips = append(ips, p.conn.RemoteAddr().String()) }) - d, _ := json.MarshalIndent(ips, "", " ") - ethutil.WriteFile(path.Join(ethutil.Config.ExecPath, "known_peers.json"), d) + + if len(ips) > 0 { + d, _ := json.MarshalIndent(ips, "", " ") + ethutil.WriteFile(path.Join(ethutil.Config.ExecPath, "known_peers.json"), d) + } eachPeer(s.peers, func(p *Peer, e *list.Element) { p.Stop() @@ -620,3 +621,11 @@ func bootstrapDb(db ethutil.Database) { db.Put([]byte("ProtocolVersion"), ethutil.NewValue(ProtocolVersion).Bytes()) } } + +func PastPeers() []string { + var ips []string + data, _ := ethutil.ReadAllFile(path.Join(ethutil.Config.ExecPath, "known_peers.json")) + json.Unmarshal([]byte(data), &ips) + + return ips +} From a26c479182375a076833068aa6125724fda647fe Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 17 Sep 2014 15:58:02 +0200 Subject: [PATCH 46/58] Added len --- block_pool.go | 4 ++++ peer.go | 50 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/block_pool.go b/block_pool.go index 0a668e111..6753308b6 100644 --- a/block_pool.go +++ b/block_pool.go @@ -33,6 +33,10 @@ func NewBlockPool(eth *Ethereum) *BlockPool { } } +func (self *BlockPool) Len() int { + return len(self.hashPool) +} + func (self *BlockPool) HasLatestHash() bool { return self.pool[string(self.eth.BlockChain().CurrentBlock.Hash())] != nil } diff --git a/peer.go b/peer.go index 628953535..aae84f0c0 100644 --- a/peer.go +++ b/peer.go @@ -287,7 +287,7 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { */ } - peerlogger.DebugDetailf("(%v) <= %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data) + peerlogger.DebugDetailf("(%v) <= %v\n", p.conn.RemoteAddr(), formatMessage(msg)) err := ethwire.WriteMessage(p.conn, msg) if err != nil { @@ -351,6 +351,27 @@ clean: } } +func formatMessage(msg *ethwire.Msg) (ret string) { + ret = fmt.Sprintf("%v ", msg.Type) + + /* + XXX Commented out because I need the log level here to determine + if i should or shouldn't generate this message + */ + switch msg.Type { + case ethwire.MsgPeersTy: + ret += fmt.Sprintf("(%d entries)", msg.Data.Len()) + case ethwire.MsgBlockTy: + b1, b2 := ethchain.NewBlockFromRlpValue(msg.Data.Get(0)), ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len()-1)) + ret += fmt.Sprintf("(%d entries) %x - %x", msg.Data.Len(), b1.Hash()[0:4], b2.Hash()[0:4]) + case ethwire.MsgBlockHashesTy: + h1, h2 := msg.Data.Get(0).Bytes(), msg.Data.Get(msg.Data.Len()-1).Bytes() + ret += fmt.Sprintf("(%d entries) %x - %x", msg.Data.Len(), h1[0:4], h2[0:4]) + } + + return +} + // Inbound handler. Inbound messages are received here and passed to the appropriate methods func (p *Peer) HandleInbound() { for atomic.LoadInt32(&p.disconnect) == 0 { @@ -363,7 +384,7 @@ func (p *Peer) HandleInbound() { peerlogger.Debugln(err) } for _, msg := range msgs { - peerlogger.DebugDetailf("(%v) => %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data) + peerlogger.DebugDetailf("(%v) => %v\n", p.conn.RemoteAddr(), formatMessage(msg)) switch msg.Type { case ethwire.MsgHandshakeTy: @@ -505,7 +526,10 @@ func (p *Peer) HandleInbound() { if err != nil { peerlogger.Infoln(err) } else { - p.FetchBlocks() + // Don't trigger if there's just one block. + if blockPool.Len() != 0 && msg.Data.Len() > 1 { + p.FetchBlocks() + } } } } @@ -643,7 +667,11 @@ func (self *Peer) handleStatus(msg *ethwire.Msg) { bestHash = c.Get(3).Bytes() genesis = c.Get(4).Bytes() ) - ethlogger.Infof("gen = %x\n", genesis) + + if bytes.Compare(self.ethereum.BlockChain().Genesis().Hash(), genesis) != 0 { + ethlogger.Warnf("Invalid genisis hash %x. Disabling [ETH]\n", genesis) + return + } // Get the td and last hash self.td = td @@ -734,17 +762,21 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.ethereum.PushPeer(p) p.ethereum.reactor.Post("peerList", p.ethereum.Peers()) - ethlogger.Infof("Added peer (%s) %d / %d (%v)\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers, caps.Raw()) - - peerlogger.Debugln(p) - capsIt := caps.NewIterator() + var capsStrs []string for capsIt.Next() { - switch capsIt.Value().Str() { + cap := capsIt.Value().Str() + switch cap { case "eth": p.pushStatus() } + + capsStrs = append(capsStrs, cap) } + + ethlogger.Infof("Added peer (%s) %d / %d (%v)\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers, capsStrs) + + peerlogger.Debugln(p) } func (p *Peer) String() string { From b3834d8272915d6b96d69a91ad6b9f994b29e891 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 17 Sep 2014 16:28:30 +0200 Subject: [PATCH 47/58] Removed extra slash so @nicksavers gets off my back ;-) --- ethwire/client_identity.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/ethwire/client_identity.go b/ethwire/client_identity.go index e803406d8..4e4f854ba 100644 --- a/ethwire/client_identity.go +++ b/ethwire/client_identity.go @@ -11,7 +11,6 @@ type ClientIdentity interface { } type SimpleClientIdentity struct { - clientString string clientIdentifier string version string customIdentifier string @@ -27,26 +26,29 @@ func NewSimpleClientIdentity(clientIdentifier string, version string, customIden os: runtime.GOOS, implementation: "Go", } - clientIdentity.init() + return clientIdentity } func (c *SimpleClientIdentity) init() { - c.clientString = fmt.Sprintf("%s/v%s/%s/%s/%s", +} + +func (c *SimpleClientIdentity) String() string { + var id string + if len(c.customIdentifier) > 0 { + id = "/" + c.customIdentifier + } + + return fmt.Sprintf("%s/v%s%s/%s/%s", c.clientIdentifier, c.version, - c.customIdentifier, + id, c.os, c.implementation) } -func (c *SimpleClientIdentity) String() string { - return c.clientString -} - func (c *SimpleClientIdentity) SetCustomIdentifier(customIdentifier string) { c.customIdentifier = customIdentifier - c.init() } func (c *SimpleClientIdentity) GetCustomIdentifier() string { From f3a93b046e45a293b673a955959666ec5389c4eb Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 18 Sep 2014 01:02:15 +0200 Subject: [PATCH 48/58] Upped protocol version for VM change --- ethchain/fees.go | 2 - ethtrie/trie.go | 7 ++ ethvm/vm.go | 3 +- ethwire/client_identity.go | 2 +- peer.go | 193 +++++++++++++++++++++---------------- 5 files changed, 118 insertions(+), 89 deletions(-) diff --git a/ethchain/fees.go b/ethchain/fees.go index 743be86a2..901357439 100644 --- a/ethchain/fees.go +++ b/ethchain/fees.go @@ -5,5 +5,3 @@ import ( ) var BlockReward *big.Int = big.NewInt(1.5e+18) -var UncleReward *big.Int = big.NewInt(1.125e+18) -var UncleInclusionReward *big.Int = big.NewInt(1.875e+17) diff --git a/ethtrie/trie.go b/ethtrie/trie.go index 38ae0754d..e6e09dd0d 100644 --- a/ethtrie/trie.go +++ b/ethtrie/trie.go @@ -92,6 +92,13 @@ func (cache *Cache) Get(key []byte) *ethutil.Value { data, _ := cache.db.Get(key) // Create the cached value value := ethutil.NewValueFromBytes(data) + + defer func() { + if r := recover(); r != nil { + fmt.Println("RECOVER GET", cache, cache.nodes) + panic("bye") + } + }() // Create caching node cache.nodes[string(key)] = NewNode(key, value, false) diff --git a/ethvm/vm.go b/ethvm/vm.go index 2a4fddbc5..f1c23b370 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -872,8 +872,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { default: vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op) - // XXX Really? - closure.UseGas(closure.Gas) + //panic(fmt.Sprintf("Invalid opcode %x", op)) return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) } diff --git a/ethwire/client_identity.go b/ethwire/client_identity.go index 4e4f854ba..ceaa9fe83 100644 --- a/ethwire/client_identity.go +++ b/ethwire/client_identity.go @@ -24,7 +24,7 @@ func NewSimpleClientIdentity(clientIdentifier string, version string, customIden version: version, customIdentifier: customIdentifier, os: runtime.GOOS, - implementation: "Go", + implementation: runtime.Version(), } return clientIdentity diff --git a/peer.go b/peer.go index aae84f0c0..8c04864d0 100644 --- a/peer.go +++ b/peer.go @@ -24,9 +24,11 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 32 + ProtocolVersion = 33 // Current P2P version P2PVersion = 0 + // Ethereum network version + NetVersion = 0 // Interval for ping/pong message pingPongTimer = 2 * time.Second ) @@ -72,7 +74,7 @@ func (d DiscReason) String() string { type Caps byte const ( - CapPeerDiscTy = 1 << iota + CapPeerDiscTy Caps = 1 << iota CapTxTy CapChainTy @@ -309,6 +311,14 @@ out: select { // Main message queue. All outbound messages are processed through here case msg := <-p.outputQueue: + if !p.statusKnown { + switch msg.Type { + case ethwire.MsgGetTxsTy, ethwire.MsgGetBlockHashesTy, ethwire.MsgGetBlocksTy, ethwire.MsgBlockHashesTy, ethwire.MsgBlockTy: + peerlogger.Debugln("Blocked outgoing [eth] message to peer without the [eth] cap.") + break + } + } + p.writeMessage(msg) p.lastSend = time.Now() @@ -435,100 +445,106 @@ func (p *Peer) HandleInbound() { case ethwire.MsgStatusTy: // Handle peer's status msg p.handleStatus(msg) - case ethwire.MsgGetTxsTy: - // Get the current transactions of the pool - txs := p.ethereum.TxPool().CurrentTransactions() - // Get the RlpData values from the txs - txsInterface := make([]interface{}, len(txs)) - for i, tx := range txs { - txsInterface[i] = tx.RlpData() - } - // Broadcast it back to the peer - p.QueueMessage(ethwire.NewMessage(ethwire.MsgTxTy, txsInterface)) + } - case ethwire.MsgGetBlockHashesTy: - if msg.Data.Len() < 2 { - peerlogger.Debugln("err: argument length invalid ", msg.Data.Len()) - } - - hash := msg.Data.Get(0).Bytes() - amount := msg.Data.Get(1).Uint() - - hashes := p.ethereum.BlockChain().GetChainHashesFromHash(hash, amount) - - p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockHashesTy, ethutil.ByteSliceToInterface(hashes))) - - case ethwire.MsgGetBlocksTy: - // Limit to max 300 blocks - max := int(math.Min(float64(msg.Data.Len()), 300.0)) - var blocks []interface{} - - for i := 0; i < max; i++ { - hash := msg.Data.Get(i).Bytes() - block := p.ethereum.BlockChain().GetBlock(hash) - if block != nil { - blocks = append(blocks, block.Value().Raw()) + // TMP + if p.statusKnown { + switch msg.Type { + case ethwire.MsgGetTxsTy: + // Get the current transactions of the pool + txs := p.ethereum.TxPool().CurrentTransactions() + // Get the RlpData values from the txs + txsInterface := make([]interface{}, len(txs)) + for i, tx := range txs { + txsInterface[i] = tx.RlpData() } - } + // Broadcast it back to the peer + p.QueueMessage(ethwire.NewMessage(ethwire.MsgTxTy, txsInterface)) - p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, blocks)) - - case ethwire.MsgBlockHashesTy: - p.catchingUp = true - - blockPool := p.ethereum.blockPool - - foundCommonHash := false - - it := msg.Data.NewIterator() - for it.Next() { - hash := it.Value().Bytes() - - if blockPool.HasCommonHash(hash) { - foundCommonHash = true - - break + case ethwire.MsgGetBlockHashesTy: + if msg.Data.Len() < 2 { + peerlogger.Debugln("err: argument length invalid ", msg.Data.Len()) } - blockPool.AddHash(hash) + hash := msg.Data.Get(0).Bytes() + amount := msg.Data.Get(1).Uint() - p.lastReceivedHash = hash + hashes := p.ethereum.BlockChain().GetChainHashesFromHash(hash, amount) - p.lastBlockReceived = time.Now() - } + p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockHashesTy, ethutil.ByteSliceToInterface(hashes))) - if foundCommonHash { - p.FetchBlocks() - } else { - p.FetchHashes() - } + case ethwire.MsgGetBlocksTy: + // Limit to max 300 blocks + max := int(math.Min(float64(msg.Data.Len()), 300.0)) + var blocks []interface{} - case ethwire.MsgBlockTy: - p.catchingUp = true + for i := 0; i < max; i++ { + hash := msg.Data.Get(i).Bytes() + block := p.ethereum.BlockChain().GetBlock(hash) + if block != nil { + blocks = append(blocks, block.Value().Raw()) + } + } - blockPool := p.ethereum.blockPool + p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, blocks)) - it := msg.Data.NewIterator() - for it.Next() { - block := ethchain.NewBlockFromRlpValue(it.Value()) - //fmt.Printf("%v %x - %x\n", block.Number, block.Hash()[0:4], block.PrevHash[0:4]) + case ethwire.MsgBlockHashesTy: + p.catchingUp = true - blockPool.SetBlock(block, p) + blockPool := p.ethereum.blockPool - p.lastBlockReceived = time.Now() - } + foundCommonHash := false - var err error - blockPool.CheckLinkAndProcess(func(block *ethchain.Block) { - err = p.ethereum.StateManager().Process(block, false) - }) + it := msg.Data.NewIterator() + for it.Next() { + hash := it.Value().Bytes() - if err != nil { - peerlogger.Infoln(err) - } else { - // Don't trigger if there's just one block. - if blockPool.Len() != 0 && msg.Data.Len() > 1 { + if blockPool.HasCommonHash(hash) { + foundCommonHash = true + + break + } + + blockPool.AddHash(hash) + + p.lastReceivedHash = hash + + p.lastBlockReceived = time.Now() + } + + if foundCommonHash { p.FetchBlocks() + } else { + p.FetchHashes() + } + + case ethwire.MsgBlockTy: + p.catchingUp = true + + blockPool := p.ethereum.blockPool + + it := msg.Data.NewIterator() + for it.Next() { + block := ethchain.NewBlockFromRlpValue(it.Value()) + //fmt.Printf("%v %x - %x\n", block.Number, block.Hash()[0:4], block.PrevHash[0:4]) + + blockPool.SetBlock(block, p) + + p.lastBlockReceived = time.Now() + } + + var err error + blockPool.CheckLinkAndProcess(func(block *ethchain.Block) { + err = p.ethereum.StateManager().Process(block, false) + }) + + if err != nil { + peerlogger.Infoln(err) + } else { + // Don't trigger if there's just one block. + if blockPool.Len() != 0 && msg.Data.Len() > 1 { + p.FetchBlocks() + } } } } @@ -645,10 +661,9 @@ func (p *Peer) pushPeers() { } func (self *Peer) pushStatus() { - const netVersion = 0 msg := ethwire.NewMessage(ethwire.MsgStatusTy, []interface{}{ uint32(ProtocolVersion), - uint32(netVersion), + uint32(NetVersion), self.ethereum.BlockChain().TD, self.ethereum.BlockChain().CurrentBlock.Hash(), self.ethereum.BlockChain().Genesis().Hash(), @@ -669,7 +684,17 @@ func (self *Peer) handleStatus(msg *ethwire.Msg) { ) if bytes.Compare(self.ethereum.BlockChain().Genesis().Hash(), genesis) != 0 { - ethlogger.Warnf("Invalid genisis hash %x. Disabling [ETH]\n", genesis) + ethlogger.Warnf("Invalid genisis hash %x. Disabling [eth]\n", genesis) + return + } + + if netVersion != NetVersion { + ethlogger.Warnf("Invalid network version %d. Disabling [eth]\n", netVersion) + return + } + + if protoVersion != ProtocolVersion { + ethlogger.Warnf("Invalid protocol version %d. Disabling [eth]\n", protoVersion) return } @@ -687,7 +712,7 @@ func (self *Peer) handleStatus(msg *ethwire.Msg) { self.FetchHashes() } - ethlogger.Infof("Peer is [ETH] capable. (TD = %v ~ %x) %d / %d", self.td, self.bestHash, protoVersion, netVersion) + ethlogger.Infof("Peer is [eth] capable. (TD = %v ~ %x) %d / %d", self.td, self.bestHash, protoVersion, netVersion) } From 863785a52046bcfbbcaa57c83b4b43c215368760 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 18 Sep 2014 16:48:42 +0200 Subject: [PATCH 49/58] Updated opcodes --- ethchain/types.go | 244 ++++++++++++++++++++-------------------------- 1 file changed, 106 insertions(+), 138 deletions(-) diff --git a/ethchain/types.go b/ethchain/types.go index 9e7269f74..45486b06c 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -27,10 +27,12 @@ const ( NOT = 0x0f // 0x10 range - bit ops - AND = 0x10 - OR = 0x11 - XOR = 0x12 - BYTE = 0x13 + AND = 0x10 + OR = 0x11 + XOR = 0x12 + BYTE = 0x13 + ADDMOD = 0x14 + MULMOD = 0x15 // 0x20 range - crypto SHA3 = 0x20 @@ -47,6 +49,8 @@ const ( CODESIZE = 0x38 CODECOPY = 0x39 GASPRICE = 0x3a + EXTCODECOPY = 0x3b + EXTCODESIZE = 0x3c // 0x40 range - block operations PREVHASH = 0x40 @@ -57,9 +61,9 @@ const ( GASLIMIT = 0x45 // 0x50 range - 'storage' and execution - POP = 0x50 - DUP = 0x51 - SWAP = 0x52 + POP = 0x50 + //DUP = 0x51 + //SWAP = 0x52 MLOAD = 0x53 MSTORE = 0x54 MSTORE8 = 0x55 @@ -105,10 +109,46 @@ const ( PUSH31 = 0x7e PUSH32 = 0x7f + DUP1 = 0x80 + DUP2 = 0x81 + DUP3 = 0x82 + DUP4 = 0x83 + DUP5 = 0x84 + DUP6 = 0x85 + DUP7 = 0x86 + DUP8 = 0x87 + DUP9 = 0x88 + DUP10 = 0x89 + DUP11 = 0x8a + DUP12 = 0x8b + DUP13 = 0x8c + DUP14 = 0x8d + DUP15 = 0x8e + DUP16 = 0x8f + + SWAP1 = 0x90 + SWAP2 = 0x91 + SWAP3 = 0x92 + SWAP4 = 0x93 + SWAP5 = 0x94 + SWAP6 = 0x95 + SWAP7 = 0x96 + SWAP8 = 0x97 + SWAP9 = 0x98 + SWAP10 = 0x99 + SWAP11 = 0x9a + SWAP12 = 0x9b + SWAP13 = 0x9c + SWAP14 = 0x9d + SWAP15 = 0x9e + SWAP16 = 0x9f + // 0xf0 range - closures - CREATE = 0xf0 - CALL = 0xf1 - RETURN = 0xf2 + CREATE = 0xf0 + CALL = 0xf1 + RETURN = 0xf2 + POST = 0xf3 + CALLSTATELESS = 0xf4 // 0x70 range - other LOG = 0xfe // XXX Unofficial @@ -136,10 +176,12 @@ var opCodeToString = map[OpCode]string{ NOT: "NOT", // 0x10 range - bit ops - AND: "AND", - OR: "OR", - XOR: "XOR", - BYTE: "BYTE", + AND: "AND", + OR: "OR", + XOR: "XOR", + BYTE: "BYTE", + ADDMOD: "ADDMOD", + MULMOD: "MULMOD", // 0x20 range - crypto SHA3: "SHA3", @@ -158,17 +200,19 @@ var opCodeToString = map[OpCode]string{ GASPRICE: "TXGASPRICE", // 0x40 range - block operations - PREVHASH: "PREVHASH", - COINBASE: "COINBASE", - TIMESTAMP: "TIMESTAMP", - NUMBER: "NUMBER", - DIFFICULTY: "DIFFICULTY", - GASLIMIT: "GASLIMIT", + PREVHASH: "PREVHASH", + COINBASE: "COINBASE", + TIMESTAMP: "TIMESTAMP", + NUMBER: "NUMBER", + DIFFICULTY: "DIFFICULTY", + GASLIMIT: "GASLIMIT", + EXTCODESIZE: "EXTCODESIZE", + EXTCODECOPY: "EXTCODECOPY", // 0x50 range - 'storage' and execution - POP: "POP", - DUP: "DUP", - SWAP: "SWAP", + POP: "POP", + //DUP: "DUP", + //SWAP: "SWAP", MLOAD: "MLOAD", MSTORE: "MSTORE", MSTORE8: "MSTORE8", @@ -214,10 +258,46 @@ var opCodeToString = map[OpCode]string{ PUSH31: "PUSH31", PUSH32: "PUSH32", + DUP1: "DUP1", + DUP2: "DUP2", + DUP3: "DUP3", + DUP4: "DUP4", + DUP5: "DUP5", + DUP6: "DUP6", + DUP7: "DUP7", + DUP8: "DUP8", + DUP9: "DUP9", + DUP10: "DUP10", + DUP11: "DUP11", + DUP12: "DUP12", + DUP13: "DUP13", + DUP14: "DUP14", + DUP15: "DUP15", + DUP16: "DUP16", + + SWAP1: "SWAP1", + SWAP2: "SWAP2", + SWAP3: "SWAP3", + SWAP4: "SWAP4", + SWAP5: "SWAP5", + SWAP6: "SWAP6", + SWAP7: "SWAP7", + SWAP8: "SWAP8", + SWAP9: "SWAP9", + SWAP10: "SWAP10", + SWAP11: "SWAP11", + SWAP12: "SWAP12", + SWAP13: "SWAP13", + SWAP14: "SWAP14", + SWAP15: "SWAP15", + SWAP16: "SWAP16", + // 0xf0 range - CREATE: "CREATE", - CALL: "CALL", - RETURN: "RETURN", + CREATE: "CREATE", + CALL: "CALL", + RETURN: "RETURN", + POST: "POST", + CALLSTATELESS: "CALLSTATELESS", // 0x70 range - other LOG: "LOG", @@ -232,115 +312,3 @@ func (o OpCode) String() string { return str } - -// Op codes for assembling -var OpCodes = map[string]byte{ - // 0x0 range - arithmetic ops - "STOP": 0x00, - "ADD": 0x01, - "MUL": 0x02, - "SUB": 0x03, - "DIV": 0x04, - "SDIV": 0x05, - "MOD": 0x06, - "SMOD": 0x07, - "EXP": 0x08, - "NEG": 0x09, - "LT": 0x0a, - "GT": 0x0b, - "EQ": 0x0c, - "NOT": 0x0d, - - // 0x10 range - bit ops - "AND": 0x10, - "OR": 0x11, - "XOR": 0x12, - "BYTE": 0x13, - - // 0x20 range - crypto - "SHA3": 0x20, - - // 0x30 range - closure state - "ADDRESS": 0x30, - "BALANCE": 0x31, - "ORIGIN": 0x32, - "CALLER": 0x33, - "CALLVALUE": 0x34, - "CALLDATALOAD": 0x35, - "CALLDATASIZE": 0x36, - "GASPRICE": 0x38, - - // 0x40 range - block operations - "PREVHASH": 0x40, - "COINBASE": 0x41, - "TIMESTAMP": 0x42, - "NUMBER": 0x43, - "DIFFICULTY": 0x44, - "GASLIMIT": 0x45, - - // 0x50 range - 'storage' and execution - "POP": 0x51, - "DUP": 0x52, - "SWAP": 0x53, - "MLOAD": 0x54, - "MSTORE": 0x55, - "MSTORE8": 0x56, - "SLOAD": 0x57, - "SSTORE": 0x58, - "JUMP": 0x59, - "JUMPI": 0x5a, - "PC": 0x5b, - "MSIZE": 0x5c, - - // 0x70 range - 'push' - "PUSH1": 0x60, - "PUSH2": 0x61, - "PUSH3": 0x62, - "PUSH4": 0x63, - "PUSH5": 0x64, - "PUSH6": 0x65, - "PUSH7": 0x66, - "PUSH8": 0x67, - "PUSH9": 0x68, - "PUSH10": 0x69, - "PUSH11": 0x6a, - "PUSH12": 0x6b, - "PUSH13": 0x6c, - "PUSH14": 0x6d, - "PUSH15": 0x6e, - "PUSH16": 0x6f, - "PUSH17": 0x70, - "PUSH18": 0x71, - "PUSH19": 0x72, - "PUSH20": 0x73, - "PUSH21": 0x74, - "PUSH22": 0x75, - "PUSH23": 0x76, - "PUSH24": 0x77, - "PUSH25": 0x78, - "PUSH26": 0x70, - "PUSH27": 0x7a, - "PUSH28": 0x7b, - "PUSH29": 0x7c, - "PUSH30": 0x7d, - "PUSH31": 0x7e, - "PUSH32": 0x7f, - - // 0xf0 range - closures - "CREATE": 0xf0, - "CALL": 0xf1, - "RETURN": 0xf2, - - // 0x70 range - other - "LOG": 0xfe, - "SUICIDE": 0x7f, -} - -func IsOpCode(s string) bool { - for key, _ := range OpCodes { - if key == s { - return true - } - } - return false -} From 80261c803a82e51413608a3dc5273c982844d135 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 19 Sep 2014 13:19:19 +0200 Subject: [PATCH 50/58] Fixed deref ptr --- ethchain/block_chain.go | 8 ++++++-- ethutil/rlp.go | 4 ++++ ethvm/vm.go | 17 ++++++++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 1e29f1188..7c9b60fc5 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -164,6 +164,7 @@ func (bc *BlockChain) setLastBlock() { bc.Add(bc.genesisBlock) fk := append([]byte("bloom"), bc.genesisBlock.Hash()...) bc.Ethereum.Db().Put(fk, make([]byte, 255)) + bc.CurrentBlock = bc.genesisBlock } // Set the last know difficulty (might be 0x0 as initial value, Genesis) @@ -201,10 +202,13 @@ func (bc *BlockChain) GetBlock(hash []byte) *Block { func (self *BlockChain) GetBlockByNumber(num uint64) *Block { block := self.CurrentBlock - for ; block.Number.Uint64() != num; block = self.GetBlock(block.PrevHash) { + for ; block != nil; block = self.GetBlock(block.PrevHash) { + if block.Number.Uint64() == num { + break + } } - if block.Number.Uint64() == 0 && num != 0 { + if block != nil && block.Number.Uint64() == 0 && num != 0 { return nil } diff --git a/ethutil/rlp.go b/ethutil/rlp.go index febfb78e1..55406133b 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -15,6 +15,10 @@ type RlpEncodeDecode interface { RlpValue() []interface{} } +func Rlp(encoder RlpEncode) []byte { + return encoder.RlpEncode() +} + type RlpEncoder struct { rlpData []byte } diff --git a/ethvm/vm.go b/ethvm/vm.go index f1c23b370..7aff320f9 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -670,9 +670,13 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Pop() case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: n := int(op - DUP1 + 1) - stack.Dupn(n) + v := stack.Dupn(n) self.Printf(" => [%d] 0x%x", n, stack.Peek().Bytes()) + + if OpCode(closure.Get(new(big.Int).Add(pc, ethutil.Big1)).Uint()) == POP && OpCode(closure.Get(new(big.Int).Add(pc, big.NewInt(2))).Uint()) == POP { + fmt.Println(toValue(v)) + } case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: n := int(op - SWAP1 + 2) x, y := stack.Swapn(n) @@ -1004,3 +1008,14 @@ func (self *Message) Exec(codeAddr []byte, caller ClosureRef) (ret []byte, err e return } + +// Mainly used for print variables and passing to Print* +func toValue(val *big.Int) interface{} { + // Let's assume a string on right padded zero's + b := val.Bytes() + if b[0] != 0 && b[len(b)-1] == 0x0 && b[len(b)-2] == 0x0 { + return string(b) + } + + return val +} From 151f9c7f8214a2702a76f36f566b52266949ac89 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 22 Sep 2014 14:50:53 +0200 Subject: [PATCH 51/58] BigInt accept string --- ethutil/value.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethutil/value.go b/ethutil/value.go index e8148b990..b1f887f29 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -118,6 +118,8 @@ func (val *Value) BigInt() *big.Int { return b } else if a, ok := val.Val.(*big.Int); ok { return a + } else if a, ok := val.Val.(string); ok { + return Big(a) } else { return big.NewInt(int64(val.Uint())) } From 65a802c6787184951753ba2f79fdf60dce526721 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 22 Sep 2014 14:51:21 +0200 Subject: [PATCH 52/58] Re-wrote Call and Execute to use the new vm messages --- ethpipe/js_pipe.go | 30 +++++++++++++++++++++++------- ethpipe/pipe.go | 30 ++++++++++++++++-------------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go index 32212b26a..96990b671 100644 --- a/ethpipe/js_pipe.go +++ b/ethpipe/js_pipe.go @@ -85,10 +85,6 @@ func (self *JSPipe) CoinBase() string { return ethutil.Bytes2Hex(self.obj.KeyManager().Address()) } -func (self *JSPipe) BalanceAt(addr string) string { - return self.World().SafeGet(ethutil.Hex2Bytes(addr)).Balance.String() -} - func (self *JSPipe) NumberToHuman(balance string) string { b := ethutil.Big(balance) @@ -101,10 +97,18 @@ func (self *JSPipe) StorageAt(addr, storageAddr string) string { return ethutil.Bytes2Hex(storage.Bytes()) } +func (self *JSPipe) BalanceAt(addr string) string { + return self.World().SafeGet(ethutil.Hex2Bytes(addr)).Balance.String() +} + func (self *JSPipe) TxCountAt(address string) int { return int(self.World().SafeGet(ethutil.Hex2Bytes(address)).Nonce) } +func (self *JSPipe) CodeAt(address string) string { + return ethutil.Bytes2Hex(self.World().SafeGet(ethutil.Hex2Bytes(address)).Code) +} + func (self *JSPipe) IsContract(address string) bool { return len(self.World().SafeGet(ethutil.Hex2Bytes(address)).Code) > 0 } @@ -118,6 +122,18 @@ func (self *JSPipe) SecretToAddress(key string) string { return ethutil.Bytes2Hex(pair.Address()) } +func (self *JSPipe) Execute(addr, value, gas, price, data string) (string, error) { + ret, err := self.ExecuteObject(&Object{ + self.World().safeGet(ethutil.Hex2Bytes(addr))}, + ethutil.Hex2Bytes(data), + ethutil.NewValue(value), + ethutil.NewValue(gas), + ethutil.NewValue(price), + ) + + return ethutil.Bytes2Hex(ret), err +} + type KeyVal struct { Key string `json:"key"` Value string `json:"value"` @@ -224,9 +240,9 @@ func (self *JSPipe) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr } func (self *JSPipe) PushTx(txStr string) (*JSReceipt, error) { - tx := ethchain.NewTransactionFromBytes(ethutil.Hex2Bytes(txStr)) - self.obj.TxPool().QueueTransaction(tx) - return NewJSReciept(tx.CreatesContract(), tx.CreationAddress(), tx.Hash(), tx.Sender()), nil + tx := ethchain.NewTransactionFromBytes(ethutil.Hex2Bytes(txStr)) + self.obj.TxPool().QueueTransaction(tx) + return NewJSReciept(tx.CreatesContract(), tx.CreationAddress(), tx.Hash(), tx.Sender()), nil } func (self *JSPipe) CompileMutan(code string) string { diff --git a/ethpipe/pipe.go b/ethpipe/pipe.go index b7d3be041..7c3f491d3 100644 --- a/ethpipe/pipe.go +++ b/ethpipe/pipe.go @@ -1,6 +1,7 @@ package ethpipe import ( + "fmt" "strings" "github.com/ethereum/eth-go/ethchain" @@ -51,18 +52,19 @@ func (self *Pipe) Execute(addr []byte, data []byte, value, gas, price *ethutil.V func (self *Pipe) ExecuteObject(object *Object, data []byte, value, gas, price *ethutil.Value) ([]byte, error) { var ( - initiator = ethstate.NewStateObject([]byte{0}) - block = self.blockChain.CurrentBlock - stateObject = object.StateObject + initiator = ethstate.NewStateObject(self.obj.KeyManager().KeyPair().Address()) + block = self.blockChain.CurrentBlock ) - if self.Vm.State == nil { - self.Vm.State = self.World().State().Copy() - } + + self.Vm.State = self.World().State().Copy() vm := ethvm.New(NewEnv(self.Vm.State, block, value.BigInt(), initiator.Address())) + vm.Verbose = true - closure := ethvm.NewClosure(ðstate.Message{}, initiator, stateObject, object.Code, gas.BigInt(), price.BigInt()) - ret, _, err := closure.Call(vm, data) + msg := ethvm.NewMessage(vm, object.Address(), data, gas.BigInt(), price.BigInt(), value.BigInt()) + ret, err := msg.Exec(object.Address(), initiator) + + fmt.Println("returned from call", ret, err) return ret, err } @@ -150,12 +152,12 @@ func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price } func (self *Pipe) PushTx(tx *ethchain.Transaction) ([]byte, error) { - self.obj.TxPool().QueueTransaction(tx) - if tx.Recipient == nil { - logger.Infof("Contract addr %x", tx.CreationAddress()) - return tx.CreationAddress(), nil - } - return tx.Hash(), nil + self.obj.TxPool().QueueTransaction(tx) + if tx.Recipient == nil { + logger.Infof("Contract addr %x", tx.CreationAddress()) + return tx.CreationAddress(), nil + } + return tx.Hash(), nil } func (self *Pipe) CompileMutan(code string) ([]byte, error) { From b65f29f8faa20a93bd83c18232326c935cb16981 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 22 Sep 2014 14:51:41 +0200 Subject: [PATCH 53/58] Added JavaScript JSON helper --- ethutil/list.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/ethutil/list.go b/ethutil/list.go index 0aa657a14..9db96cf18 100644 --- a/ethutil/list.go +++ b/ethutil/list.go @@ -1,6 +1,9 @@ package ethutil -import "reflect" +import ( + "encoding/json" + "reflect" +) // The list type is an anonymous slice handler which can be used // for containing any slice type to use in an environment which @@ -44,3 +47,15 @@ func (self *List) Append(v interface{}) { func (self *List) Interface() interface{} { return self.list.Interface() } + +// For JavaScript <3 +func (self *List) ToJSON() string { + var list []interface{} + for i := 0; i < self.Length; i++ { + list = append(list, self.Get(i)) + } + + data, _ := json.Marshal(list) + + return string(data) +} From 9ed5b4d90e287de788d9079abab54578064864ba Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 22 Sep 2014 16:28:28 +0200 Subject: [PATCH 54/58] Support C++ GetBlockHash by assuming empty = done --- peer.go | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/peer.go b/peer.go index 8c04864d0..67bf4e555 100644 --- a/peer.go +++ b/peer.go @@ -362,22 +362,24 @@ clean: } func formatMessage(msg *ethwire.Msg) (ret string) { - ret = fmt.Sprintf("%v ", msg.Type) + ret = fmt.Sprintf("%v %v", msg.Type, msg.Data) /* XXX Commented out because I need the log level here to determine if i should or shouldn't generate this message */ - switch msg.Type { - case ethwire.MsgPeersTy: - ret += fmt.Sprintf("(%d entries)", msg.Data.Len()) - case ethwire.MsgBlockTy: - b1, b2 := ethchain.NewBlockFromRlpValue(msg.Data.Get(0)), ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len()-1)) - ret += fmt.Sprintf("(%d entries) %x - %x", msg.Data.Len(), b1.Hash()[0:4], b2.Hash()[0:4]) - case ethwire.MsgBlockHashesTy: - h1, h2 := msg.Data.Get(0).Bytes(), msg.Data.Get(msg.Data.Len()-1).Bytes() - ret += fmt.Sprintf("(%d entries) %x - %x", msg.Data.Len(), h1[0:4], h2[0:4]) - } + /* + switch msg.Type { + case ethwire.MsgPeersTy: + ret += fmt.Sprintf("(%d entries)", msg.Data.Len()) + case ethwire.MsgBlockTy: + b1, b2 := ethchain.NewBlockFromRlpValue(msg.Data.Get(0)), ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len()-1)) + ret += fmt.Sprintf("(%d entries) %x - %x", msg.Data.Len(), b1.Hash()[0:4], b2.Hash()[0:4]) + case ethwire.MsgBlockHashesTy: + h1, h2 := msg.Data.Get(0).Bytes(), msg.Data.Get(msg.Data.Len()-1).Bytes() + ret += fmt.Sprintf("(%d entries) %x - %x", msg.Data.Len(), h1, h2) + } + */ return } @@ -512,7 +514,7 @@ func (p *Peer) HandleInbound() { p.lastBlockReceived = time.Now() } - if foundCommonHash { + if foundCommonHash || msg.Data.Len() == 0 { p.FetchBlocks() } else { p.FetchHashes() From 16871ae2b49fb2a8fad3848e3184c8ab87c7f67a Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 22 Sep 2014 16:28:49 +0200 Subject: [PATCH 55/58] New Peer server --- ethereum.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethereum.go b/ethereum.go index 4cf1ce9e7..a54399921 100644 --- a/ethereum.go +++ b/ethereum.go @@ -25,7 +25,7 @@ import ( const ( seedTextFileUri string = "http://www.ethereum.org/servers.poc3.txt" - seedNodeAddress = "54.76.56.74:30303" + seedNodeAddress = "poc-6.ethdev.com:30303" ) var ethlogger = ethlog.NewLogger("SERV") @@ -208,6 +208,7 @@ func (s *Ethereum) ProcessPeerList(addrs []string) { } func (s *Ethereum) ConnectToPeer(addr string) error { + fmt.Println("ConnectToPeer", addr) if s.peers.Len() < s.MaxPeers { var alreadyConnected bool From 1bc815e0b1d3fb6f47f8747e607a03f6d8a25ac2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 22 Sep 2014 16:30:30 +0200 Subject: [PATCH 56/58] Remove log --- ethereum.go | 1 - 1 file changed, 1 deletion(-) diff --git a/ethereum.go b/ethereum.go index a54399921..79e722c26 100644 --- a/ethereum.go +++ b/ethereum.go @@ -208,7 +208,6 @@ func (s *Ethereum) ProcessPeerList(addrs []string) { } func (s *Ethereum) ConnectToPeer(addr string) error { - fmt.Println("ConnectToPeer", addr) if s.peers.Len() < s.MaxPeers { var alreadyConnected bool From 2ae3bda029ec91e02fb164fd53175ad78d45a0ba Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 22 Sep 2014 18:15:10 +0200 Subject: [PATCH 57/58] Increased from 200 nano to milliseconds --- ethwire/messaging.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index b1cefc0ae..2b3836e9c 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -109,9 +109,10 @@ func ReadMessages(conn net.Conn) (msgs []*Msg, err error) { } } + fmt.Println(n, len(buff)) if n == 0 && len(buff) == 0 { // If there's nothing on the wire wait for a bit - time.Sleep(200) + time.Sleep(200 * time.Millisecond) continue } From 7d08e4f7d14600ee4ed38fc9d435e9c2e0e0fdac Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 22 Sep 2014 18:15:32 +0200 Subject: [PATCH 58/58] Remove log --- ethwire/messaging.go | 1 - 1 file changed, 1 deletion(-) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index 2b3836e9c..2ef53c003 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -109,7 +109,6 @@ func ReadMessages(conn net.Conn) (msgs []*Msg, err error) { } } - fmt.Println(n, len(buff)) if n == 0 && len(buff) == 0 { // If there's nothing on the wire wait for a bit time.Sleep(200 * time.Millisecond)