From 72c72b6b0c46571e8e05bfb16f0fc3589ca5c0fe Mon Sep 17 00:00:00 2001 From: Talha Cross <47772477+soc1c@users.noreply.github.com> Date: Tue, 13 Aug 2019 13:53:18 +0200 Subject: [PATCH] 6.0.8-stable backports (#37) * Replace repository reference for accounts/abi/bind (#29) * docs: update badges (#34) * docs: add gitter badge * docs: add circle-ci badge * Update README.md * Update README.md * Update README.md * docs: update repository path * Update README.md * Tx Encoding and decoding fix (#33) * Added test for decoding old encoding function * Fixed decoding issue and improved tests to handle all cases including previous client * Add compatibility with previous version * Rename receipt storage variable * Storage and edge case fixes (#28) * Applied storage fixes and updates * Minor execution refactor --- README.md | 21 ++++---- core/database_util_test.go | 106 +++++++++++++++++++++++++++++++++++++ core/execution.go | 34 ++++-------- core/state/state_object.go | 29 ++++++---- core/state/statedb.go | 56 +++++++++----------- core/state_processor.go | 4 +- core/tx_pool.go | 2 +- core/types/receipt.go | 43 +++++++++------ core/vm/contract.go | 6 +-- core/vm/environment.go | 2 +- eth/api.go | 16 +++--- go.mod | 2 + 12 files changed, 214 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index d379a21df..93a5826db 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,19 @@ # Geth Classic -[![GitHub release](https://img.shields.io/github/release-pre/eth-classic/go-ethereum.svg)](https://github.com/eth-classic/go-ethereum/releases/latest) -![GitHub All Releases](https://img.shields.io/github/downloads/eth-classic/go-ethereum/total.svg) -![LICENSE](https://img.shields.io/github/license/eth-classic/go-ethereum.svg) +[![GitHub release](https://img.shields.io/github/release-pre/etclabscore/go-ethereum.svg)](https://github.com/etclabscore/go-ethereum/releases/latest) +![GitHub All Releases](https://img.shields.io/github/downloads/etclabscore/go-ethereum/total.svg) +![LICENSE](https://img.shields.io/github/license/etclabscore/go-ethereum.svg) - -[![CircleCI](https://img.shields.io/circleci/build/gh/eth-classic/go-ethereum/development.svg)](https://circleci.com/gh/eth-classic/go-ethereum/tree/development) -![GitHub last commit](https://img.shields.io/github/last-commit/eth-classic/go-ethereum.svg) -[![Join the chat at https://gitter.im/eth-classic/go-ethereum](https://badges.gitter.im/eth-classic/go-ethereum.svg)](https://gitter.im/eth-classic/go-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![CircleCI](https://img.shields.io/circleci/build/gh/etclabscore/go-ethereum/development.svg)](https://circleci.com/gh/etclabscore/go-ethereum/tree/development) +![GitHub last commit](https://img.shields.io/github/last-commit/etclabscore/go-ethereum.svg) +[![Join the chat at https://gitter.im/etclabscore/go-ethereum](https://badges.gitter.im/etclabscore/go-ethereum.svg)](https://gitter.im/etclabscore/go-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Official Go-language implementation of the Ethereum Classic protocol. Ethereum Classic (ETC) offers a censorship-resistant and powerful application platform for developers in parallel to the Ethereum Foundation network (ETH), while differentially rejecting the DAO transition. ## Install Geth Classic ### :gift: Official Releases -Regular releases will be published on the [release page](https://github.com/eth-classic/go-ethereum/releases). Binaries will be provided for all releases that are considered fairly stable. +Regular releases will be published on the [release page](https://github.com/etclabscore/go-ethereum/releases). Binaries will be provided for all releases that are considered fairly stable. ### :hammer: Building the source If your heart is set on the bleeding edge, install from source. However, please be advised that you may encounter some strange things, and we can't prioritize support beyond the release versions. Recommended for developers only. @@ -28,7 +27,7 @@ With [Go modules](https://github.com/golang/go/wiki/Modules), dependencies will Clone the repository: ``` -git clone https://github.com/eth-classic/go-ethereum.git getc && cd getc +git clone https://github.com/etclabscore/go-ethereum.git getc && cd getc ``` Build all executables: @@ -79,7 +78,7 @@ This repository includes several wrappers/executables found in the `cmd` directo | `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. | | `disasm` | Bytecode disassembler to convert EVM (Ethereum Virtual Machine) bytecode into more user friendly assembly-like opcodes (e.g. `echo "6001" | disasm`). For details on the individual opcodes, please see pages 22-30 of the [Ethereum Yellow Paper](http://gavwood.com/paper.pdf). | | `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow insolated, fine graned debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). | -| `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/eth-classic/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereumproject/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/eth-classic/rpc-tests/blob/master/README.md) for details. | +| `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/etclabscore/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereumproject/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/etclabscore/rpc-tests/blob/master/README.md) for details. | | `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereumproject/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | ## :green_book: Getting started with Geth Classic @@ -207,7 +206,7 @@ You'll need to use your own programming environments' capabilities (libraries, t > Note: Please understand the security implications of opening up an HTTP/WS based transport before doing so! Hackers on the internet are actively trying to subvert Ethereum nodes with exposed APIs! Further, all browser tabs can access locally running webservers, so malicious webpages could try to subvert locally available APIs!* ### Operating a private/custom network -As of [Geth 3.4](https://github.com/eth-classic/go-ethereum/releases) you are now able to configure a private chain by specifying an __external chain configuration__ JSON file, which includes necessary genesis block data as well as feature configurations for protocol forks, bootnodes, and chainID. +As of [Geth 3.4](https://github.com/etclabscore/go-ethereum/releases) you are now able to configure a private chain by specifying an __external chain configuration__ JSON file, which includes necessary genesis block data as well as feature configurations for protocol forks, bootnodes, and chainID. Please find full [example external configuration files representing the Mainnet and Morden Testnet specs in the /config subdirectory of this repo](). You can use either of these files as a starting point for your own customizations. diff --git a/core/database_util_test.go b/core/database_util_test.go index a148f3173..c755ec9a5 100644 --- a/core/database_util_test.go +++ b/core/database_util_test.go @@ -702,6 +702,112 @@ func TestReceiptStorage(t *testing.T) { } } +func TestReceiptStorageEncoding(t *testing.T) { + var w bytes.Buffer + r := &types.ReceiptForStorage{ + PostState: []byte{0x01, 0x02}, + Status: types.TxSuccess, + CumulativeGasUsed: big.NewInt(1), + Logs: vm.Logs{ + &vm.Log{Address: common.BytesToAddress([]byte{0x11})}, + &vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})}, + }, + TxHash: common.BytesToHash([]byte{0x12, 0x11}), + ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), + GasUsed: big.NewInt(111111), + } + + r.EncodeRLP(&w) + + var encodedReceipt types.ReceiptForStorage + stream := rlp.NewStream(bytes.NewReader(w.Bytes()), 0) + encodedReceipt.DecodeRLP(stream) + + if bytes.Compare(encodedReceipt.PostState, r.PostState) != 0 { + t.Errorf("Old storage receipt PostState: have (%v) want (%v)", encodedReceipt.PostState, r.PostState) + } + if encodedReceipt.Status != r.Status { + t.Errorf("Old storage receipt status: have (%v) want (%v)", encodedReceipt.Status, r.Status) + } + if encodedReceipt.CumulativeGasUsed.Cmp(r.CumulativeGasUsed) != 0 { + t.Errorf("Old storage receipt CumulativeGasUsed: have (%v) want (%v)", encodedReceipt.CumulativeGasUsed, r.CumulativeGasUsed) + } + if encodedReceipt.TxHash != r.TxHash { + t.Errorf("Old storage receipt TxHash: have (%v) want (%v)", encodedReceipt.TxHash, r.TxHash) + } + if encodedReceipt.ContractAddress != r.ContractAddress { + t.Errorf("Old storage receipt ContractAddress: have (%v) want (%v)", encodedReceipt.ContractAddress, r.ContractAddress) + } + if encodedReceipt.GasUsed.Cmp(r.GasUsed) != 0 { + t.Errorf("Old storage receipt GasUsed: have (%v) want (%v)", encodedReceipt.GasUsed, r.GasUsed) + } + for i, log := range r.Logs { + if bytes.Compare(r.Logs[i].Data, log.Data) != 0 { + t.Errorf("Old storage receipt Log: have (%v) want (%v)", log.Data, r.Logs[i].Data) + } + } +} + +func TestOldReceiptStorageTransition(t *testing.T) { + var w bytes.Buffer + r := &types.Receipt{ + PostState: []byte{0x24, 0x12}, + Status: types.TxSuccess, + CumulativeGasUsed: big.NewInt(1), + Logs: vm.Logs{ + &vm.Log{Address: common.BytesToAddress([]byte{0x11})}, + &vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})}, + }, + TxHash: common.BytesToHash([]byte{0x11, 0x11}), + ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), + GasUsed: big.NewInt(111111), + } + + logs := make([]*vm.LogForStorage, len(r.Logs)) + for i, log := range r.Logs { + logs[i] = (*vm.LogForStorage)(log) + } + + rlp.Encode(&w, []interface{}{ + r.PostState, + r.CumulativeGasUsed, + r.Bloom, + r.TxHash, + r.ContractAddress, + logs, + r.GasUsed, + r.Status, + }) + + var encodedReceipt types.ReceiptForStorage + stream := rlp.NewStream(bytes.NewReader(w.Bytes()), 0) + encodedReceipt.DecodeRLP(stream) + + if bytes.Compare(encodedReceipt.PostState, r.PostState) != 0 { + t.Errorf("Old storage receipt PostState: have (%v) want (%v)", encodedReceipt.PostState, r.PostState) + } + if encodedReceipt.Status != r.Status { + t.Errorf("Old storage receipt status: have (%v) want (%v)", encodedReceipt.Status, r.Status) + } + if encodedReceipt.CumulativeGasUsed.Cmp(r.CumulativeGasUsed) != 0 { + t.Errorf("Old storage receipt CumulativeGasUsed: have (%v) want (%v)", encodedReceipt.CumulativeGasUsed, r.CumulativeGasUsed) + } + if encodedReceipt.TxHash != r.TxHash { + t.Errorf("Old storage receipt TxHash: have (%v) want (%v)", encodedReceipt.TxHash, r.TxHash) + } + if encodedReceipt.ContractAddress != r.ContractAddress { + t.Errorf("Old storage receipt ContractAddress: have (%v) want (%v)", encodedReceipt.ContractAddress, r.ContractAddress) + } + if encodedReceipt.GasUsed.Cmp(r.GasUsed) != 0 { + t.Errorf("Old storage receipt GasUsed: have (%v) want (%v)", encodedReceipt.GasUsed, r.GasUsed) + } + for i, log := range r.Logs { + if bytes.Compare(r.Logs[i].Data, log.Data) != 0 { + t.Errorf("Old storage receipt Log: have (%v) want (%v)", log.Data, r.Logs[i].Data) + } + } +} + // Tests that receipts associated with a single block can be stored and retrieved. func TestBlockReceiptStorage(t *testing.T) { db, _ := ethdb.NewMemDatabase() diff --git a/core/execution.go b/core/execution.go index ef496509a..a3ae9cdc4 100644 --- a/core/execution.go +++ b/core/execution.go @@ -45,7 +45,6 @@ var ( // the necessary steps to create accounts and reverses the state in case of an // execution error or failed value transfer. func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) { - evm := env.Vm() // Depth check execution. Fail if we're trying to execute above the limit. if env.Depth() > callCreateDepthMax { caller.ReturnGas(gas, gasPrice) @@ -86,7 +85,7 @@ func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input defer contract.Finalise() // Even if the account has no code, we need to continue because it might be a precompile - ret, err = evm.Run(contract, input, false) + ret, err = env.Vm().Run(contract, input, false) // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally @@ -102,7 +101,6 @@ func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input // CallCode executes the given address' code as the given contract address func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) { - evm := env.Vm() // Depth check execution. Fail if we're trying to execute above the limit. if env.Depth() > callCreateDepthMax { caller.ReturnGas(gas, gasPrice) @@ -127,7 +125,7 @@ func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, in defer contract.Finalise() // Even if the account has no code, we need to continue because it might be a precompile - ret, err = evm.Run(contract, input, false) + ret, err = env.Vm().Run(contract, input, false) if err != nil { env.RevertToSnapshot(snapshot) @@ -140,7 +138,6 @@ func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, in // DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) { - evm := env.Vm() // Depth check execution. Fail if we're trying to execute above the limit. if env.Depth() > callCreateDepthMax { caller.ReturnGas(gas, gasPrice) @@ -165,7 +162,7 @@ func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address defer contract.Finalise() // Even if the account has no code, we need to continue because it might be a precompile - ret, err = evm.Run(contract, input, false) + ret, err = env.Vm().Run(contract, input, false) // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally @@ -181,7 +178,6 @@ func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address // StaticCall executes within the given contract and throws exception if state is attempted to be changed func StaticCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) { - evm := env.Vm() // Depth check execution. Fail if we're trying to execute above the limit. if env.Depth() > callCreateDepthMax { caller.ReturnGas(gas, gasPrice) @@ -211,7 +207,7 @@ func StaticCall(env vm.Environment, caller vm.ContractRef, addr common.Address, env.Db().AddBalance(addr, big.NewInt(0)) // Even if the account has no code, we need to continue because it might be a precompile - ret, err = evm.Run(contract, input, true) + ret, err = env.Vm().Run(contract, input, true) // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally @@ -227,20 +223,6 @@ func StaticCall(env vm.Environment, caller vm.ContractRef, addr common.Address, // Create creates a new contract with the given code func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) { - ret, address, err = create(env, caller, crypto.Keccak256Hash(code), code, gas, gasPrice, value) - // Here we get an error if we run into maximum stack depth, - // See: https://github.com/ethereum/yellowpaper/pull/131 - // and YP definitions for CREATE - - //if there's an error we return nothing - if err != nil && err != vm.ErrRevert { - return nil, address, err - } - return ret, address, err -} - -func create(env vm.Environment, caller vm.ContractRef, codeHash common.Hash, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) { - evm := env.Vm() // Depth check execution. Fail if we're trying to execute above the limit. if env.Depth() > callCreateDepthMax { caller.ReturnGas(gas, gasPrice) @@ -281,10 +263,10 @@ func create(env vm.Environment, caller vm.ContractRef, codeHash common.Hash, cod // EVM. The contract is a scoped environment for this execution context // only. contract := vm.NewContract(caller, to, value, gas, gasPrice) - contract.SetCallCode(nil, codeHash, code) + contract.SetCallCode(nil, crypto.Keccak256Hash(code), code) defer contract.Finalise() - ret, err = evm.Run(contract, nil, false) + ret, err = env.Vm().Run(contract, nil, false) maxCodeSizeExceeded := len(ret) > maxCodeSize && env.RuleSet().IsAtlantis(env.BlockNumber()) // if the contract creation ran successfully and no errors were returned @@ -317,6 +299,10 @@ func create(env vm.Environment, caller vm.ContractRef, codeHash common.Hash, cod err = errMaxCodeSizeExceeded } + //if there's an error we return nothing + if err != nil && err != vm.ErrRevert { + return nil, address, err + } return ret, address, err } diff --git a/core/state/state_object.go b/core/state/state_object.go index 57068813b..3c65cc8e9 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -386,18 +386,27 @@ func (self *StateObject) Value() *big.Int { panic("Value on StateObject should never be called") } -func (self *StateObject) ForEachStorage(cb func(key, value common.Hash) bool) { - // When iterating over the storage check the cache first - for h, value := range self.cachedStorage { - cb(h, value) - } - - it := trie.NewIterator(self.getTrie(self.db.db).NodeIterator(nil)) +func (s *StateObject) ForEachStorage(cb func(key, value common.Hash) bool) error { + it := trie.NewIterator(s.getTrie(s.db.db).NodeIterator(nil)) for it.Next() { // ignore cached values - key := common.BytesToHash(self.trie.GetKey(it.Key)) - if _, ok := self.cachedStorage[key]; !ok { - cb(key, common.BytesToHash(it.Value)) + key := common.BytesToHash(s.trie.GetKey(it.Key)) + if value, dirty := s.dirtyStorage[key]; dirty { + if cb(key, value) { + return nil + } + continue + } + + if len(it.Value) > 0 { + _, content, _, err := rlp.Split(it.Value) + if err != nil { + return err + } + if !cb(key, common.BytesToHash(content)) { + return nil + } } } + return nil } diff --git a/core/state/statedb.go b/core/state/statedb.go index 82ede1580..f6e260bed 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -481,8 +481,12 @@ func (self *StateDB) Copy() *StateDB { } for hash, logs := range self.logs { - state.logs[hash] = make(vm.Logs, len(logs)) - copy(state.logs[hash], logs) + cpy := make([]*vm.Log, len(logs)) + for i, l := range logs { + cpy[i] = new(vm.Log) + *cpy[i] = *l + } + state.logs[hash] = cpy } for hash, preimage := range self.preimages { state.preimages[hash] = preimage @@ -558,27 +562,6 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { s.clearJournalAndRefund() } -// DeleteSuicides flags the suicided objects for deletion so that it -// won't be referenced again when called / queried up on. -// -// DeleteSuicides should not be used for consensus related updates -// under any circumstances. -func (s *StateDB) DeleteSuicides() { - // Reset refund so that any used-gas calculations can use this method. - s.clearJournalAndRefund() - - for addr := range s.stateObjectsDirty { - stateObject := s.stateObjects[addr] - - // If the object has been removed by a suicide - // flag the object as deleted. - if stateObject.suicided { - stateObject.deleted = true - } - delete(s.stateObjectsDirty, addr) - } -} - func (s *StateDB) clearJournalAndRefund() { s.journal = newJournal() s.validRevisions = s.validRevisions[:0] @@ -624,23 +607,32 @@ func (s *StateDB) CommitTo(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (ro return root, err } -func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) { +func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) error { so := db.getStateObject(addr) if so == nil { - return - } - - // When iterating over the storage check the cache first - for h, value := range so.cachedStorage { - cb(h, value) + return nil } it := trie.NewIterator(so.getTrie(db.db).NodeIterator(nil)) for it.Next() { // ignore cached values key := common.BytesToHash(db.trie.GetKey(it.Key)) - if _, ok := so.cachedStorage[key]; !ok { - cb(key, common.BytesToHash(it.Value)) + if value, dirty := so.dirtyStorage[key]; dirty { + if cb(key, value) { + return nil + } + continue + } + + if len(it.Value) > 0 { + _, content, _, err := rlp.Split(it.Value) + if err != nil { + return err + } + if !cb(key, common.BytesToHash(content)) { + return nil + } } } + return nil } diff --git a/core/state_processor.go b/core/state_processor.go index 0fcfc6f67..db23cc93b 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -87,7 +87,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB) (ty if UseSputnikVM != "true" { receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas) if err != nil { - return nil, nil, totalUsedGas, err + return nil, nil, nil, err } receipts = append(receipts, receipt) allLogs = append(allLogs, logs...) @@ -95,7 +95,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB) (ty } receipt, logs, _, err := ApplyMultiVmTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas) if err != nil { - return nil, nil, totalUsedGas, err + return nil, nil, nil, err } receipts = append(receipts, receipt) allLogs = append(allLogs, logs...) diff --git a/core/tx_pool.go b/core/tx_pool.go index a42e8f2a4..81b595166 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -297,7 +297,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) (e error) { return } - intrGas := IntrinsicGas(tx.Data(), MessageCreatesContract(tx), pool.homestead) + intrGas := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) if tx.Gas().Cmp(intrGas) < 0 { e = ErrIntrinsicGas return diff --git a/core/types/receipt.go b/core/types/receipt.go index f1bd1b189..d56fccdea 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -57,7 +57,7 @@ type Receipt struct { // storedReceiptRLP is the storage encoding of a receipt. type storedReceiptRLP struct { - PostStateOrStatus []byte + PostState []byte CumulativeGasUsed *big.Int Bloom Bloom TxHash common.Hash @@ -66,9 +66,9 @@ type storedReceiptRLP struct { GasUsed *big.Int } -// storedReceiptRLP is the storage encoding of a receipt. -type oldStoredReceiptRLP struct { - PostStateOrStatus []byte +// storedReceiptRLPWithStatus is the storage encoding of a receipt. +type storedReceiptRLPWithStatus struct { + PostState []byte CumulativeGasUsed *big.Int Bloom Bloom TxHash common.Hash @@ -159,14 +159,15 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error { for i, log := range r.Logs { logs[i] = (*vm.LogForStorage)(log) } - receiptToStore := &storedReceiptRLP{ - PostStateOrStatus: (*Receipt)(r).statusEncoding(), + receiptToStore := &storedReceiptRLPWithStatus{ + PostState: r.PostState, CumulativeGasUsed: r.CumulativeGasUsed, Logs: logs, Bloom: r.Bloom, TxHash: r.TxHash, ContractAddress: r.ContractAddress, GasUsed: r.GasUsed, + Status: r.Status, } return rlp.Encode(w, receiptToStore) } @@ -179,12 +180,12 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { return err } - // Try decoding the receipt without Status first - if err := decodeStoredReceiptRLP(r, raw); err == nil { + // Try decoding the receipt with Status first + if err := decodeStoredReceiptRLPWithStatus(r, raw); err == nil { return nil } - return decodeOldStoredReceiptRLP(r, raw) + return decodeStoredReceiptRLP(r, raw) } // Decode stored receipt @@ -205,21 +206,33 @@ func decodeStoredReceiptRLP(r *ReceiptForStorage, raw []byte) error { r.Logs[i] = (*vm.Log)(log) } - if err := (*Receipt)(r).setStatus(receipt.PostStateOrStatus); err != nil { - return err - } + r.decodePostStateOrStatus(receipt) return nil } +// Previous version encoded tx Status in place of PostState, to ensure compatibility, +// this status needs to be decoded from PostState +func (r *ReceiptForStorage) decodePostStateOrStatus(sr storedReceiptRLP) { + if bytes.Equal(sr.PostState, receiptStatusSuccessfulRLP) { + r.Status = TxSuccess + return + } else if bytes.Equal(sr.PostState, receiptStatusFailedRLP) { + r.Status = TxFailure + return + } + r.PostState = sr.PostState + r.Status = TxStatusUnknown +} + // Decode with status field included in storage -func decodeOldStoredReceiptRLP(r *ReceiptForStorage, raw []byte) error { - var receipt oldStoredReceiptRLP +func decodeStoredReceiptRLPWithStatus(r *ReceiptForStorage, raw []byte) error { + var receipt storedReceiptRLPWithStatus if err := rlp.DecodeBytes(raw, &receipt); err != nil { return err } - r.PostState = receipt.PostStateOrStatus + r.PostState = receipt.PostState r.Status = receipt.Status r.CumulativeGasUsed = receipt.CumulativeGasUsed r.Bloom = receipt.Bloom diff --git a/core/vm/contract.go b/core/vm/contract.go index ad0fd7ddc..8d21877a7 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -28,7 +28,7 @@ type ContractRef interface { Address() common.Address Value() *big.Int SetCode(common.Hash, []byte) - ForEachStorage(callback func(key, value common.Hash) bool) + ForEachStorage(callback func(key, value common.Hash) bool) error } // Contract represents an ethereum contract in the state database. It contains @@ -159,8 +159,8 @@ func (self *Contract) SetCallCode(addr *common.Address, hash common.Hash, code [ // EachStorage iterates the contract's storage and calls a method for every key // value pair. -func (self *Contract) ForEachStorage(cb func(key, value common.Hash) bool) { - self.caller.ForEachStorage(cb) +func (self *Contract) ForEachStorage(cb func(key, value common.Hash) bool) error { + return self.caller.ForEachStorage(cb) } func (c *Contract) isValidJump(pc *uint64, to *big.Int) bool { diff --git a/core/vm/environment.go b/core/vm/environment.go index 0c9722778..196a2d239 100644 --- a/core/vm/environment.go +++ b/core/vm/environment.go @@ -134,6 +134,6 @@ type Account interface { Address() common.Address ReturnGas(*big.Int, *big.Int) SetCode(common.Hash, []byte) - ForEachStorage(cb func(key, value common.Hash) bool) + ForEachStorage(cb func(key, value common.Hash) bool) error Value() *big.Int } diff --git a/eth/api.go b/eth/api.go index f06a43f17..b7e6c3d0b 100644 --- a/eth/api.go +++ b/eth/api.go @@ -568,14 +568,14 @@ type PublicBlockChainAPI struct { // NewPublicBlockChainAPI creates a new Etheruem blockchain API. func NewPublicBlockChainAPI(config *core.ChainConfig, bc *core.BlockChain, m *miner.Miner, chainDb ethdb.Database, gpo *GasPriceOracle, eventMux *event.TypeMux, am *accounts.Manager) *PublicBlockChainAPI { api := &PublicBlockChainAPI{ - config: config, - bc: bc, - miner: m, - chainDb: chainDb, - eventMux: eventMux, - am: am, + config: config, + bc: bc, + miner: m, + chainDb: chainDb, + eventMux: eventMux, + am: am, newBlockSubscriptions: make(map[string]func(core.ChainEvent) error), - gpo: gpo, + gpo: gpo, } go api.subscriptionLoop() @@ -2154,7 +2154,7 @@ func (s *PublicDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int) (core. if err != nil { return nil, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err) } - statedb.DeleteSuicides() + statedb.Finalise(true) } return nil, nil, fmt.Errorf("tx index %d out of range for block %x", txIndex, blockHash) } diff --git a/go.mod b/go.mod index b9f077a08..22169d7c6 100644 --- a/go.mod +++ b/go.mod @@ -33,3 +33,5 @@ require ( gopkg.in/karalabe/cookiejar.v2 v2.0.0-20150724131613-8dcd6a7f4951 gopkg.in/urfave/cli.v1 v1.17.0 ) + +replace github.com/eth-classic/go-ethereum/accounts/abi/bind v0.0.0-20190521151733-fe17e9e1e2ce => ./accounts/abi/bind