From df5603de0a34e80a1af6ad03e37ce43728baad35 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 30 Oct 2014 13:32:50 +0100 Subject: [PATCH] Moved logging to state, proper structured block * Moved logs to state so it's subject to snapshotting * Split up block header * Removed logs from transactions and made them receipts only --- ethchain/block.go | 42 ++++++++++++------------------------ ethchain/bloom9.go | 8 +++---- ethchain/state_manager.go | 7 ++++-- ethchain/state_transition.go | 2 +- ethchain/transaction.go | 13 +++-------- ethchain/vm_env.go | 4 ++-- ethminer/miner.go | 2 +- ethpipe/vm_env.go | 2 +- {vm => ethstate}/log.go | 2 +- ethstate/state.go | 19 ++++++++++++++++ utils/vm_env.go | 2 +- vm/environment.go | 6 +++++- vm/vm_debug.go | 3 ++- 13 files changed, 59 insertions(+), 53 deletions(-) rename {vm => ethstate}/log.go (97%) diff --git a/ethchain/block.go b/ethchain/block.go index b31d68e4d..a10da97ec 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -149,10 +149,7 @@ func (block *Block) Hash() ethutil.Bytes { } func (block *Block) HashNoNonce() []byte { - return ethcrypto.Sha3(ethutil.Encode([]interface{}{block.PrevHash, - block.UncleSha, block.Coinbase, block.state.Trie.Root, - block.ReceiptSha, block.Difficulty, block.Number, block.MinGasPrice, - block.GasLimit, block.GasUsed, block.Time, block.Extra})) + return ethcrypto.Sha3(ethutil.Encode(block.miningHeader())) } func (block *Block) State() *ethstate.State { @@ -235,31 +232,18 @@ func (block *Block) rlpUncles() interface{} { func (block *Block) SetUncles(uncles []*Block) { block.Uncles = uncles - block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles())) } func (self *Block) SetReceipts(receipts Receipts) { self.receipts = receipts - self.SetReceiptHash(receipts) + self.ReceiptSha = DeriveSha(receipts) + self.LogsBloom = CreateBloom(self) } func (self *Block) SetTransactions(txs Transactions) { - self.setTransactions(txs) - self.SetTransactionHash(txs) -} - -func (block *Block) setTransactions(txs Transactions) { - block.transactions = txs - block.LogsBloom = CreateBloom(block) -} - -func (self *Block) SetTransactionHash(transactions Transactions) { - self.TxSha = DeriveSha(transactions) -} - -func (self *Block) SetReceiptHash(receipts Receipts) { - self.ReceiptSha = DeriveSha(receipts) + self.transactions = txs + self.TxSha = DeriveSha(txs) } func (block *Block) Value() *ethutil.Value { @@ -285,10 +269,10 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { if decoder.Get(1).IsNil() == false { // Yes explicitness //receipts := decoder.Get(1) //block.receipts = make([]*Receipt, receipts.Len()) - it := decoder.Get(1).NewIterator() - block.transactions = make(Transactions, it.Len()) - for it.Next() { - block.transactions[it.Idx()] = NewTransactionFromValue(it.Value()) + txs := decoder.Get(1) + block.transactions = make(Transactions, txs.Len()) + for i := 0; i < txs.Len(); i++ { + block.transactions[i] = NewTransactionFromValue(txs.Get(i)) //receipt := NewRecieptFromValue(receipts.Get(i)) //block.transactions[i] = receipt.Tx //block.receipts[i] = receipt @@ -347,7 +331,7 @@ func (self *Block) Receipts() []*Receipt { return self.receipts } -func (block *Block) header() []interface{} { +func (block *Block) miningHeader() []interface{} { return []interface{}{ // Sha of the previous block block.PrevHash, @@ -377,11 +361,13 @@ func (block *Block) header() []interface{} { block.Time, // Extra data block.Extra, - // Block's Nonce for validation - block.Nonce, } } +func (block *Block) header() []interface{} { + return append(block.miningHeader(), block.Nonce) +} + func (block *Block) String() string { return fmt.Sprintf(` BLOCK(%x): Size: %v diff --git a/ethchain/bloom9.go b/ethchain/bloom9.go index 4028231a3..8fa7b6339 100644 --- a/ethchain/bloom9.go +++ b/ethchain/bloom9.go @@ -3,21 +3,21 @@ package ethchain import ( "math/big" + "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/vm" ) func CreateBloom(block *Block) []byte { bin := new(big.Int) bin.Or(bin, bloom9(block.Coinbase)) - for _, tx := range block.Transactions() { - bin.Or(bin, LogsBloom(tx.logs)) + for _, receipt := range block.Receipts() { + bin.Or(bin, LogsBloom(receipt.logs)) } return bin.Bytes() } -func LogsBloom(logs []vm.Log) *big.Int { +func LogsBloom(logs ethstate.Logs) *big.Int { bin := new(big.Int) for _, log := range logs { data := [][]byte{log.Address} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 0fe7001c6..62970f621 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -145,6 +145,9 @@ func (self *StateManager) ProcessTransactions(coinbase *ethstate.StateObject, st done: for i, tx := range txs { + // If we are mining this block and validating we want to set the logs back to 0 + state.EmptyLogs() + txGas := new(big.Int).Set(tx.Gas) cb := state.GetStateObject(coinbase.Address()) @@ -175,7 +178,7 @@ done: txGas.Sub(txGas, st.gas) cumulative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) //receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} - receipt := &Receipt{ethutil.CopyBytes(state.Root().([]byte)), cumulative, LogsBloom(tx.logs).Bytes(), tx.logs} + receipt := &Receipt{ethutil.CopyBytes(state.Root().([]byte)), cumulative, LogsBloom(state.Logs()).Bytes(), state.Logs()} if i < len(block.Receipts()) { original := block.Receipts()[i] @@ -238,7 +241,7 @@ func (sm *StateManager) Process(block *Block) (err error) { txSha := DeriveSha(block.transactions) if bytes.Compare(txSha, block.TxSha) != 0 { - return fmt.Errorf("Error validating transaction sha. Received %x, got %x", block.ReceiptSha, txSha) + return fmt.Errorf("Error validating transaction sha. Received %x, got %x", block.TxSha, txSha) } receipts, err := sm.ApplyDiff(state, parent, block) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 809e5ad6a..ad7b320c4 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -232,7 +232,7 @@ func (self *StateTransition) TransitionState() (err error) { } else { // Add default LOG. Default = big(sender.addr) + 1 addr := ethutil.BigD(receiver.Address()) - tx.addLog(vm.Log{sender.Address(), [][]byte{addr.Add(addr, ethutil.Big1).Bytes()}, nil}) + self.state.AddLog(ethstate.Log{sender.Address(), [][]byte{ethutil.U256(addr.Add(addr, ethutil.Big1)).Bytes()}, nil}) } } diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 10bf5bc8e..331f44b55 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/go-ethereum/ethcrypto" "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/vm" "github.com/obscuren/secp256k1-go" ) @@ -29,8 +28,6 @@ type Transaction struct { v byte r, s []byte - logs []vm.Log - // Indicates whether this tx is a contract creation transaction contractCreation bool } @@ -57,10 +54,6 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { return tx } -func (self *Transaction) addLog(log vm.Log) { - self.logs = append(self.logs, log) -} - func (self *Transaction) GasValue() *big.Int { return new(big.Int).Mul(self.Gas, self.GasPrice) } @@ -212,7 +205,7 @@ type Receipt struct { PostState []byte CumulativeGasUsed *big.Int Bloom []byte - Logs vm.Logs + logs ethstate.Logs } func NewRecieptFromValue(val *ethutil.Value) *Receipt { @@ -229,12 +222,12 @@ func (self *Receipt) RlpValueDecode(decoder *ethutil.Value) { it := decoder.Get(3).NewIterator() for it.Next() { - self.Logs = append(self.Logs, vm.NewLogFromValue(it.Value())) + self.logs = append(self.logs, ethstate.NewLogFromValue(it.Value())) } } func (self *Receipt) RlpData() interface{} { - return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.Logs.RlpData()} + return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs.RlpData()} } func (self *Receipt) RlpEncode() []byte { diff --git a/ethchain/vm_env.go b/ethchain/vm_env.go index 4dc96e8b1..1bb67dbd0 100644 --- a/ethchain/vm_env.go +++ b/ethchain/vm_env.go @@ -31,8 +31,8 @@ func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) Value() *big.Int { return self.tx.Value } func (self *VMEnv) State() *ethstate.State { return self.state } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } -func (self *VMEnv) AddLog(log vm.Log) { - self.tx.addLog(log) +func (self *VMEnv) AddLog(log ethstate.Log) { + self.state.AddLog(log) } func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { return vm.Transfer(from, to, amount) diff --git a/ethminer/miner.go b/ethminer/miner.go index 57cf0cd57..571b92ce0 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -185,8 +185,8 @@ func (self *Miner) mineNewBlock() { self.ethereum.TxPool().RemoveSet(erroneous) self.txs = append(txs, unhandledTxs...) - self.block.SetReceipts(receipts) self.block.SetTransactions(txs) + self.block.SetReceipts(receipts) // Accumulate the rewards included for this block stateManager.AccumelateRewards(self.block.State(), self.block, parent) diff --git a/ethpipe/vm_env.go b/ethpipe/vm_env.go index 9d11ecf34..eb1190cf1 100644 --- a/ethpipe/vm_env.go +++ b/ethpipe/vm_env.go @@ -34,7 +34,7 @@ func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) Value() *big.Int { return self.value } func (self *VMEnv) State() *ethstate.State { return self.state } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } -func (self *VMEnv) AddLog(vm.Log) {} +func (self *VMEnv) AddLog(ethstate.Log) {} func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { return vm.Transfer(from, to, amount) } diff --git a/vm/log.go b/ethstate/log.go similarity index 97% rename from vm/log.go rename to ethstate/log.go index bc72a0423..a2e9ca041 100644 --- a/vm/log.go +++ b/ethstate/log.go @@ -1,4 +1,4 @@ -package vm +package ethstate import "github.com/ethereum/go-ethereum/ethutil" diff --git a/ethstate/state.go b/ethstate/state.go index 97958cc0a..48efeae46 100644 --- a/ethstate/state.go +++ b/ethstate/state.go @@ -24,6 +24,8 @@ type State struct { manifest *Manifest refund map[string]*big.Int + + logs Logs } // Create a new state from a given trie @@ -31,6 +33,18 @@ func New(trie *ethtrie.Trie) *State { return &State{Trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest(), refund: make(map[string]*big.Int)} } +func (self *State) EmptyLogs() { + self.logs = nil +} + +func (self *State) AddLog(log Log) { + self.logs = append(self.logs, log) +} + +func (self *State) Logs() Logs { + return self.logs +} + // Retrieve the balance from the given address or 0 if object not found func (self *State) GetBalance(addr []byte) *big.Int { stateObject := self.GetStateObject(addr) @@ -202,6 +216,10 @@ func (self *State) Copy() *State { state.refund[addr] = refund } + logs := make(Logs, len(self.logs)) + copy(logs, self.logs) + state.logs = logs + return state } @@ -216,6 +234,7 @@ func (self *State) Set(state *State) { self.Trie = state.Trie self.stateObjects = state.stateObjects self.refund = state.refund + self.logs = state.logs } func (s *State) Root() interface{} { diff --git a/utils/vm_env.go b/utils/vm_env.go index 034d4a16e..9d9bbf4ec 100644 --- a/utils/vm_env.go +++ b/utils/vm_env.go @@ -35,7 +35,7 @@ func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) Value() *big.Int { return self.value } func (self *VMEnv) State() *ethstate.State { return self.state } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } -func (self *VMEnv) AddLog(vm.Log) {} +func (self *VMEnv) AddLog(ethstate.Log) {} func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { return vm.Transfer(from, to, amount) } diff --git a/vm/environment.go b/vm/environment.go index b8013856e..deb46b77f 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -20,7 +20,7 @@ type Environment interface { BlockHash() []byte GasLimit() *big.Int Transfer(from, to Account, amount *big.Int) error - AddLog(Log) + AddLog(ethstate.Log) } type Object interface { @@ -43,5 +43,9 @@ func Transfer(from, to Account, amount *big.Int) error { from.SubBalance(amount) to.AddBalance(amount) + // Add default LOG. Default = big(sender.addr) + 1 + //addr := ethutil.BigD(receiver.Address()) + //tx.addLog(vm.Log{sender.Address(), [][]byte{ethutil.U256(addr.Add(addr, ethutil.Big1)).Bytes()}, nil}) + return nil } diff --git a/vm/vm_debug.go b/vm/vm_debug.go index b3fbfe341..7afc7e79a 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -5,6 +5,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" ) @@ -710,7 +711,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { for i := 0; i < n; i++ { topics[i] = stack.Pop().Bytes() } - self.env.AddLog(Log{closure.Address(), topics, data}) + self.env.AddLog(ethstate.Log{closure.Address(), topics, data}) case MLOAD: offset := stack.Pop() val := ethutil.BigD(mem.Get(offset.Int64(), 32))