diff --git a/.circleci/config.yml b/.circleci/config.yml index 34aacc296..b75e1ea2c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,13 +9,12 @@ sputnik_vm_steps: &sputnik_vm_steps command: | export GOPATH=$HOME/go export PATH=$PATH:$HOME/.cargo/bin:$HOME/janusbin - git clone https://github.com/ethereumproject/sputnikvm-ffi $GOPATH/src/github.com/ethereumproject/sputnikvm-ffi - cd $GOPATH/src/github.com/ethereumproject/sputnikvm-ffi/c/ffi && cargo build --release - cp $GOPATH/src/github.com/ethereumproject/sputnikvm-ffi/c/ffi/target/release/libsputnikvm_ffi.a $GOPATH/src/github.com/ethereumproject/sputnikvm-ffi/c/libsputnikvm.a + cd $GOPATH/src/github.com/ethereumproject/go-ethereum + make -C vendor/github.com/ethereumproject/sputnikvm-ffi/c - persist_to_workspace: root: ~/ paths: - - go/src/github.com/ethereumproject/sputnikvm-ffi/c/libsputnikvm.a + - go/src/github.com/ethereumproject/go-ethereum/vendor/github.com/ethereumproject/sputnikvm-ffi/c/libsputnikvm.a deploy_steps: &deploy_steps steps: @@ -48,7 +47,7 @@ unit_tests_steps: &unit_tests_steps export GOPATH=$HOME/go export GOBIN=$GOPATH/bin export PATH=$PATH:$GOBIN - export CGO_LDFLAGS="$GOPATH/src/github.com/ethereumproject/sputnikvm-ffi/c/libsputnikvm.a -ldl" + export CGO_LDFLAGS="$GOPATH/src/github.com/ethereumproject/go-ethereum/vendor/github.com/ethereumproject/sputnikvm-ffi/c/libsputnikvm.a -ldl" if [ "$(uname)" == "Darwin" ]; then export CGO_LDFLAGS="$CGO_LDFLAGS -lresolv" fi @@ -68,7 +67,7 @@ bats_tests_steps: &bats_tests_steps name: Run bats tests command: | export GOPATH=$HOME/go - export CGO_LDFLAGS="$GOPATH/src/github.com/ethereumproject/sputnikvm-ffi/c/libsputnikvm.a -ldl" + export CGO_LDFLAGS="$GOPATH/src/github.com/ethereumproject/go-ethereum/vendor/github.com/ethereumproject/sputnikvm-ffi/c/libsputnikvm.a -ldl" if [ "$(uname)" == "Darwin" ]; then export CGO_LDFLAGS="$CGO_LDFLAGS -lresolv" else diff --git a/Gopkg.lock b/Gopkg.lock index 598e35476..62c7cf65e 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -28,7 +28,25 @@ [[projects]] branch = "master" name = "github.com/ethereumproject/benchmark" - packages = ["rtprof","rtprof/pprof/driver","rtprof/pprof/internal/binutils","rtprof/pprof/internal/driver","rtprof/pprof/internal/elfexec","rtprof/pprof/internal/graph","rtprof/pprof/internal/measurement","rtprof/pprof/internal/plugin","rtprof/pprof/internal/report","rtprof/pprof/internal/symbolizer","rtprof/pprof/internal/symbolz","rtprof/pprof/measurement","rtprof/pprof/profile","rtprof/pprof/third_party/d3","rtprof/pprof/third_party/d3flamegraph","rtprof/pprof/third_party/d3tip","rtprof/pprof/third_party/svg"] + packages = [ + "rtprof", + "rtprof/pprof/driver", + "rtprof/pprof/internal/binutils", + "rtprof/pprof/internal/driver", + "rtprof/pprof/internal/elfexec", + "rtprof/pprof/internal/graph", + "rtprof/pprof/internal/measurement", + "rtprof/pprof/internal/plugin", + "rtprof/pprof/internal/report", + "rtprof/pprof/internal/symbolizer", + "rtprof/pprof/internal/symbolz", + "rtprof/pprof/measurement", + "rtprof/pprof/profile", + "rtprof/pprof/third_party/d3", + "rtprof/pprof/third_party/d3flamegraph", + "rtprof/pprof/third_party/d3tip", + "rtprof/pprof/third_party/svg" + ] revision = "8eff34efba2579d41fe2fb772fe1a3c89f6496ce" [[projects]] @@ -38,10 +56,10 @@ revision = "65a5b25efc277ff0996160cc3c76a44bec7a11fb" [[projects]] - branch = "master" + branch = "vm-failed" name = "github.com/ethereumproject/sputnikvm-ffi" packages = ["go/sputnikvm"] - revision = "a6c914124a94151706443826c8124896ab1473bc" + revision = "67fde4837870516c14cf253f8e956141c9d586f9" [[projects]] name = "github.com/fatih/color" @@ -64,13 +82,24 @@ [[projects]] branch = "master" name = "github.com/hashicorp/golang-lru" - packages = [".","simplelru"] + packages = [ + ".", + "simplelru" + ] revision = "0a025b7e63adc15a622f29b0b2c4c3848243bbf6" [[projects]] branch = "master" name = "github.com/huin/goupnp" - packages = [".","dcps/internetgateway1","dcps/internetgateway2","httpu","scpd","soap","ssdp"] + packages = [ + ".", + "dcps/internetgateway1", + "dcps/internetgateway2", + "httpu", + "scpd", + "soap", + "ssdp" + ] revision = "dceda08e705b2acee36aab47d765ed801f64cfc7" [[projects]] @@ -88,7 +117,12 @@ [[projects]] branch = "master" name = "github.com/mailru/easyjson" - packages = [".","buffer","jlexer","jwriter"] + packages = [ + ".", + "buffer", + "jlexer", + "jwriter" + ] revision = "32fa128f234d041f196a9f3e0fea5ac9772c08e1" [[projects]] @@ -153,7 +187,15 @@ [[projects]] branch = "master" name = "github.com/robertkrimen/otto" - packages = [".","ast","dbg","file","parser","registry","token"] + packages = [ + ".", + "ast", + "dbg", + "file", + "parser", + "registry", + "token" + ] revision = "3b44b4dcb6c00477273595c312908e2412d07da6" [[projects]] @@ -164,44 +206,97 @@ [[projects]] name = "github.com/spf13/afero" - packages = [".","mem"] + packages = [ + ".", + "mem" + ] revision = "63644898a8da0bc22138abf860edaf5277b6102e" version = "v1.1.0" [[projects]] branch = "master" name = "github.com/syndtr/goleveldb" - packages = ["leveldb","leveldb/cache","leveldb/comparer","leveldb/errors","leveldb/filter","leveldb/iterator","leveldb/journal","leveldb/memdb","leveldb/opt","leveldb/storage","leveldb/table","leveldb/util"] + packages = [ + "leveldb", + "leveldb/cache", + "leveldb/comparer", + "leveldb/errors", + "leveldb/filter", + "leveldb/iterator", + "leveldb/journal", + "leveldb/memdb", + "leveldb/opt", + "leveldb/storage", + "leveldb/table", + "leveldb/util" + ] revision = "34011bf325bce385408353a30b101fe5e923eb6e" [[projects]] branch = "master" name = "golang.org/x/crypto" - packages = ["pbkdf2","ripemd160","scrypt"] + packages = [ + "pbkdf2", + "ripemd160", + "scrypt" + ] revision = "d585fd2cc9195196078f516b69daff6744ef5e84" [[projects]] branch = "master" name = "golang.org/x/net" - packages = ["html","html/atom","html/charset","websocket"] + packages = [ + "html", + "html/atom", + "html/charset", + "websocket" + ] revision = "d866cfc389cec985d6fda2859936a575a55a3ab6" [[projects]] branch = "master" name = "golang.org/x/sys" - packages = ["unix","windows","windows/registry"] + packages = [ + "unix", + "windows", + "windows/registry" + ] revision = "83801418e1b59fb1880e363299581ee543af32ca" [[projects]] branch = "master" name = "golang.org/x/text" - packages = ["encoding","encoding/charmap","encoding/htmlindex","encoding/internal","encoding/internal/identifier","encoding/japanese","encoding/korean","encoding/simplifiedchinese","encoding/traditionalchinese","encoding/unicode","internal/gen","internal/tag","internal/triegen","internal/ucd","internal/utf8internal","language","runes","transform","unicode/cldr","unicode/norm"] + packages = [ + "encoding", + "encoding/charmap", + "encoding/htmlindex", + "encoding/internal", + "encoding/internal/identifier", + "encoding/japanese", + "encoding/korean", + "encoding/simplifiedchinese", + "encoding/traditionalchinese", + "encoding/unicode", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "internal/utf8internal", + "language", + "runes", + "transform", + "unicode/cldr", + "unicode/norm" + ] revision = "e19ae1496984b1c655b8044a65c0300a3c878dd3" [[projects]] branch = "master" name = "golang.org/x/tools" - packages = ["go/ast/astutil","imports"] + packages = [ + "go/ast/astutil", + "imports" + ] revision = "b451b9aaee4dcf75f9f28cddb69b9d0ed17a9752" [[projects]] @@ -224,7 +319,10 @@ [[projects]] name = "gopkg.in/sourcemap.v1" - packages = [".","base64vlq"] + packages = [ + ".", + "base64vlq" + ] revision = "6e83acea0053641eff084973fee085f0c193c61a" version = "v1.0.5" diff --git a/Makefile b/Makefile index 717158a76..ec681b26c 100644 --- a/Makefile +++ b/Makefile @@ -130,6 +130,8 @@ ${GOPATH}/bin/resources: clean: ## Remove local snapshot binary directory if [ -d ${BINARY} ] ; then rm -rf ${BINARY} ; fi go clean -i ./... + rm -rf vendor/github.com/ethereumproject/sputnikvm-ffi/c/ffi/target + rm -f vendor/github.com/ethereumproject/sputnikvm-ffi/c/libsputnikvm.* # Absolutely awesome: http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html help: diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 2648ce977..906186833 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -120,7 +120,7 @@ func (b *SimulatedBackend) ContractCall(contract common.Address, data []byte, pe vmenv := core.NewEnv(statedb, core.DefaultConfigMorden.ChainConfig, b.blockchain, msg, block.Header()) gaspool := new(core.GasPool).AddGas(common.MaxBig) - out, _, err := core.ApplyMessage(vmenv, msg, gaspool) + out, _, _, err := core.ApplyMessage(vmenv, msg, gaspool) return out, err } diff --git a/common/registrar/ethreg/api.go b/common/registrar/ethreg/api.go index b1ac2cbca..9aa6c4655 100644 --- a/common/registrar/ethreg/api.go +++ b/common/registrar/ethreg/api.go @@ -209,7 +209,7 @@ func (be *registryAPIBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr header := be.bc.CurrentBlock().Header() vmenv := core.NewEnv(statedb, be.config, be.bc, msg, header) gp := new(core.GasPool).AddGas(common.MaxBig) - res, gas, err := core.ApplyMessage(vmenv, msg, gp) + res, gas, _, err := core.ApplyMessage(vmenv, msg, gp) return common.ToHex(res), gas.String(), err } diff --git a/core/multivm_processor.go b/core/multivm_processor.go index 2ac2a960e..61d3660a8 100644 --- a/core/multivm_processor.go +++ b/core/multivm_processor.go @@ -179,6 +179,11 @@ Loop: receipt := types.NewReceipt(statedb.IntermediateRoot(false).Bytes(), totalUsedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = new(big.Int).Set(totalUsedGas) + if vm.Failed() { + receipt.Status = types.TxFailure + } else { + receipt.Status = types.TxSuccess + } if MessageCreatesContract(tx) { receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce()) } diff --git a/core/state_processor.go b/core/state_processor.go index 0ea042708..a00029048 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,10 +17,9 @@ package core import ( - "math/big" - "errors" "fmt" + "math/big" "github.com/ethereumproject/go-ethereum/core/state" "github.com/ethereumproject/go-ethereum/core/types" @@ -114,7 +113,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB) (ty func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int) (*types.Receipt, vm.Logs, *big.Int, error) { tx.SetSigner(config.GetSigner(header.Number)) - _, gas, err := ApplyMessage(NewEnv(statedb, config, bc, tx, header), tx, gp) + _, gas, failed, err := ApplyMessage(NewEnv(statedb, config, bc, tx, header), tx, gp) if err != nil { return nil, nil, nil, err } @@ -132,6 +131,11 @@ func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb logs := statedb.GetLogs(tx.Hash()) receipt.Logs = logs receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + if failed { + receipt.Status = types.TxFailure + } else { + receipt.Status = types.TxSuccess + } glog.V(logger.Debug).Infoln(receipt) diff --git a/core/state_transition.go b/core/state_transition.go index c96b7d58c..f57cc074b 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -127,11 +127,11 @@ func NewStateTransition(env vm.Environment, msg Message, gp *GasPool) *StateTran // the gas used (which includes gas refunds) and an error if it failed. An error always // indicates a core error meaning that the message would always fail for that particular // state and would never be accepted within a block. -func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.Int, error) { +func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.Int, bool, error) { st := NewStateTransition(env, msg, gp) - ret, _, gasUsed, err := st.TransitionDb() - return ret, gasUsed, err + ret, gasUsed, failed, err := st.TransitionDb() + return ret, gasUsed, failed, err } func (self *StateTransition) from() (vm.Account, error) { @@ -221,7 +221,7 @@ func (self *StateTransition) preCheck() (err error) { } // TransitionDb will move the state by applying the message against the given environment. -func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, err error) { +func (self *StateTransition) TransitionDb() (ret []byte, gas *big.Int, failed bool, err error) { if err = self.preCheck(); err != nil { return } @@ -232,45 +232,40 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b contractCreation := MessageCreatesContract(msg) // Pay intrinsic gas if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil { - return nil, nil, nil, InvalidTxError(err) + return nil, nil, false, InvalidTxError(err) } vmenv := self.env //var addr common.Address + var vmerr error if contractCreation { - ret, _, err = vmenv.Create(sender, self.data, self.gas, self.gasPrice, self.value) - if homestead && err == vm.CodeStoreOutOfGasError { + ret, _, vmerr = vmenv.Create(sender, self.data, self.gas, self.gasPrice, self.value) + if homestead && vmerr == vm.CodeStoreOutOfGasError { self.gas = big.NewInt(0) } - if err != nil { - ret = nil - glog.V(logger.Core).Infoln("VM create err:", err) + if vmerr != nil { + glog.V(logger.Core).Infoln("VM create err:", vmerr) } } else { // Increment the nonce for the next transaction self.state.SetNonce(sender.Address(), self.state.GetNonce(sender.Address())+1) - ret, err = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.gasPrice, self.value) - if err != nil { - glog.V(logger.Core).Infoln("VM call err:", err) + ret, vmerr = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.gasPrice, self.value) + if vmerr != nil { + glog.V(logger.Core).Infoln("VM call err:", vmerr) } } - if err != nil && IsValueTransferErr(err) { - return nil, nil, nil, InvalidTxError(err) + if vmerr != nil && IsValueTransferErr(vmerr) { + // if the vmerr was a value transfer error, return immediately + // transaction receipt status will be set to TxSuccess + return nil, nil, false, InvalidTxError(vmerr) } - // We aren't interested in errors here. Errors returned by the VM are non-consensus errors and therefor shouldn't bubble up - if err != nil { - err = nil - } - - requiredGas = new(big.Int).Set(self.gasUsed()) - self.refundGas() self.state.AddBalance(self.env.Coinbase(), new(big.Int).Mul(self.gasUsed(), self.gasPrice)) - return ret, requiredGas, self.gasUsed(), err + return ret, self.gasUsed(), vmerr != nil, err } func (self *StateTransition) refundGas() { @@ -285,7 +280,6 @@ func (self *StateTransition) refundGas() { refund := common.BigMin(uhalf, self.state.GetRefund()) self.gas.Add(self.gas, refund) self.state.AddBalance(sender.Address(), refund.Mul(refund, self.gasPrice)) - // Also return remaining gas to the block gas counter so it is // available for the next transaction. self.gp.AddGas(self.gas) diff --git a/core/types/receipt.go b/core/types/receipt.go index 279933dc6..66c057b63 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -26,6 +26,14 @@ import ( "github.com/ethereumproject/go-ethereum/rlp" ) +type ReceiptStatus byte + +const ( + TxFailure ReceiptStatus = 0 + TxSuccess ReceiptStatus = 1 + TxStatusUnknown ReceiptStatus = 0xFF +) + // Receipt represents the results of a transaction. type Receipt struct { // Consensus fields @@ -38,11 +46,12 @@ type Receipt struct { TxHash common.Hash ContractAddress common.Address GasUsed *big.Int + Status ReceiptStatus } // NewReceipt creates a barebone transaction receipt, copying the init fields. func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt { - return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)} + return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed), Status: TxStatusUnknown} } // EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt @@ -92,12 +101,21 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error { for i, log := range r.Logs { logs[i] = (*vm.LogForStorage)(log) } - return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed}) + return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed, r.Status}) } // DecodeRLP implements rlp.Decoder, and loads both consensus and implementation // fields of a receipt from an RLP stream. func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { + var oldReceipt struct { + PostState []byte + CumulativeGasUsed *big.Int + Bloom Bloom + TxHash common.Hash + ContractAddress common.Address + Logs []*vm.LogForStorage + GasUsed *big.Int + } var receipt struct { PostState []byte CumulativeGasUsed *big.Int @@ -106,10 +124,29 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { ContractAddress common.Address Logs []*vm.LogForStorage GasUsed *big.Int + Status ReceiptStatus } - if err := s.Decode(&receipt); err != nil { + receipt.Status = TxStatusUnknown + + raw, err := s.Raw() + if err != nil { return err } + + if err := rlp.DecodeBytes(raw, &receipt); err != nil { + if err := rlp.DecodeBytes(raw, &oldReceipt); err != nil { + return err + } + receipt.PostState = oldReceipt.PostState + receipt.CumulativeGasUsed = oldReceipt.CumulativeGasUsed + receipt.Bloom = oldReceipt.Bloom + receipt.TxHash = oldReceipt.TxHash + receipt.ContractAddress = oldReceipt.ContractAddress + receipt.Logs = oldReceipt.Logs + receipt.GasUsed = oldReceipt.GasUsed + receipt.Status = TxStatusUnknown + + } // Assign the consensus fields r.PostState, r.CumulativeGasUsed, r.Bloom = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom r.Logs = make(vm.Logs, len(receipt.Logs)) @@ -117,7 +154,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { r.Logs[i] = (*vm.Log)(log) } // Assign the implementation fields - r.TxHash, r.ContractAddress, r.GasUsed = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed + r.TxHash, r.ContractAddress, r.GasUsed, r.Status = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed, receipt.Status return nil } diff --git a/eth/api.go b/eth/api.go index 64afe8c54..1cb761274 100644 --- a/eth/api.go +++ b/eth/api.go @@ -1159,14 +1159,39 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma tx, _, err := getTransaction(s.chainDb, s.txPool, txHash) if err != nil { - glog.V(logger.Debug).Infof("%v\n", err) - return nil, nil + return nil, err } txBlock, blockIndex, index, err := getTransactionBlockData(s.chainDb, txHash) if err != nil { - glog.V(logger.Debug).Infof("%v\n", err) - return nil, nil + return nil, err + } + + if receipt.Status == types.TxStatusUnknown { + // To be able to get the proper state for n-th transaction in a block, + // all previous transactions has to be executed. Because of that, it is + // reasonable to reprocess entire block and update all receipts from + // given block. + proc := s.bc.Processor() + block := s.bc.GetBlock(txBlock) + parent := s.bc.GetBlock(block.ParentHash()) + statedb, err := s.bc.StateAt(parent.Root()) + if err != nil { + return nil, fmt.Errorf("state not found - transaction status is not available for fast synced block: %v", err) + } + + receipts, _, _, err := proc.Process(block, statedb) + if err != nil { + return nil, err + } + + if err := core.WriteReceipts(s.chainDb, receipts); err != nil { + glog.V(logger.Warn).Infof("cannot save updated receipts: %v", err) + } + if err := core.WriteBlockReceipts(s.chainDb, block.Hash(), receipts); err != nil { + glog.V(logger.Warn).Infof("cannot save updated block receipts: %v", err) + } + receipt = receipts[index] } var signer types.Signer = types.BasicSigner{} @@ -1198,6 +1223,12 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma fields["contractAddress"] = receipt.ContractAddress } + // We're not fully compatible with EIP-609 - just return status for all blocks. + fields["status"] = nil + if receipt.Status != types.TxStatusUnknown { + fields["status"] = receipt.Status + } + return fields, nil } @@ -2035,7 +2066,7 @@ func (s *PublicBlockChainAPI) TraceCall(args CallArgs, blockNr rpc.BlockNumber) vmenv := core.NewEnv(stateDb, s.config, s.bc, msg, block.Header()) gp := new(core.GasPool).AddGas(common.MaxBig) - ret, gas, err := core.ApplyMessage(vmenv, msg, gp) + ret, gas, _, err := core.ApplyMessage(vmenv, msg, gp) return &ExecutionResult{ Gas: gas, ReturnValue: fmt.Sprintf("%x", ret), @@ -2056,7 +2087,7 @@ func (s *PublicDebugAPI) TraceTransaction(txHash common.Hash) (*ExecutionResult, } gp := new(core.GasPool).AddGas(tx.Gas()) - ret, gas, err := core.ApplyMessage(vmenv, msg, gp) + ret, gas, _, err := core.ApplyMessage(vmenv, msg, gp) return &ExecutionResult{ Gas: gas, ReturnValue: fmt.Sprintf("%x", ret), @@ -2111,7 +2142,7 @@ func (s *PublicDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int) (core. } gp := new(core.GasPool).AddGas(tx.Gas()) - _, _, err := core.ApplyMessage(vmenv, msg, gp) + _, _, _, err := core.ApplyMessage(vmenv, msg, gp) if err != nil { return nil, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err) } diff --git a/eth/backend.go b/eth/backend.go index 38fbed262..01a20cdb1 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -660,7 +660,10 @@ func addMipmapBloomBins(db ethdb.Database) (err error) { if (hash == common.Hash{}) { return fmt.Errorf("chain db corrupted. Could not find block %d.", i) } - core.WriteMipmapBloom(db, i, core.GetBlockReceipts(db, hash)) + err := core.WriteMipmapBloom(db, i, core.GetBlockReceipts(db, hash)) + if err != nil { + return err + } } glog.V(logger.Info).Infoln("upgrade completed in", time.Since(tstart)) return nil diff --git a/tests/state_test_util.go b/tests/state_test_util.go index e0a435917..89af8fb93 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -239,7 +239,7 @@ func RunState(ruleSet RuleSet, db ethdb.Database, statedb *state.StateDB, env, t message := NewMessage(addr, to, data, value, gas, price, nonce) vmenv := NewEnvFromMap(ruleSet, statedb, env, tx) vmenv.origin = addr - ret, _, err := core.ApplyMessage(vmenv, message, gaspool) + ret, _, _, err := core.ApplyMessage(vmenv, message, gaspool) if core.IsNonceErr(err) || core.IsInvalidTxErr(err) || core.IsGasLimitErr(err) { statedb.RevertToSnapshot(snapshot) } diff --git a/vendor/github.com/ethereumproject/sputnikvm-ffi/c/Makefile b/vendor/github.com/ethereumproject/sputnikvm-ffi/c/Makefile index f125552e0..754c1ed6f 100644 --- a/vendor/github.com/ethereumproject/sputnikvm-ffi/c/Makefile +++ b/vendor/github.com/ethereumproject/sputnikvm-ffi/c/Makefile @@ -1,7 +1,7 @@ build: cd ffi && cargo build --release cp ffi/target/release/libsputnikvm_ffi.a libsputnikvm.a - cp ffi/target/release/libsputnikvm_ffi.so libsputnikvm.so + cp ffi/target/release/libsputnikvm_ffi.so libsputnikvm.so | true build-musl: cd ffi && docker run --rm -it -v "$(shell pwd)/ffi":/home/rust/src ekidd/rust-musl-builder cargo build --release @@ -10,4 +10,4 @@ build-musl: debug: cd ffi && cargo build cp ffi/target/debug/libsputnikvm_ffi.a libsputnikvm.a - cp ffi/target/debug/libsputnikvm_ffi.so libsputnikvm.so + cp ffi/target/debug/libsputnikvm_ffi.so libsputnikvm.so | true diff --git a/vendor/github.com/ethereumproject/sputnikvm-ffi/c/ffi/src/common.rs b/vendor/github.com/ethereumproject/sputnikvm-ffi/c/ffi/src/common.rs index f12d47767..539137b75 100644 --- a/vendor/github.com/ethereumproject/sputnikvm-ffi/c/ffi/src/common.rs +++ b/vendor/github.com/ethereumproject/sputnikvm-ffi/c/ffi/src/common.rs @@ -1,4 +1,4 @@ -use libc::{c_uchar, c_uint, c_longlong}; +use libc::{c_uchar}; use bigint::{U256, H256, Gas, Address}; // We use big-endian representation for c_u256 and c_gas. Note that @@ -138,3 +138,4 @@ impl From for c_h256 { a } } + diff --git a/vendor/github.com/ethereumproject/sputnikvm-ffi/c/ffi/src/lib.rs b/vendor/github.com/ethereumproject/sputnikvm-ffi/c/ffi/src/lib.rs index a316d5596..04c6c7e24 100644 --- a/vendor/github.com/ethereumproject/sputnikvm-ffi/c/ffi/src/lib.rs +++ b/vendor/github.com/ethereumproject/sputnikvm-ffi/c/ffi/src/lib.rs @@ -15,7 +15,7 @@ use libc::{c_uchar, c_uint, c_longlong}; use bigint::{U256, M256}; use sputnikvm::{TransactionAction, ValidTransaction, HeaderParams, SeqTransactionVM, Patch, MainnetFrontierPatch, MainnetHomesteadPatch, MainnetEIP150Patch, MainnetEIP160Patch, - VM, RequireError, AccountCommitment, AccountChange, + VM, VMStatus, RequireError, AccountCommitment, AccountChange, FrontierPatch, HomesteadPatch, EIP150Patch, EIP160Patch, AccountPatch}; type c_action = c_uchar; @@ -764,3 +764,18 @@ pub extern "C" fn sputnikvm_default_header_params() -> c_header_params { gas_limit: c_gas::default(), } } + +#[no_mangle] +pub extern "C" fn sputnikvm_status_failed(vm: *mut Box) -> c_uchar { + let mut vm_box = unsafe { Box::from_raw(vm) }; + let ret; + { + let vm: &mut VM = vm_box.deref_mut().deref_mut(); + match vm.status() { + VMStatus::ExitedErr(_) => ret = 1, + default => ret = 0, + } + } + Box::into_raw(vm_box); + ret +} diff --git a/vendor/github.com/ethereumproject/sputnikvm-ffi/c/sputnikvm.h b/vendor/github.com/ethereumproject/sputnikvm-ffi/c/sputnikvm.h index 8a2f00466..88f3a5b7a 100644 --- a/vendor/github.com/ethereumproject/sputnikvm-ffi/c/sputnikvm.h +++ b/vendor/github.com/ethereumproject/sputnikvm-ffi/c/sputnikvm.h @@ -335,3 +335,9 @@ sputnikvm_default_transaction(void); */ extern sputnikvm_header_params sputnikvm_default_header_params(void); + +/** + * Returns 1 if VM failed (VMStatus::ExitedErr), 0 otherwise (including VM is still running). + */ +extern char +sputnikvm_status_failed(sputnikvm_vm_t *vm); diff --git a/vendor/github.com/ethereumproject/sputnikvm-ffi/go/sputnikvm/sputnikvm.go b/vendor/github.com/ethereumproject/sputnikvm-ffi/go/sputnikvm/sputnikvm.go index 1afa7da35..641e61c71 100644 --- a/vendor/github.com/ethereumproject/sputnikvm-ffi/go/sputnikvm/sputnikvm.go +++ b/vendor/github.com/ethereumproject/sputnikvm-ffi/go/sputnikvm/sputnikvm.go @@ -33,12 +33,13 @@ package sputnikvm import "C" import ( - "unsafe" - "math/big" "github.com/ethereumproject/go-ethereum/common" + "math/big" + "unsafe" ) type AccountChangeType int + const ( AccountChangeIncreaseBalance = iota AccountChangeDecreaseBalance @@ -48,14 +49,14 @@ const ( ) type AccountChangeStorageItem struct { - Key *big.Int + Key *big.Int Value *big.Int } type AccountChange struct { - info C.sputnikvm_account_change + info C.sputnikvm_account_change storage []AccountChangeStorageItem - code []byte + code []byte } func (change *AccountChange) Typ() AccountChangeType { @@ -149,6 +150,7 @@ func (change *AccountChange) ChangedStorage() []AccountChangeStorageItem { } type RequireType int + const ( RequireNone = iota RequireAccount @@ -211,8 +213,8 @@ func (require *Require) BlockNumber() *big.Int { type Log struct { Address common.Address - Topics []common.Hash - Data []byte + Topics []common.Hash + Data []byte } type VM struct { @@ -220,21 +222,21 @@ type VM struct { } type Transaction struct { - Caller common.Address + Caller common.Address GasPrice *big.Int GasLimit *big.Int - Address *common.Address // If it is nil, then we take it as a Create transaction. - Value *big.Int - Input []byte - Nonce *big.Int + Address *common.Address // If it is nil, then we take it as a Create transaction. + Value *big.Int + Input []byte + Nonce *big.Int } type HeaderParams struct { Beneficiary common.Address - Timestamp uint64 - Number *big.Int - Difficulty *big.Int - GasLimit *big.Int + Timestamp uint64 + Number *big.Int + Difficulty *big.Int + GasLimit *big.Int } func PrintCU256(v C.sputnikvm_u256) { @@ -248,7 +250,7 @@ func ToCU256(v *big.Int) C.sputnikvm_u256 { if i < (32 - len(bytes)) { continue } - cu256.data[i] = C.uchar(bytes[i - (32 - len(bytes))]) + cu256.data[i] = C.uchar(bytes[i-(32-len(bytes))]) } return *cu256 } @@ -270,7 +272,7 @@ func ToCGas(v *big.Int) C.sputnikvm_gas { if i < (32 - len(bytes)) { continue } - cgas.data[i] = C.uchar(bytes[i - (32 - len(bytes))]) + cgas.data[i] = C.uchar(bytes[i-(32-len(bytes))]) } return *cgas } @@ -517,7 +519,7 @@ func SetCustomInitialNonce(nonce *big.Int) { func (vm *VM) Fire() Require { ret := C.sputnikvm_fire(vm.c) - return Require { + return Require{ c: ret, } } @@ -596,10 +598,10 @@ func (vm *VM) Logs() []Log { j_cdata := unsafe.Pointer(uintptr(cdata) + uintptr(j)) data[j] = byte(*(*C.uchar)(j_cdata)) } - logs = append(logs, Log { + logs = append(logs, Log{ Address: address, - Topics: topics, - Data: data, + Topics: topics, + Data: data, }) C.free(cdata) } @@ -615,10 +617,10 @@ func (vm *VM) AccountChanges() []AccountChange { for i := 0; i < int(l); i++ { i_cchange := unsafe.Pointer(uintptr(cchanges) + (uintptr(i) * uintptr(C.sizeof_sputnikvm_account_change))) cchange := (*C.sputnikvm_account_change)(i_cchange) - change := AccountChange { - info: *cchange, + change := AccountChange{ + info: *cchange, storage: make([]AccountChangeStorageItem, 0), - code: make([]byte, 0), + code: make([]byte, 0), } switch change.Typ() { case AccountChangeIncreaseBalance, AccountChangeDecreaseBalance, AccountChangeRemoved: @@ -635,8 +637,8 @@ func (vm *VM) AccountChanges() []AccountChange { for j := 0; j < int(uint(storage_len)); j++ { j_cstorage := unsafe.Pointer(uintptr(cstorage) + (uintptr(j) * uintptr(C.sizeof_sputnikvm_account_change_storage))) citem := (*C.sputnikvm_account_change_storage)(j_cstorage) - storage = append(storage, AccountChangeStorageItem { - Key: FromCU256(citem.key), + storage = append(storage, AccountChangeStorageItem{ + Key: FromCU256(citem.key), Value: FromCU256(citem.value), }) } @@ -661,3 +663,7 @@ func (vm *VM) AccountChanges() []AccountChange { C.free(cchanges) return changes } + +func (vm *VM) Failed() bool { + return uint(C.sputnikvm_status_failed(vm.c)) == 1 +}