From 7fb5e993e3a1cc2251bba7af1c85ed1d024b4b50 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 20:11:40 +0200 Subject: [PATCH 01/10] Moved 0 check to state object for now --- ethchain/state_object.go | 7 +++++++ ethchain/vm.go | 26 ++++++++++++++------------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 5b64c3b372..17391963f7 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -90,6 +90,13 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) + + // FIXME This should be handled in the Trie it self + if val.BigInt().Cmp(ethutil.Big0) == 0 { + c.state.trie.Delete(string(addr)) + return + } + //fmt.Printf("sstore %x => %v\n", addr, val) c.SetAddr(addr, val) } diff --git a/ethchain/vm.go b/ethchain/vm.go index b9e8353fbe..bacd05ba55 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -325,21 +325,21 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(base) case LT: require(2) - y, x := stack.Popn() - vm.Printf(" %v < %v", x, y) + x, y := stack.Popn() + vm.Printf(" %v < %v", y, x) // x < y - if x.Cmp(y) < 0 { + if y.Cmp(x) < 0 { stack.Push(ethutil.BigTrue) } else { stack.Push(ethutil.BigFalse) } case GT: require(2) - y, x := stack.Popn() - vm.Printf(" %v > %v", x, y) + x, y := stack.Popn() + vm.Printf(" %v > %v", y, x) // x > y - if x.Cmp(y) > 0 { + if y.Cmp(x) > 0 { stack.Push(ethutil.BigTrue) } else { stack.Push(ethutil.BigFalse) @@ -520,7 +520,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case MLOAD: require(1) offset := stack.Pop() - stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) + val := ethutil.BigD(mem.Get(offset.Int64(), 32)) + stack.Push(val) + + vm.Printf(" => 0x%x", val.Bytes()) case MSTORE: // Store the value at stack top-1 in to memory at location stack top require(2) // Pop value of the stack @@ -541,15 +544,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val := closure.GetMem(loc) stack.Push(val.BigInt()) - vm.Printf(" {} 0x%x", val) + vm.Printf(" {0x%x} 0x%x", loc.Bytes(), val) case SSTORE: require(2) val, loc := stack.Popn() - // FIXME This should be handled in the Trie it self - if val.Cmp(big.NewInt(0)) != 0 { - closure.SetStorage(loc, ethutil.NewValue(val)) - } + //if val.Cmp(big.NewInt(0)) != 0 { + closure.SetStorage(loc, ethutil.NewValue(val)) + //} // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) From 931ae0f116ca65c3758524160bf21e28f06db50e Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 20:12:08 +0200 Subject: [PATCH 02/10] Append zero's in R & S --- ethchain/transaction.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 34ab357a17..29b167355b 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -150,8 +150,11 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Value = decoder.Get(4).BigInt() tx.Data = decoder.Get(5).Bytes() tx.v = byte(decoder.Get(6).Uint()) - tx.r = decoder.Get(7).Bytes() - tx.s = decoder.Get(8).Bytes() + + r := make([]byte, 32-len(decoder.Get(7).Bytes())) + s := make([]byte, 32-len(decoder.Get(8).Bytes())) + tx.r = append(r, decoder.Get(7).Bytes()...) + tx.s = append(s, decoder.Get(8).Bytes()...) if IsContractAddr(tx.Recipient) { tx.contractCreation = true @@ -175,7 +178,8 @@ func (tx *Transaction) String() string { `, tx.Hash(), len(tx.Recipient) == 0, - tx.Sender(), + //tx.Sender(), + nil, tx.Recipient, tx.Nonce, tx.GasPrice, From 299b50a0d4e1ec0d7c6e5820c4f68da4e424f382 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 21 Jun 2014 02:40:25 +0200 Subject: [PATCH 03/10] Support serpent lang --- ethutil/script.go | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/ethutil/script.go b/ethutil/script.go index 94e4014069..c8b1da51cf 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -3,23 +3,35 @@ package ethutil import ( "fmt" "github.com/obscuren/mutan" + "github.com/obscuren/serpent-go" "strings" ) // General compile function -func Compile(script string) ([]byte, error) { - byteCode, errors := mutan.Compile(strings.NewReader(script), false) - if len(errors) > 0 { - var errs string - for _, er := range errors { - if er != nil { - errs += er.Error() +func Compile(script string) (ret []byte, err error) { + c := strings.Split(script, "\n")[0] + + if c == "#!serpent" { + byteCode, err := serpent.Compile(script) + if err != nil { + return nil, err + } + + return byteCode, nil + } else { + byteCode, errors := mutan.Compile(strings.NewReader(script), false) + if len(errors) > 0 { + var errs string + for _, er := range errors { + if er != nil { + errs += er.Error() + } } + return nil, fmt.Errorf("%v", errs) } - return nil, fmt.Errorf("%v", errs) - } - return byteCode, nil + return byteCode, nil + } } func CompileScript(script string) ([]byte, []byte, error) { From bb1641e4ecd92884f219d77acd5348ceb0782490 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:23:18 +0200 Subject: [PATCH 04/10] Clean up & refactored methods --- ethchain/state_manager.go | 53 ++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 36ba1731c1..7444d51808 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -143,45 +143,31 @@ done: return receipts, handled, unhandled, err } -func (sm *StateManager) Process(block *Block, dontReact bool) error { - if !sm.bc.HasBlock(block.PrevHash) { - return ParentError(block.PrevHash) - } - - parent := sm.bc.GetBlock(block.PrevHash) - - return sm.ProcessBlock(parent.State(), parent, block, dontReact) - -} - -// Block processing and validating with a given (temporarily) state -func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontReact bool) (err error) { +func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() - hash := block.Hash() - if sm.bc.HasBlock(hash) { + if sm.bc.HasBlock(block.Hash()) { return nil } + if !sm.bc.HasBlock(block.PrevHash) { + return ParentError(block.PrevHash) + } + + var ( + parent = sm.bc.GetBlock(block.PrevHash) + state = parent.State() + ) + // Defer the Undo on the Trie. If the block processing happened // we don't want to undo but since undo only happens on dirty // nodes this won't happen because Commit would have been called // before that. defer state.Reset() - // Check if we have the parent hash, if it isn't known we discard it - // Reasons might be catching up or simply an invalid block - if !sm.bc.HasBlock(block.PrevHash) && sm.bc.CurrentBlock != nil { - return ParentError(block.PrevHash) - } - - coinbase := state.GetOrNewStateObject(block.Coinbase) - coinbase.SetGasPool(block.CalcGasLimit(parent)) - - // Process the transactions on to current block - receipts, _, _, _ := sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + receipts, err := sm.ApplyDiff(state, parent, block) defer func() { if err != nil { if len(receipts) == len(block.Receipts()) { @@ -194,6 +180,10 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea } }() + if err != nil { + return err + } + // Block validation if err = sm.ValidateBlock(block); err != nil { fmt.Println("[SM] Error validating block:", err) @@ -237,6 +227,17 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea return nil } + +func (sm *StateManager) ApplyDiff(state *State, parent, block *Block) (receipts Receipts, err error) { + coinbase := state.GetOrNewStateObject(block.Coinbase) + coinbase.SetGasPool(block.CalcGasLimit(parent)) + + // Process the transactions on to current block + receipts, _, _, _ = sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + + return receipts, nil +} + func (sm *StateManager) CalculateTD(block *Block) bool { uncleDiff := new(big.Int) for _, uncle := range block.Uncles { From 842d52db7b98fb309ed99ccc4b65ca3973fb81ec Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:23:51 +0200 Subject: [PATCH 05/10] Make sure that public key always uses 64 bytes --- ethchain/transaction.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 29b167355b..2ab6810304 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -89,11 +89,12 @@ func (tx *Transaction) Signature(key []byte) []byte { func (tx *Transaction) PublicKey() []byte { hash := tx.Hash() - // If we don't make a copy we will overwrite the existing underlying array - dst := make([]byte, len(tx.r)) - copy(dst, tx.r) + r := make([]byte, 32-len(tx.r)) + s := make([]byte, 32-len(tx.s)) + r = append(r, ethutil.CopyBytes(tx.r)...) + s = append(s, ethutil.CopyBytes(tx.s)...) - sig := append(dst, tx.s...) + sig := append(r, s...) sig = append(sig, tx.v-27) pubkey, _ := secp256k1.RecoverPubkey(hash, sig) @@ -127,6 +128,8 @@ func (tx *Transaction) Sign(privk []byte) error { func (tx *Transaction) RlpData() interface{} { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} + // TODO Remove prefixing zero's + return append(data, tx.v, tx.r, tx.s) } @@ -151,10 +154,8 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Data = decoder.Get(5).Bytes() tx.v = byte(decoder.Get(6).Uint()) - r := make([]byte, 32-len(decoder.Get(7).Bytes())) - s := make([]byte, 32-len(decoder.Get(8).Bytes())) - tx.r = append(r, decoder.Get(7).Bytes()...) - tx.s = append(s, decoder.Get(8).Bytes()...) + tx.r = decoder.Get(7).Bytes() + tx.s = decoder.Get(8).Bytes() if IsContractAddr(tx.Recipient) { tx.contractCreation = true @@ -178,8 +179,7 @@ func (tx *Transaction) String() string { `, tx.Hash(), len(tx.Recipient) == 0, - //tx.Sender(), - nil, + tx.Sender(), tx.Recipient, tx.Nonce, tx.GasPrice, From 8c96c5662f9a362c50f3e6e04e886e2518cc68b9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:24:07 +0200 Subject: [PATCH 06/10] Added hex script method --- ethpub/types.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ethpub/types.go b/ethpub/types.go index 31b92f6ed6..3525981483 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -244,6 +244,14 @@ func (c *PStateObject) Script() string { return "" } +func (c *PStateObject) HexScript() string { + if c.object != nil { + return ethutil.Hex(c.object.Script()) + } + + return "" +} + type PStorageState struct { StateAddress string Address string From 9350ecd36fe3a30bea4cfd60db9a53787d4d5852 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:24:45 +0200 Subject: [PATCH 07/10] Do not keep on asking for the same chain --- peer.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/peer.go b/peer.go index b4bde2c1d6..ca41689408 100644 --- a/peer.go +++ b/peer.go @@ -138,6 +138,8 @@ type Peer struct { // We use this to give some kind of pingtime to a node, not very accurate, could be improved. pingTime time.Duration pingStartTime time.Time + + lastRequestedBlock *ethchain.Block } func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { @@ -351,6 +353,12 @@ func (p *Peer) HandleInbound() { // We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find // common ground to start syncing from lastBlock = ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len() - 1)) + if p.lastRequestedBlock != nil && bytes.Compare(lastBlock.Hash(), p.lastRequestedBlock.Hash()) == 0 { + p.catchingUp = false + continue + } + p.lastRequestedBlock = lastBlock + ethutil.Config.Log.Infof("[PEER] Last block: %x. Checking if we have it locally.\n", lastBlock.Hash()) for i := msg.Data.Len() - 1; i >= 0; i-- { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) From a4e26bf7c2c0cfc65be14ef98af695a0d663609f Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:25:14 +0200 Subject: [PATCH 08/10] Added Block do which replays the given block or error --- ethereum.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ethereum.go b/ethereum.go index a6cb78b1fc..77a7c92c77 100644 --- a/ethereum.go +++ b/ethereum.go @@ -113,6 +113,24 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { return ethereum, nil } +// Replay block +func (self *Ethereum) BlockDo(hash []byte) error { + block := self.blockChain.GetBlock(hash) + if block == nil { + return fmt.Errorf("unknown block %x", hash) + } + + parent := self.blockChain.GetBlock(block.PrevHash) + + _, err := self.stateManager.ApplyDiff(parent.State(), parent, block) + if err != nil { + return err + } + + return nil + +} + func (s *Ethereum) Reactor() *ethutil.ReactorEngine { return s.reactor } From 803e4807ede157db36030c6415a4f515f723ccf0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:26:31 +0200 Subject: [PATCH 09/10] Removed comments --- ethchain/state_object.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 17391963f7..0a2e28ded5 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -94,10 +94,10 @@ func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { // FIXME This should be handled in the Trie it self if val.BigInt().Cmp(ethutil.Big0) == 0 { c.state.trie.Delete(string(addr)) + return } - //fmt.Printf("sstore %x => %v\n", addr, val) c.SetAddr(addr, val) } From d890258af6de8c5ef9701826fb4ee7c353788ad5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:26:51 +0200 Subject: [PATCH 10/10] Minor fixes to vm output --- ethchain/vm.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index bacd05ba55..a2e1c60fd5 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -358,10 +358,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case NOT: require(1) x := stack.Pop() - if x.Cmp(ethutil.BigFalse) == 0 { - stack.Push(ethutil.BigTrue) - } else { + if x.Cmp(ethutil.BigFalse) > 0 { stack.Push(ethutil.BigFalse) + } else { + stack.Push(ethutil.BigTrue) } // 0x10 range @@ -542,16 +542,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) loc := stack.Pop() val := closure.GetMem(loc) + stack.Push(val.BigInt()) - vm.Printf(" {0x%x} 0x%x", loc.Bytes(), val) + vm.Printf(" {0x%x} 0x%x", loc.Bytes(), val.Bytes()) case SSTORE: require(2) val, loc := stack.Popn() - - //if val.Cmp(big.NewInt(0)) != 0 { closure.SetStorage(loc, ethutil.NewValue(val)) - //} // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) @@ -690,7 +688,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro fallthrough case STOP: // Stop the closure - vm.Printf(" (g) %v", closure.Gas).Endl() + vm.Endl() return closure.Return(nil), nil default: