diff --git a/.travis.yml b/.travis.yml index 703ed0cb1d..a972668c95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,11 +15,23 @@ matrix: - go run build/ci.go install - go run build/ci.go test -coverage - # These are the latest Go versions. - os: linux dist: trusty sudo: required go: 1.8.3 + script: + - sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install fuse + - sudo modprobe fuse + - sudo chmod 666 /dev/fuse + - sudo chown root:$USER /etc/fuse.conf + - go run build/ci.go install + - go run build/ci.go test -coverage + + # These are the latest Go versions. + - os: linux + dist: trusty + sudo: required + go: 1.9.0 script: - sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install fuse - sudo modprobe fuse @@ -29,7 +41,7 @@ matrix: - go run build/ci.go test -coverage -misspell - os: osx - go: 1.8.3 + go: 1.9.0 sudo: required script: - brew update @@ -42,7 +54,7 @@ matrix: - os: linux dist: trusty sudo: required - go: 1.8.3 + go: 1.9.0 env: - ubuntu-ppa - azure-linux @@ -81,7 +93,7 @@ matrix: sudo: required services: - docker - go: 1.8.3 + go: 1.9.0 env: - azure-linux-mips script: @@ -121,7 +133,7 @@ matrix: - azure-android - maven-android before_install: - - curl https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz | tar -xz + - curl https://storage.googleapis.com/golang/go1.9.linux-amd64.tar.gz | tar -xz - export PATH=`pwd`/go/bin:$PATH - export GOROOT=`pwd`/go - export GOPATH=$HOME/go @@ -138,7 +150,7 @@ matrix: # This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads - os: osx - go: 1.8.3 + go: 1.9.0 env: - azure-osx - azure-ios @@ -164,7 +176,7 @@ matrix: - os: linux dist: trusty sudo: required - go: 1.8.3 + go: 1.9.0 env: - azure-purge script: diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index e0ee06a0a1..88fb3331e8 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -253,7 +253,8 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM // about the transaction and calling mechanisms. vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{}) gaspool := new(core.GasPool).AddGas(math.MaxBig256) - ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() + // TODO utilize returned failed flag to help gas estimation. + ret, gasUsed, _, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() return ret, gasUsed, err } diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index 73e95e02a1..f587580884 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -122,7 +122,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La } // For Go bindings pass the code through goimports to clean it up and double check if lang == LangGo { - code, err := imports.Process("", buffer.Bytes(), nil) + code, err := imports.Process(".", buffer.Bytes(), nil) if err != nil { return "", fmt.Errorf("%v\n%s", err, buffer) } diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index 8ea3eca415..43ed53b922 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -459,7 +459,7 @@ func TestBindings(t *testing.T) { } // Skip the test if the go-ethereum sources are symlinked (https://github.com/golang/go/issues/14845) linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend(nil))\n}") - linkTestDeps, err := imports.Process("", []byte(linkTestCode), nil) + linkTestDeps, err := imports.Process(os.TempDir(), []byte(linkTestCode), nil) if err != nil { t.Fatalf("failed check for goimports symlink bug: %v", err) } diff --git a/appveyor.yml b/appveyor.yml index 945cafaf2e..78b11fa9d6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -23,8 +23,8 @@ environment: install: - git submodule update --init - rmdir C:\go /s /q - - appveyor DownloadFile https://storage.googleapis.com/golang/go1.8.3.windows-%GETH_ARCH%.zip - - 7z x go1.8.3.windows-%GETH_ARCH%.zip -y -oC:\ > NUL + - appveyor DownloadFile https://storage.googleapis.com/golang/go1.9.windows-%GETH_ARCH%.zip + - 7z x go1.9.windows-%GETH_ARCH%.zip -y -oC:\ > NUL - go version - gcc --version diff --git a/cmd/evm/json_logger.go b/cmd/evm/json_logger.go index d61981062c..2cfeaa7952 100644 --- a/cmd/evm/json_logger.go +++ b/cmd/evm/json_logger.go @@ -57,11 +57,15 @@ func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cos } // CaptureEnd is triggered at end of execution. -func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration) error { +func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error { type endLog struct { Output string `json:"output"` GasUsed math.HexOrDecimal64 `json:"gasUsed"` Time time.Duration `json:"time"` + Err string `json:"error,omitempty"` } - return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t}) + if err != nil { + return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, err.Error()}) + } + return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, ""}) } diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index ae56781103..96de0c76ac 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -234,13 +234,13 @@ Gas used: %d `, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas) } if tracer != nil { - tracer.CaptureEnd(ret, initialGas-leftOverGas, execTime) + tracer.CaptureEnd(ret, initialGas-leftOverGas, execTime, err) } else { fmt.Printf("0x%x\n", ret) + if err != nil { + fmt.Printf(" error: %v\n", err) + } } - if err != nil { - fmt.Printf(" error: %v\n", err) - } return nil } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index b257084719..37ccd06efb 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -120,7 +120,7 @@ var ( } NoUSBFlag = cli.BoolFlag{ Name: "nousb", - Usage: "Disables monitoring for and managine USB hardware wallets", + Usage: "Disables monitoring for and managing USB hardware wallets", } NetworkIdFlag = cli.Uint64Flag{ Name: "networkid", diff --git a/common/bytes.go b/common/bytes.go index c445968f22..66577bbfd0 100644 --- a/common/bytes.go +++ b/common/bytes.go @@ -47,6 +47,9 @@ func FromHex(s string) []byte { // // Returns an exact copy of the provided bytes func CopyBytes(b []byte) (copiedBytes []byte) { + if b == nil { + return nil + } copiedBytes = make([]byte, len(b)) copy(copiedBytes, b) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 01d97a470e..b714204458 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -36,8 +36,9 @@ import ( // Ethash proof-of-work protocol constants. var ( - blockReward *big.Int = big.NewInt(5e+18) // Block reward in wei for successfully mining a block - maxUncles = 2 // Maximum number of uncles allowed in a single block + frontierBlockReward *big.Int = big.NewInt(5e+18) // Block reward in wei for successfully mining a block + metropolisBlockReward *big.Int = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Metropolis + maxUncles = 2 // Maximum number of uncles allowed in a single block ) // Various error messages to mark blocks invalid. These should be private to @@ -306,6 +307,7 @@ var ( big9 = big.NewInt(9) big10 = big.NewInt(10) bigMinus99 = big.NewInt(-99) + big2999999 = big.NewInt(2999999) ) // calcDifficultyMetropolis is the difficulty adjustment algorithm. It returns @@ -346,8 +348,15 @@ func calcDifficultyMetropolis(time uint64, parent *types.Header) *big.Int { if x.Cmp(params.MinimumDifficulty) < 0 { x.Set(params.MinimumDifficulty) } + // calculate a fake block numer for the ice-age delay: + // https://github.com/ethereum/EIPs/pull/669 + // fake_block_number = min(0, block.number - 3_000_000 + fakeBlockNumber := new(big.Int) + if parent.Number.Cmp(big2999999) >= 0 { + fakeBlockNumber = fakeBlockNumber.Sub(parent.Number, big2999999) // Note, parent is 1 less than the actual block number + } // for the exponential factor - periodCount := new(big.Int).Add(parent.Number, big1) + periodCount := fakeBlockNumber periodCount.Div(periodCount, expDiffPeriod) // the exponential factor, commonly referred to as "the bomb" @@ -501,7 +510,7 @@ func (ethash *Ethash) Prepare(chain consensus.ChainReader, header *types.Header) // setting the final state and assembling the block. func (ethash *Ethash) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { // Accumulate any block and uncle rewards and commit the final state root - AccumulateRewards(state, header, uncles) + AccumulateRewards(chain.Config(), state, header, uncles) header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) // Header seems complete, assemble into a block and return @@ -518,7 +527,13 @@ var ( // reward. The total reward consists of the static block reward and rewards for // included uncles. The coinbase of each uncle block is also rewarded. // TODO (karalabe): Move the chain maker into this package and make this private! -func AccumulateRewards(state *state.StateDB, header *types.Header, uncles []*types.Header) { +func AccumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) { + // Select the correct block reward based on chain progression + blockReward := frontierBlockReward + if config.IsMetropolis(header.Number) { + blockReward = metropolisBlockReward + } + // Accumulate the rewards for the miner and any included uncles reward := new(big.Int).Set(blockReward) r := new(big.Int) for _, uncle := range uncles { diff --git a/core/chain_makers.go b/core/chain_makers.go index cb5825d187..dd3e2fb192 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -179,7 +179,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Dat if gen != nil { gen(i, b) } - ethash.AccumulateRewards(statedb, h, b.uncles) + ethash.AccumulateRewards(config, statedb, h, b.uncles) root, err := statedb.CommitTo(db, config.IsEIP158(h.Number)) if err != nil { panic(fmt.Sprintf("state write error: %v", err)) diff --git a/core/database_util_test.go b/core/database_util_test.go index e9a6df97b7..e91f1b5930 100644 --- a/core/database_util_test.go +++ b/core/database_util_test.go @@ -340,7 +340,7 @@ func TestBlockReceiptStorage(t *testing.T) { db, _ := ethdb.NewMemDatabase() receipt1 := &types.Receipt{ - PostState: []byte{0x01}, + Failed: true, CumulativeGasUsed: big.NewInt(1), Logs: []*types.Log{ {Address: common.BytesToAddress([]byte{0x11})}, @@ -351,7 +351,7 @@ func TestBlockReceiptStorage(t *testing.T) { GasUsed: big.NewInt(111111), } receipt2 := &types.Receipt{ - PostState: []byte{0x02}, + PostState: common.Hash{2}.Bytes(), CumulativeGasUsed: big.NewInt(2), Logs: []*types.Log{ {Address: common.BytesToAddress([]byte{0x22})}, @@ -461,12 +461,12 @@ func TestMipmapChain(t *testing.T) { var receipts types.Receipts switch i { case 1: - receipt := types.NewReceipt(nil, new(big.Int)) + receipt := types.NewReceipt(nil, false, new(big.Int)) receipt.Logs = []*types.Log{{Address: addr, Topics: []common.Hash{hash1}}} gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} case 1000: - receipt := types.NewReceipt(nil, new(big.Int)) + receipt := types.NewReceipt(nil, false, new(big.Int)) receipt.Logs = []*types.Log{{Address: addr2}} gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} diff --git a/core/state/journal.go b/core/state/journal.go index b5c8ca9a21..ddb76f1a2e 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -91,11 +91,6 @@ func (ch suicideChange) undo(s *StateDB) { if obj != nil { obj.suicided = ch.prev obj.setBalance(ch.prevbalance) - // if the object wasn't suicided before, remove - // it from the list of destructed objects as well. - if !obj.suicided { - delete(s.stateObjectsDestructed, *ch.account) - } } } diff --git a/core/state/statedb.go b/core/state/statedb.go index 694374f822..002fa62496 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -46,9 +46,8 @@ type StateDB struct { trie Trie // This map holds 'live' objects, which will get modified while processing a state transition. - stateObjects map[common.Address]*stateObject - stateObjectsDirty map[common.Address]struct{} - stateObjectsDestructed map[common.Address]struct{} + stateObjects map[common.Address]*stateObject + stateObjectsDirty map[common.Address]struct{} // DB error. // State objects are used by the consensus core and VM which are @@ -83,14 +82,13 @@ func New(root common.Hash, db Database) (*StateDB, error) { return nil, err } return &StateDB{ - db: db, - trie: tr, - stateObjects: make(map[common.Address]*stateObject), - stateObjectsDirty: make(map[common.Address]struct{}), - stateObjectsDestructed: make(map[common.Address]struct{}), - refund: new(big.Int), - logs: make(map[common.Hash][]*types.Log), - preimages: make(map[common.Hash][]byte), + db: db, + trie: tr, + stateObjects: make(map[common.Address]*stateObject), + stateObjectsDirty: make(map[common.Address]struct{}), + refund: new(big.Int), + logs: make(map[common.Hash][]*types.Log), + preimages: make(map[common.Hash][]byte), }, nil } @@ -115,7 +113,6 @@ func (self *StateDB) Reset(root common.Hash) error { self.trie = tr self.stateObjects = make(map[common.Address]*stateObject) self.stateObjectsDirty = make(map[common.Address]struct{}) - self.stateObjectsDestructed = make(map[common.Address]struct{}) self.thash = common.Hash{} self.bhash = common.Hash{} self.txIndex = 0 @@ -323,7 +320,6 @@ func (self *StateDB) Suicide(addr common.Address) bool { }) stateObject.markSuicided() stateObject.data.Balance = new(big.Int) - self.stateObjectsDestructed[addr] = struct{}{} return true } @@ -456,23 +452,19 @@ func (self *StateDB) Copy() *StateDB { // Copy all the basic fields, initialize the memory ones state := &StateDB{ - db: self.db, - trie: self.trie, - stateObjects: make(map[common.Address]*stateObject, len(self.stateObjectsDirty)), - stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)), - stateObjectsDestructed: make(map[common.Address]struct{}, len(self.stateObjectsDestructed)), - refund: new(big.Int).Set(self.refund), - logs: make(map[common.Hash][]*types.Log, len(self.logs)), - logSize: self.logSize, - preimages: make(map[common.Hash][]byte), + db: self.db, + trie: self.trie, + stateObjects: make(map[common.Address]*stateObject, len(self.stateObjectsDirty)), + stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)), + refund: new(big.Int).Set(self.refund), + logs: make(map[common.Hash][]*types.Log, len(self.logs)), + logSize: self.logSize, + preimages: make(map[common.Hash][]byte), } // Copy the dirty states, logs, and preimages for addr := range self.stateObjectsDirty { state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state, state.MarkStateObjectDirty) state.stateObjectsDirty[addr] = struct{}{} - if self.stateObjects[addr].suicided { - state.stateObjectsDestructed[addr] = struct{}{} - } } for hash, logs := range self.logs { state.logs[hash] = make([]*types.Log, len(logs)) @@ -520,10 +512,9 @@ func (self *StateDB) GetRefund() *big.Int { return self.refund } -// IntermediateRoot computes the current root hash of the state trie. -// It is called in between transactions to get the root hash that -// goes into transaction receipts. -func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { +// Finalise finalises the state by removing the self destructed objects +// and clears the journal as well as the refunds. +func (s *StateDB) Finalise(deleteEmptyObjects bool) { for addr := range s.stateObjectsDirty { stateObject := s.stateObjects[addr] if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) { @@ -535,6 +526,13 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { } // Invalidate journal because reverting across transactions is not allowed. s.clearJournalAndRefund() +} + +// IntermediateRoot computes the current root hash of the state trie. +// It is called in between transactions to get the root hash that +// goes into transaction receipts. +func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { + s.Finalise(deleteEmptyObjects) return s.trie.Hash() } @@ -546,19 +544,6 @@ func (self *StateDB) Prepare(thash, bhash common.Hash, ti int) { self.txIndex = ti } -// Finalise finalises the state by removing the self destructed objects -// in the current stateObjectsDestructed buffer and clears the journal -// as well as the refunds. -// -// Please note that Finalise is used by EIP#98 and is used instead of -// IntermediateRoot. -func (s *StateDB) Finalise() { - for addr := range s.stateObjectsDestructed { - s.deleteStateObject(s.stateObjects[addr]) - } - s.clearJournalAndRefund() -} - // DeleteSuicides flags the suicided objects for deletion so that it // won't be referenced again when called / queried up on. // diff --git a/core/state_processor.go b/core/state_processor.go index 4489cfce25..4115eab8cb 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -98,7 +98,7 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common // about the transaction and calling mechanisms. vmenv := vm.NewEVM(context, statedb, config, cfg) // Apply the transaction to the current state (included in the env) - _, gas, err := ApplyMessage(vmenv, msg, gp) + _, gas, failed, err := ApplyMessage(vmenv, msg, gp) if err != nil { return nil, nil, err } @@ -106,7 +106,7 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common // Update the state with pending changes var root []byte if config.IsMetropolis(header.Number) { - statedb.Finalise() + statedb.Finalise(true) } else { root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() } @@ -114,7 +114,7 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx // based on the eip phase, we're passing wether the root touch-delete accounts. - receipt := types.NewReceipt(root, usedGas) + receipt := types.NewReceipt(root, failed, usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = new(big.Int).Set(gas) // if the transaction created a contract, store the creation address in the receipt. diff --git a/core/state_transition.go b/core/state_transition.go index 0ae9d7fcbf..bab4540be8 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -59,8 +59,7 @@ type StateTransition struct { value *big.Int data []byte state vm.StateDB - - evm *vm.EVM + evm *vm.EVM } // Message represents a message sent to a contract. @@ -127,11 +126,11 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition // 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(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, error) { +func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, bool, error) { st := NewStateTransition(evm, msg, gp) - ret, _, gasUsed, err := st.TransitionDb() - return ret, gasUsed, err + ret, _, gasUsed, failed, err := st.TransitionDb() + return ret, gasUsed, failed, err } func (st *StateTransition) from() vm.AccountRef { @@ -208,7 +207,7 @@ func (st *StateTransition) preCheck() error { // TransitionDb will transition the state by applying the current message and returning the result // including the required gas for the operation as well as the used gas. It returns an error if it // failed. An error indicates a consensus issue. -func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, err error) { +func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, failed bool, err error) { if err = st.preCheck(); err != nil { return } @@ -222,10 +221,10 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big // TODO convert to uint64 intrinsicGas := IntrinsicGas(st.data, contractCreation, homestead) if intrinsicGas.BitLen() > 64 { - return nil, nil, nil, vm.ErrOutOfGas + return nil, nil, nil, false, vm.ErrOutOfGas } if err = st.useGas(intrinsicGas.Uint64()); err != nil { - return nil, nil, nil, err + return nil, nil, nil, false, err } var ( @@ -248,7 +247,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big // sufficient balance to make the transfer happen. The first // balance transfer may never fail. if vmerr == vm.ErrInsufficientBalance { - return nil, nil, nil, vmerr + return nil, nil, nil, false, vmerr } } requiredGas = new(big.Int).Set(st.gasUsed()) @@ -256,7 +255,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big st.refundGas() st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(st.gasUsed(), st.gasPrice)) - return ret, requiredGas, st.gasUsed(), err + return ret, requiredGas, st.gasUsed(), vmerr != nil, err } func (st *StateTransition) refundGas() { diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go index eb2e5d42b4..1e6880c223 100644 --- a/core/types/gen_receipt_json.go +++ b/core/types/gen_receipt_json.go @@ -14,6 +14,7 @@ import ( func (r Receipt) MarshalJSON() ([]byte, error) { type Receipt struct { PostState hexutil.Bytes `json:"root"` + Failed bool `json:"failed"` CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -23,6 +24,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) { } var enc Receipt enc.PostState = r.PostState + enc.Failed = r.Failed enc.CumulativeGasUsed = (*hexutil.Big)(r.CumulativeGasUsed) enc.Bloom = r.Bloom enc.Logs = r.Logs @@ -35,6 +37,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) { func (r *Receipt) UnmarshalJSON(input []byte) error { type Receipt struct { PostState hexutil.Bytes `json:"root"` + Failed *bool `json:"failed"` CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"` Bloom *Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -49,6 +52,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { if dec.PostState != nil { r.PostState = dec.PostState } + if dec.Failed != nil { + r.Failed = *dec.Failed + } if dec.CumulativeGasUsed == nil { return errors.New("missing required field 'cumulativeGasUsed' for Receipt") } diff --git a/core/types/receipt.go b/core/types/receipt.go index c9906b0154..4f3b7357ed 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -17,6 +17,7 @@ package types import ( + "bytes" "fmt" "io" "math/big" @@ -28,10 +29,16 @@ import ( //go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go +var ( + receiptStatusFailed = []byte{} + receiptStatusSuccessful = []byte{0x01} +) + // Receipt represents the results of a transaction. type Receipt struct { // Consensus fields PostState []byte `json:"root"` + Failed bool `json:"failed"` CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -48,87 +55,78 @@ type receiptMarshaling struct { GasUsed *hexutil.Big } -// homesteadReceiptRLP contains the receipt's Homestead consensus fields, used -// during RLP serialization. -type homesteadReceiptRLP struct { - PostState []byte +// receiptRLP is the consensus encoding of a receipt. +type receiptRLP struct { + PostStateOrStatus []byte CumulativeGasUsed *big.Int Bloom Bloom Logs []*Log } -// metropolisReceiptRLP contains the receipt's Metropolis consensus fields, used -// during RLP serialization. -type metropolisReceiptRLP struct { +type receiptStorageRLP struct { + PostStateOrStatus []byte CumulativeGasUsed *big.Int Bloom Bloom - Logs []*Log + TxHash common.Hash + ContractAddress common.Address + Logs []*LogForStorage + GasUsed *big.Int } // 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)} +func NewReceipt(root []byte, failed bool, cumulativeGasUsed *big.Int) *Receipt { + return &Receipt{PostState: common.CopyBytes(root), Failed: failed, CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)} } // EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt // into an RLP stream. If no post state is present, metropolis fork is assumed. func (r *Receipt) EncodeRLP(w io.Writer) error { - if r.PostState == nil { - return rlp.Encode(w, &metropolisReceiptRLP{r.CumulativeGasUsed, r.Bloom, r.Logs}) - } - return rlp.Encode(w, &homesteadReceiptRLP{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs}) + return rlp.Encode(w, &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs}) } // DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt // from an RLP stream. func (r *Receipt) DecodeRLP(s *rlp.Stream) error { - // Load the raw bytes since we have multiple possible formats - raw, err := s.Raw() - if err != nil { + var dec receiptRLP + if err := s.Decode(&dec); err != nil { return err } - list, _, err := rlp.SplitList(raw) - if err != nil { + if err := r.setStatus(dec.PostStateOrStatus); err != nil { return err } - items, err := rlp.CountValues(list) - if err != nil { - return err - } - // Deserialize based on the number of content items - switch items { - case 3: - // Metropolis receipts have 3 components - var metro metropolisReceiptRLP - if err := rlp.DecodeBytes(raw, &metro); err != nil { - return err - } - r.CumulativeGasUsed = metro.CumulativeGasUsed - r.Bloom = metro.Bloom - r.Logs = metro.Logs - return nil - - case 4: - // Homestead receipts have 4 components - var home homesteadReceiptRLP - if err := rlp.DecodeBytes(raw, &home); err != nil { - return err - } - r.PostState = home.PostState[:] - r.CumulativeGasUsed = home.CumulativeGasUsed - r.Bloom = home.Bloom - r.Logs = home.Logs - return nil + r.CumulativeGasUsed, r.Bloom, r.Logs = dec.CumulativeGasUsed, dec.Bloom, dec.Logs + return nil +} +func (r *Receipt) setStatus(postStateOrStatus []byte) error { + switch { + case bytes.Equal(postStateOrStatus, receiptStatusSuccessful): + r.Failed = false + case bytes.Equal(postStateOrStatus, receiptStatusFailed): + r.Failed = true + case len(postStateOrStatus) == len(common.Hash{}): + r.PostState = postStateOrStatus default: - return fmt.Errorf("invalid receipt components: %v", items) + return fmt.Errorf("invalid receipt status %x", postStateOrStatus) } + return nil +} + +func (r *Receipt) statusEncoding() []byte { + if len(r.PostState) == 0 { + if r.Failed { + return receiptStatusFailed + } else { + return receiptStatusSuccessful + } + } + return r.PostState } // String implements the Stringer interface. func (r *Receipt) String() string { if r.PostState == nil { - return fmt.Sprintf("receipt{cgas=%v bloom=%x logs=%v}", r.CumulativeGasUsed, r.Bloom, r.Logs) + return fmt.Sprintf("receipt{failed=%t cgas=%v bloom=%x logs=%v}", r.Failed, r.CumulativeGasUsed, r.Bloom, r.Logs) } return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs) } @@ -140,37 +138,39 @@ type ReceiptForStorage Receipt // EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt // into an RLP stream. func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error { - logs := make([]*LogForStorage, len(r.Logs)) - for i, log := range r.Logs { - logs[i] = (*LogForStorage)(log) + enc := &receiptStorageRLP{ + PostStateOrStatus: (*Receipt)(r).statusEncoding(), + CumulativeGasUsed: r.CumulativeGasUsed, + Bloom: r.Bloom, + TxHash: r.TxHash, + ContractAddress: r.ContractAddress, + Logs: make([]*LogForStorage, len(r.Logs)), + GasUsed: r.GasUsed, } - return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed}) + for i, log := range r.Logs { + enc.Logs[i] = (*LogForStorage)(log) + } + return rlp.Encode(w, enc) } // 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 receipt struct { - PostState []byte - CumulativeGasUsed *big.Int - Bloom Bloom - TxHash common.Hash - ContractAddress common.Address - Logs []*LogForStorage - GasUsed *big.Int + var dec receiptStorageRLP + if err := s.Decode(&dec); err != nil { + return err } - if err := s.Decode(&receipt); err != nil { + if err := (*Receipt)(r).setStatus(dec.PostStateOrStatus); err != nil { return err } // Assign the consensus fields - r.PostState, r.CumulativeGasUsed, r.Bloom = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom - r.Logs = make([]*Log, len(receipt.Logs)) - for i, log := range receipt.Logs { + r.CumulativeGasUsed, r.Bloom = dec.CumulativeGasUsed, dec.Bloom + r.Logs = make([]*Log, len(dec.Logs)) + for i, log := range dec.Logs { r.Logs[i] = (*Log)(log) } // Assign the implementation fields - r.TxHash, r.ContractAddress, r.GasUsed = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed - + r.TxHash, r.ContractAddress, r.GasUsed = dec.TxHash, dec.ContractAddress, dec.GasUsed return nil } diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index 022070ab80..880d7324ae 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -13,6 +13,7 @@ type precompiledTest struct { input, expected string gas uint64 name string + noBenchmark bool // Benchmark primarily the worst-cases } // modexpTests are the test and benchmark data for the modexp precompiled contract. @@ -182,6 +183,78 @@ var bn256ScalarMulTests = []precompiledTest{ input: "025a6f4181d2b4ea8b724290ffb40156eb0adb514c688556eb79cdea0752c2bb2eff3f31dea215f1eb86023a133a996eb6300b44da664d64251d05381bb8a02e183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3", expected: "14789d0d4a730b354403b5fac948113739e276c23e0258d8596ee72f9cd9d3230af18a63153e0ec25ff9f2951dd3fa90ed0197bfef6e2a1a62b5095b9d2b4a27", name: "chfast3", + }, { + input: "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + expected: "2cde5879ba6f13c0b5aa4ef627f159a3347df9722efce88a9afbb20b763b4c411aa7e43076f6aee272755a7f9b84832e71559ba0d2e0b17d5f9f01755e5b0d11", + name: "cdetrio1", + }, { + input: "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f630644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000", + expected: "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe3163511ddc1c3f25d396745388200081287b3fd1472d8339d5fecb2eae0830451", + name: "cdetrio2", + noBenchmark: true, + }, { + input: "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000100000000000000000000000000000000", + expected: "1051acb0700ec6d42a88215852d582efbaef31529b6fcbc3277b5c1b300f5cf0135b2394bb45ab04b8bd7611bd2dfe1de6a4e6e2ccea1ea1955f577cd66af85b", + name: "cdetrio3", + noBenchmark: true, + }, { + input: "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000009", + expected: "1dbad7d39dbc56379f78fac1bca147dc8e66de1b9d183c7b167351bfe0aeab742cd757d51289cd8dbd0acf9e673ad67d0f0a89f912af47ed1be53664f5692575", + name: "cdetrio4", + noBenchmark: true, + }, { + input: "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000001", + expected: "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6", + name: "cdetrio5", + noBenchmark: true, + }, { + input: "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + expected: "29e587aadd7c06722aabba753017c093f70ba7eb1f1c0104ec0564e7e3e21f6022b1143f6a41008e7755c71c3d00b6b915d386de21783ef590486d8afa8453b1", + name: "cdetrio6", + }, { + input: "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000", + expected: "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa92e83f8d734803fc370eba25ed1f6b8768bd6d83887b87165fc2434fe11a830cb", + name: "cdetrio7", + noBenchmark: true, + }, { + input: "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000100000000000000000000000000000000", + expected: "221a3577763877920d0d14a91cd59b9479f83b87a653bb41f82a3f6f120cea7c2752c7f64cdd7f0e494bff7b60419f242210f2026ed2ec70f89f78a4c56a1f15", + name: "cdetrio8", + noBenchmark: true, + }, { + input: "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000000000000000000000000000000000009", + expected: "228e687a379ba154554040f8821f4e41ee2be287c201aa9c3bc02c9dd12f1e691e0fd6ee672d04cfd924ed8fdc7ba5f2d06c53c1edc30f65f2af5a5b97f0a76a", + name: "cdetrio9", + noBenchmark: true, + }, { + input: "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000000000000000000000000000000000001", + expected: "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c", + name: "cdetrio10", + noBenchmark: true, + }, { + input: "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + expected: "00a1a234d08efaa2616607e31eca1980128b00b415c845ff25bba3afcb81dc00242077290ed33906aeb8e42fd98c41bcb9057ba03421af3f2d08cfc441186024", + name: "cdetrio11", + }, { + input: "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d9830644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000", + expected: "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b8692929ee761a352600f54921df9bf472e66217e7bb0cee9032e00acc86b3c8bfaf", + name: "cdetrio12", + noBenchmark: true, + }, { + input: "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000100000000000000000000000000000000", + expected: "1071b63011e8c222c5a771dfa03c2e11aac9666dd097f2c620852c3951a4376a2f46fe2f73e1cf310a168d56baa5575a8319389d7bfa6b29ee2d908305791434", + name: "cdetrio13", + noBenchmark: true, + }, { + input: "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000000000000000000000000000000000009", + expected: "19f75b9dd68c080a688774a6213f131e3052bd353a304a189d7a2ee367e3c2582612f545fb9fc89fde80fd81c68fc7dcb27fea5fc124eeda69433cf5c46d2d7f", + name: "cdetrio14", + noBenchmark: true, + }, { + input: "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000000000000000000000000000000000001", + expected: "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98", + name: "cdetrio15", + noBenchmark: true, }, } @@ -262,6 +335,9 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) { } func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) { + if test.noBenchmark { + return + } p := PrecompiledContractsMetropolis[common.HexToAddress(addr)] in := common.Hex2Bytes(test.input) reqGas := p.RequiredGas(in) diff --git a/core/vm/errors.go b/core/vm/errors.go index 69c7d6a98c..b19366be0e 100644 --- a/core/vm/errors.go +++ b/core/vm/errors.go @@ -19,9 +19,10 @@ package vm import "errors" var ( - ErrOutOfGas = errors.New("out of gas") - ErrCodeStoreOutOfGas = errors.New("contract creation code storage out of gas") - ErrDepth = errors.New("max call depth exceeded") - ErrTraceLimitReached = errors.New("the number of logs reached the specified limit") - ErrInsufficientBalance = errors.New("insufficient balance for transfer") + ErrOutOfGas = errors.New("out of gas") + ErrCodeStoreOutOfGas = errors.New("contract creation code storage out of gas") + ErrDepth = errors.New("max call depth exceeded") + ErrTraceLimitReached = errors.New("the number of logs reached the specified limit") + ErrInsufficientBalance = errors.New("insufficient balance for transfer") + ErrContractAddressCollision = errors.New("contract address collision") ) diff --git a/core/vm/evm.go b/core/vm/evm.go index 8d654c666e..caf8b4507d 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -25,6 +25,10 @@ import ( "github.com/ethereum/go-ethereum/params" ) +// emptyCodeHash is used by create to ensure deployment is disallowed to already +// deployed contract addresses (relevant after the account abstraction). +var emptyCodeHash = crypto.Keccak256Hash(nil) + type ( CanTransferFunc func(StateDB, common.Address, *big.Int) bool TransferFunc func(StateDB, common.Address, common.Address, *big.Int) @@ -158,7 +162,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) // initialise a new contract and set the code that is to be used by the - // E The contract is a scoped evmironment for this execution context + // E The contract is a scoped environment for this execution context // only. contract := NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) @@ -307,13 +311,17 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { return nil, common.Address{}, gas, ErrInsufficientBalance } - - // Create a new account on the state + // Ensure there's no existing contract already at the designated address nonce := evm.StateDB.GetNonce(caller.Address()) evm.StateDB.SetNonce(caller.Address(), nonce+1) - snapshot := evm.StateDB.Snapshot() contractAddr = crypto.CreateAddress(caller.Address(), nonce) + contractHash := evm.StateDB.GetCodeHash(contractAddr) + if evm.StateDB.GetNonce(contractAddr) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) { + return nil, common.Address{}, 0, ErrContractAddressCollision + } + // Create a new account on the state + snapshot := evm.StateDB.Snapshot() evm.StateDB.CreateAccount(contractAddr) if evm.ChainConfig().IsEIP158(evm.BlockNumber) { evm.StateDB.SetNonce(contractAddr, 1) @@ -351,6 +359,10 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I contract.UseGas(contract.Gas) } } + // Assign err if contract code size exceeds the max while the err is still empty. + if maxCodeSizeExceeded && err == nil { + err = errMaxCodeSizeExceeded + } return ret, contractAddr, contract.Gas, err } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index ece4d2229a..b6d6e22c4c 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -33,6 +33,7 @@ var ( errWriteProtection = errors.New("evm: write protection") errReturnDataOutOfBounds = errors.New("evm: return data out of bounds") errExecutionReverted = errors.New("evm: execution reverted") + errMaxCodeSizeExceeded = errors.New("evm: max code size exceeded") ) func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { @@ -619,7 +620,6 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta if value.Sign() != 0 { gas += params.CallStipend } - ret, returnGas, err := evm.Call(contract, address, args, gas, value) if err != nil { stack.push(new(big.Int)) diff --git a/core/vm/logger.go b/core/vm/logger.go index b73b13bd97..623c0d5632 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -86,7 +86,7 @@ func (s *StructLog) OpName() string { // if you need to retain them beyond the current call. type Tracer interface { CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error - CaptureEnd(output []byte, gasUsed uint64, t time.Duration) error + CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error } // StructLogger is an EVM state logger and implements Tracer. @@ -128,18 +128,14 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui } // capture SSTORE opcodes and determine the changed value and store - // it in the local storage container. NOTE: we do not need to do any - // range checks here because that's already handler prior to calling - // this function. - switch op { - case SSTORE: + // it in the local storage container. + if op == SSTORE && stack.len() >= 2 { var ( value = common.BigToHash(stack.data[stack.len()-2]) address = common.BigToHash(stack.data[stack.len()-1]) ) l.changedValues[contract.Address()][address] = value } - // copy a snapstot of the current memory state to a new buffer var mem []byte if !l.cfg.DisableMemory { @@ -183,8 +179,11 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui return nil } -func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration) error { +func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error { fmt.Printf("0x%x", output) + if err != nil { + fmt.Printf(" error: %v\n", err) + } return nil } diff --git a/eth/api.go b/eth/api.go index f5214fc379..9904c6f536 100644 --- a/eth/api.go +++ b/eth/api.go @@ -523,7 +523,8 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common. // Run the transaction with tracing enabled. vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{Debug: true, Tracer: tracer}) - ret, gas, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())) + // TODO utilize failed flag + ret, gas, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { return nil, fmt.Errorf("tracing failed: %v", err) } @@ -570,7 +571,7 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int) (co vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{}) gp := new(core.GasPool).AddGas(tx.Gas()) - _, _, err := core.ApplyMessage(vmenv, msg, gp) + _, _, _, err := core.ApplyMessage(vmenv, msg, gp) if err != nil { return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err) } diff --git a/eth/backend_test.go b/eth/backend_test.go index 4351b24cfb..1fd25e95aa 100644 --- a/eth/backend_test.go +++ b/eth/backend_test.go @@ -35,11 +35,11 @@ func TestMipmapUpgrade(t *testing.T) { chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) { switch i { case 1: - receipt := types.NewReceipt(nil, new(big.Int)) + receipt := types.NewReceipt(nil, false, new(big.Int)) receipt.Logs = []*types.Log{{Address: addr}} gen.AddUncheckedReceipt(receipt) case 2: - receipt := types.NewReceipt(nil, new(big.Int)) + receipt := types.NewReceipt(nil, false, new(big.Int)) receipt.Logs = []*types.Log{{Address: addr}} gen.AddUncheckedReceipt(receipt) } diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 3244c04d74..cf508a218d 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -33,7 +33,7 @@ import ( ) func makeReceipt(addr common.Address) *types.Receipt { - receipt := types.NewReceipt(nil, new(big.Int)) + receipt := types.NewReceipt(nil, false, new(big.Int)) receipt.Logs = []*types.Log{ {Address: addr}, } @@ -145,7 +145,7 @@ func TestFilters(t *testing.T) { var receipts types.Receipts switch i { case 1: - receipt := types.NewReceipt(nil, new(big.Int)) + receipt := types.NewReceipt(nil, false, new(big.Int)) receipt.Logs = []*types.Log{ { Address: addr, @@ -155,7 +155,7 @@ func TestFilters(t *testing.T) { gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} case 2: - receipt := types.NewReceipt(nil, new(big.Int)) + receipt := types.NewReceipt(nil, false, new(big.Int)) receipt.Logs = []*types.Log{ { Address: addr, @@ -165,7 +165,7 @@ func TestFilters(t *testing.T) { gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} case 998: - receipt := types.NewReceipt(nil, new(big.Int)) + receipt := types.NewReceipt(nil, false, new(big.Int)) receipt.Logs = []*types.Log{ { Address: addr, @@ -175,7 +175,7 @@ func TestFilters(t *testing.T) { gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} case 999: - receipt := types.NewReceipt(nil, new(big.Int)) + receipt := types.NewReceipt(nil, false, new(big.Int)) receipt.Logs = []*types.Log{ { Address: addr, diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index c3924b93a7..30710aaabd 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -635,7 +635,8 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr // Setup the gas pool (also for unmetered requests) // and apply the message. gp := new(core.GasPool).AddGas(math.MaxBig256) - res, gas, err := core.ApplyMessage(evm, msg, gp) + // TODO utilize failed flag to help gas estimation + res, gas, _, err := core.ApplyMessage(evm, msg, gp) if err := vmError(); err != nil { return nil, common.Big0, err } diff --git a/internal/ethapi/tracer.go b/internal/ethapi/tracer.go index fc66839ea5..0516265270 100644 --- a/internal/ethapi/tracer.go +++ b/internal/ethapi/tracer.go @@ -346,7 +346,7 @@ func (jst *JavascriptTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, } // CaptureEnd is called after the call finishes -func (jst *JavascriptTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration) error { +func (jst *JavascriptTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error { //TODO! @Arachnid please figure out of there's anything we can use this method for return nil } diff --git a/les/odr_test.go b/les/odr_test.go index 3a0fd6738f..f56c4036d4 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -127,7 +127,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai //vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{}) gp := new(core.GasPool).AddGas(math.MaxBig256) - ret, _, _ := core.ApplyMessage(vmenv, msg, gp) + ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) res = append(res, ret...) } } else { @@ -138,7 +138,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai context := core.NewEVMContext(msg, header, lc, nil) vmenv := vm.NewEVM(context, state, config, vm.Config{}) gp := new(core.GasPool).AddGas(math.MaxBig256) - ret, _, _ := core.ApplyMessage(vmenv, msg, gp) + ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) if state.Error() == nil { res = append(res, ret...) } diff --git a/light/odr_test.go b/light/odr_test.go index bd1e976e81..c0c5438fdb 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -180,7 +180,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain context := core.NewEVMContext(msg, header, chain, nil) vmenv := vm.NewEVM(context, st, config, vm.Config{}) gp := new(core.GasPool).AddGas(math.MaxBig256) - ret, _, _ := core.ApplyMessage(vmenv, msg, gp) + ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) res = append(res, ret...) if st.Error() != nil { return res, st.Error() diff --git a/metrics/metrics.go b/metrics/metrics.go index 9906bb8ad2..da2cdbc53c 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -29,7 +29,7 @@ import ( ) // MetricsEnabledFlag is the CLI flag name to use to enable metrics collections. -var MetricsEnabledFlag = "metrics" +const MetricsEnabledFlag = "metrics" // Enabled is the flag specifying if metrics are enable or not. var Enabled = false diff --git a/node/errors.go b/node/errors.go index bd5ddeb5de..2e0dadc4d6 100644 --- a/node/errors.go +++ b/node/errors.go @@ -17,10 +17,28 @@ package node import ( + "errors" "fmt" "reflect" + "syscall" ) +var ( + ErrDatadirUsed = errors.New("datadir already used by another process") + ErrNodeStopped = errors.New("node not started") + ErrNodeRunning = errors.New("node already running") + ErrServiceUnknown = errors.New("unknown service") + + datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true} +) + +func convertFileLockError(err error) error { + if errno, ok := err.(syscall.Errno); ok && datadirInUseErrnos[uint(errno)] { + return ErrDatadirUsed + } + return err +} + // DuplicateServiceError is returned during Node startup if a registered service // constructor returns a service of the same type that was already started. type DuplicateServiceError struct { diff --git a/node/node.go b/node/node.go index e3f0232b4b..86cfb29baf 100644 --- a/node/node.go +++ b/node/node.go @@ -25,7 +25,6 @@ import ( "reflect" "strings" "sync" - "syscall" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/ethdb" @@ -34,16 +33,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rpc" - "github.com/syndtr/goleveldb/leveldb/storage" -) - -var ( - ErrDatadirUsed = errors.New("datadir already used") - ErrNodeStopped = errors.New("node not started") - ErrNodeRunning = errors.New("node already running") - ErrServiceUnknown = errors.New("unknown service") - - datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true} + "github.com/prometheus/prometheus/util/flock" ) // Node is a container on which services can be registered. @@ -52,8 +42,8 @@ type Node struct { config *Config accman *accounts.Manager - ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop - instanceDirLock storage.Storage // prevents concurrent use of instance directory + ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop + instanceDirLock flock.Releaser // prevents concurrent use of instance directory serverConfig p2p.Config server *p2p.Server // Currently running P2P networking layer @@ -197,10 +187,7 @@ func (n *Node) Start() error { running.Protocols = append(running.Protocols, service.Protocols()...) } if err := running.Start(); err != nil { - if errno, ok := err.(syscall.Errno); ok && datadirInUseErrnos[uint(errno)] { - return ErrDatadirUsed - } - return err + return convertFileLockError(err) } // Start each of the services started := []reflect.Type{} @@ -242,14 +229,13 @@ func (n *Node) openDataDir() error { if err := os.MkdirAll(instdir, 0700); err != nil { return err } - // Try to open the instance directory as LevelDB storage. This creates a lock file - // which prevents concurrent use by another instance as well as accidental use of the - // instance directory as a database. - storage, err := storage.OpenFile(instdir, true) + // Lock the instance directory to prevent concurrent use by another instance as well as + // accidental use of the instance directory as a database. + release, _, err := flock.New(filepath.Join(instdir, "LOCK")) if err != nil { - return err + return convertFileLockError(err) } - n.instanceDirLock = storage + n.instanceDirLock = release return nil } @@ -509,7 +495,9 @@ func (n *Node) Stop() error { // Release instance directory lock. if n.instanceDirLock != nil { - n.instanceDirLock.Close() + if err := n.instanceDirLock.Release(); err != nil { + log.Error("Can't release datadir lock", "err", err) + } n.instanceDirLock = nil } diff --git a/rlp/decode.go b/rlp/decode.go index 78ccf6275e..60d9dab2b5 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -693,7 +693,7 @@ func (s *Stream) Raw() ([]byte, error) { return nil, err } if kind == String { - puthead(buf, 0x80, 0xB8, size) + puthead(buf, 0x80, 0xB7, size) } else { puthead(buf, 0xC0, 0xF7, size) } diff --git a/rlp/decode_test.go b/rlp/decode_test.go index d762e195d0..4d8abd0012 100644 --- a/rlp/decode_test.go +++ b/rlp/decode_test.go @@ -256,16 +256,31 @@ func TestStreamList(t *testing.T) { } func TestStreamRaw(t *testing.T) { - s := NewStream(bytes.NewReader(unhex("C58401010101")), 0) - s.List() - - want := unhex("8401010101") - raw, err := s.Raw() - if err != nil { - t.Fatal(err) + tests := []struct { + input string + output string + }{ + { + "C58401010101", + "8401010101", + }, + { + "F842B84001010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101", + "B84001010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101", + }, } - if !bytes.Equal(want, raw) { - t.Errorf("raw mismatch: got %x, want %x", raw, want) + for i, tt := range tests { + s := NewStream(bytes.NewReader(unhex(tt.input)), 0) + s.List() + + want := unhex(tt.output) + raw, err := s.Raw() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(want, raw) { + t.Errorf("test %d: raw mismatch: got %x, want %x", i, raw, want) + } } } diff --git a/tests/block_test.go b/tests/block_test.go index 6fc66b17cc..56e1e1e8da 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -33,10 +33,10 @@ func TestBlockchain(t *testing.T) { // Constantinople is not implemented yet. bt.skipLoad(`(?i)(constantinople)`) // Expected failures: - bt.fails("^TransitionTests/bcEIP158ToByzantium", "byzantium not supported") bt.fails(`^TransitionTests/bcHomesteadToDao/DaoTransactions(|_UncleExtradata|_EmptyTransactionAndForkBlocksAhead)\.json`, "issue in test") - bt.fails(`^bc(Exploit|Fork|Gas|Multi|Total|State|Random|Uncle|Valid|Wallet).*_Byzantium$`, "byzantium not supported") - bt.fails(`^bcBlockGasLimitTest/(BlockGasLimit2p63m1|TransactionGasHigherThanLimit2p63m1|SuicideTransaction|GasUsedHigherThanBlockGasLimitButNotWithRefundsSuicideFirst|TransactionGasHigherThanLimit2p63m1_2).*_Byzantium$`, "byzantium not supported") + + // Still failing tests + bt.skipLoad(`^bcWalletTest.*_Byzantium$`) bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { if err := bt.checkFailure(t, name, test.Run()); err != nil { diff --git a/tests/gen_stlog.go b/tests/gen_stlog.go deleted file mode 100644 index 4f7ebc9660..0000000000 --- a/tests/gen_stlog.go +++ /dev/null @@ -1,61 +0,0 @@ -// Code generated by github.com/fjl/gencodec. DO NOT EDIT. - -package tests - -import ( - "encoding/json" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" -) - -var _ = (*stLogMarshaling)(nil) - -func (s stLog) MarshalJSON() ([]byte, error) { - type stLog struct { - Address common.UnprefixedAddress `json:"address"` - Data hexutil.Bytes `json:"data"` - Topics []common.UnprefixedHash `json:"topics"` - Bloom string `json:"bloom"` - } - var enc stLog - enc.Address = common.UnprefixedAddress(s.Address) - enc.Data = s.Data - if s.Topics != nil { - enc.Topics = make([]common.UnprefixedHash, len(s.Topics)) - for k, v := range s.Topics { - enc.Topics[k] = common.UnprefixedHash(v) - } - } - enc.Bloom = s.Bloom - return json.Marshal(&enc) -} - -func (s *stLog) UnmarshalJSON(input []byte) error { - type stLog struct { - Address *common.UnprefixedAddress `json:"address"` - Data hexutil.Bytes `json:"data"` - Topics []common.UnprefixedHash `json:"topics"` - Bloom *string `json:"bloom"` - } - var dec stLog - if err := json.Unmarshal(input, &dec); err != nil { - return err - } - if dec.Address != nil { - s.Address = common.Address(*dec.Address) - } - if dec.Data != nil { - s.Data = dec.Data - } - if dec.Topics != nil { - s.Topics = make([]common.Hash, len(dec.Topics)) - for k, v := range dec.Topics { - s.Topics[k] = common.Hash(v) - } - } - if dec.Bloom != nil { - s.Bloom = *dec.Bloom - } - return nil -} diff --git a/tests/state_test.go b/tests/state_test.go index 00067c61ac..3d7b29012e 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -37,10 +37,8 @@ func TestState(t *testing.T) { // Expected failures: st.fails(`^stCodeSizeLimit/codesizeOOGInvalidSize\.json/(Frontier|Homestead|EIP150)`, "code size limit implementation is not conditional on fork") - st.fails(`^stRevertTest/RevertDepthCreateAddressCollision\.json/EIP15[08]/[67]`, "bug in test") st.fails(`^stRevertTest/RevertPrecompiledTouch\.json/EIP158`, "bug in test") st.fails(`^stRevertTest/RevertPrefoundEmptyOOG\.json/EIP158`, "bug in test") - st.fails(`^stRevertTest/RevertDepthCreateAddressCollision\.json/Byzantium/[67]`, "bug in test") st.fails(`^stRevertTest/RevertPrecompiledTouch\.json/Byzantium`, "bug in test") st.fails(`^stRevertTest/RevertPrefoundEmptyOOG\.json/Byzantium`, "bug in test") diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 2bf940bab7..ecaa6c6684 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -17,12 +17,10 @@ package tests import ( - "bytes" "encoding/hex" "encoding/json" "fmt" "math/big" - "reflect" "strings" "github.com/ethereum/go-ethereum/common" @@ -33,8 +31,10 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" ) // StateTest checks transaction processing without block context. @@ -63,7 +63,7 @@ type stJSON struct { type stPostState struct { Root common.UnprefixedHash `json:"hash"` - Logs *[]stLog `json:"logs"` + Logs common.UnprefixedHash `json:"logs"` Indexes struct { Data int `json:"data"` Gas int `json:"gas"` @@ -108,21 +108,6 @@ type stTransactionMarshaling struct { PrivateKey hexutil.Bytes } -//go:generate gencodec -type stLog -field-override stLogMarshaling -out gen_stlog.go - -type stLog struct { - Address common.Address `json:"address"` - Data []byte `json:"data"` - Topics []common.Hash `json:"topics"` - Bloom string `json:"bloom"` -} - -type stLogMarshaling struct { - Address common.UnprefixedAddress - Data hexutil.Bytes - Topics []common.UnprefixedHash -} - // Subtests returns all valid subtests of the test. func (t *StateTest) Subtests() []StateSubtest { var sub []StateSubtest @@ -156,13 +141,11 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) error { gaspool := new(core.GasPool) gaspool.AddGas(block.GasLimit()) snapshot := statedb.Snapshot() - if _, _, err := core.ApplyMessage(evm, msg, gaspool); err != nil { + if _, _, _, err := core.ApplyMessage(evm, msg, gaspool); err != nil { statedb.RevertToSnapshot(snapshot) } - if post.Logs != nil { - if err := checkLogs(statedb.Logs(), *post.Logs); err != nil { - return err - } + if logs := rlpHash(statedb.Logs()); logs != common.Hash(post.Logs) { + return fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs) } root, _ := statedb.CommitTo(db, config.IsEIP158(block.Number())) if root != common.Hash(post.Root) { @@ -254,28 +237,9 @@ func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) { return msg, nil } -func checkLogs(have []*types.Log, want []stLog) error { - if len(have) != len(want) { - return fmt.Errorf("logs length mismatch: got %d, want %d", len(have), len(want)) - } - for i := range have { - if have[i].Address != want[i].Address { - return fmt.Errorf("log address %d: got %x, want %x", i, have[i].Address, want[i].Address) - } - if !bytes.Equal(have[i].Data, want[i].Data) { - return fmt.Errorf("log data %d: got %x, want %x", i, have[i].Data, want[i].Data) - } - if !reflect.DeepEqual(have[i].Topics, want[i].Topics) { - return fmt.Errorf("log topics %d:\ngot %x\nwant %x", i, have[i].Topics, want[i].Topics) - } - genBloom := math.PaddedBigBytes(types.LogsBloom([]*types.Log{have[i]}), 256) - var wantBloom types.Bloom - if err := hexutil.UnmarshalFixedUnprefixedText("Bloom", []byte(want[i].Bloom), wantBloom[:]); err != nil { - return fmt.Errorf("test log %d has invalid bloom: %v", i, err) - } - if !bytes.Equal(genBloom, wantBloom[:]) { - return fmt.Errorf("bloom mismatch") - } - } - return nil +func rlpHash(x interface{}) (h common.Hash) { + hw := sha3.NewKeccak256() + rlp.Encode(hw, x) + hw.Sum(h[:0]) + return h } diff --git a/tests/testdata b/tests/testdata index 85f6d7cc01..1d30b47956 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit 85f6d7cc01b6bd04e071f5ba579fc675cfd2043b +Subproject commit 1d30b4795664f64b1b157971754e14a10cfd9115 diff --git a/tests/vm_test.go b/tests/vm_test.go index 5289ba3559..c9f5e225e9 100644 --- a/tests/vm_test.go +++ b/tests/vm_test.go @@ -26,6 +26,9 @@ func TestVM(t *testing.T) { t.Parallel() vmt := new(testMatcher) vmt.fails("^vmSystemOperationsTest.json/createNameRegistrator$", "fails without parallel execution") + + vmt.skipLoad(`^vmInputLimits(Light)?.json`) // log format broken + vmt.skipShortMode("^vmPerformanceTest.json") vmt.skipShortMode("^vmInputLimits(Light)?.json") diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index afdd896c35..0aa37955ce 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -44,14 +44,14 @@ func (t *VMTest) UnmarshalJSON(data []byte) error { } type vmJSON struct { - Env stEnv `json:"env"` - Exec vmExec `json:"exec"` - Logs []stLog `json:"logs"` - GasRemaining *math.HexOrDecimal64 `json:"gas"` - Out hexutil.Bytes `json:"out"` - Pre core.GenesisAlloc `json:"pre"` - Post core.GenesisAlloc `json:"post"` - PostStateRoot common.Hash `json:"postStateRoot"` + Env stEnv `json:"env"` + Exec vmExec `json:"exec"` + Logs common.UnprefixedHash `json:"logs"` + GasRemaining *math.HexOrDecimal64 `json:"gas"` + Out hexutil.Bytes `json:"out"` + Pre core.GenesisAlloc `json:"pre"` + Post core.GenesisAlloc `json:"post"` + PostStateRoot common.Hash `json:"postStateRoot"` } //go:generate gencodec -type vmExec -field-override vmExecMarshaling -out gen_vmexec.go @@ -109,7 +109,10 @@ func (t *VMTest) Run(vmconfig vm.Config) error { // if root := statedb.IntermediateRoot(false); root != t.json.PostStateRoot { // return fmt.Errorf("post state root mismatch, got %x, want %x", root, t.json.PostStateRoot) // } - return checkLogs(statedb.Logs(), t.json.Logs) + if logs := rlpHash(statedb.Logs()); logs != common.Hash(t.json.Logs) { + return fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, t.json.Logs) + } + return nil } func (t *VMTest) exec(statedb *state.StateDB, vmconfig vm.Config) ([]byte, uint64, error) { diff --git a/vendor/github.com/prometheus/prometheus/LICENSE b/vendor/github.com/prometheus/prometheus/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/github.com/prometheus/prometheus/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/prometheus/prometheus/NOTICE b/vendor/github.com/prometheus/prometheus/NOTICE new file mode 100644 index 0000000000..47de2415e1 --- /dev/null +++ b/vendor/github.com/prometheus/prometheus/NOTICE @@ -0,0 +1,87 @@ +The Prometheus systems and service monitoring server +Copyright 2012-2015 The Prometheus Authors + +This product includes software developed at +SoundCloud Ltd. (http://soundcloud.com/). + + +The following components are included in this product: + +Bootstrap +http://getbootstrap.com +Copyright 2011-2014 Twitter, Inc. +Licensed under the MIT License + +bootstrap3-typeahead.js +https://github.com/bassjobsen/Bootstrap-3-Typeahead +Original written by @mdo and @fat +Copyright 2014 Bass Jobsen @bassjobsen +Licensed under the Apache License, Version 2.0 + +fuzzy +https://github.com/mattyork/fuzzy +Original written by @mattyork +Copyright 2012 Matt York +Licensed under the MIT License + +bootstrap-datetimepicker.js +https://github.com/Eonasdan/bootstrap-datetimepicker +Copyright 2015 Jonathan Peterson (@Eonasdan) +Licensed under the MIT License + +moment.js +https://github.com/moment/moment/ +Copyright JS Foundation and other contributors +Licensed under the MIT License + +Rickshaw +https://github.com/shutterstock/rickshaw +Copyright 2011-2014 by Shutterstock Images, LLC +See https://github.com/shutterstock/rickshaw/blob/master/LICENSE for license details + +mustache.js +https://github.com/janl/mustache.js +Copyright 2009 Chris Wanstrath (Ruby) +Copyright 2010-2014 Jan Lehnardt (JavaScript) +Copyright 2010-2015 The mustache.js community +Licensed under the MIT License + +jQuery +https://jquery.org +Copyright jQuery Foundation and other contributors +Licensed under the MIT License + +Go support for Protocol Buffers - Google's data interchange format +http://github.com/golang/protobuf/ +Copyright 2010 The Go Authors +See source code for license details. + +Go support for leveled logs, analogous to +https://code.google.com/p/google-glog/ +Copyright 2013 Google Inc. +Licensed under the Apache License, Version 2.0 + +Support for streaming Protocol Buffer messages for the Go language (golang). +https://github.com/matttproud/golang_protobuf_extensions +Copyright 2013 Matt T. Proud +Licensed under the Apache License, Version 2.0 + +DNS library in Go +http://miek.nl/posts/2014/Aug/16/go-dns-package/ +Copyright 2009 The Go Authors, 2011 Miek Gieben +See https://github.com/miekg/dns/blob/master/LICENSE for license details. + +LevelDB key/value database in Go +https://github.com/syndtr/goleveldb +Copyright 2012 Suryandaru Triandana +See https://github.com/syndtr/goleveldb/blob/master/LICENSE for license details. + +gosnappy - a fork of code.google.com/p/snappy-go +https://github.com/syndtr/gosnappy +Copyright 2011 The Snappy-Go Authors +See https://github.com/syndtr/gosnappy/blob/master/LICENSE for license details. + +go-zookeeper - Native ZooKeeper client for Go +https://github.com/samuel/go-zookeeper +Copyright (c) 2013, Samuel Stauffer +See https://github.com/samuel/go-zookeeper/blob/master/LICENSE for license details. diff --git a/vendor/github.com/prometheus/prometheus/util/flock/flock.go b/vendor/github.com/prometheus/prometheus/util/flock/flock.go new file mode 100644 index 0000000000..5dc22a2fae --- /dev/null +++ b/vendor/github.com/prometheus/prometheus/util/flock/flock.go @@ -0,0 +1,46 @@ +// Copyright 2016 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package flock provides portable file locking. It is essentially ripped out +// from the code of github.com/syndtr/goleveldb. Strange enough that the +// standard library does not provide this functionality. Once this package has +// proven to work as expected, we should probably turn it into a separate +// general purpose package for humanity. +package flock + +import ( + "os" + "path/filepath" +) + +// Releaser provides the Release method to release a file lock. +type Releaser interface { + Release() error +} + +// New locks the file with the provided name. If the file does not exist, it is +// created. The returned Releaser is used to release the lock. existed is true +// if the file to lock already existed. A non-nil error is returned if the +// locking has failed. Neither this function nor the returned Releaser is +// goroutine-safe. +func New(fileName string) (r Releaser, existed bool, err error) { + if err = os.MkdirAll(filepath.Dir(fileName), 0755); err != nil { + return + } + + _, err = os.Stat(fileName) + existed = err == nil + + r, err = newLock(fileName) + return +} diff --git a/vendor/github.com/prometheus/prometheus/util/flock/flock_plan9.go b/vendor/github.com/prometheus/prometheus/util/flock/flock_plan9.go new file mode 100644 index 0000000000..004e85c0fe --- /dev/null +++ b/vendor/github.com/prometheus/prometheus/util/flock/flock_plan9.go @@ -0,0 +1,32 @@ +// Copyright 2016 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package flock + +import "os" + +type plan9Lock struct { + f *os.File +} + +func (l *plan9Lock) Release() error { + return l.f.Close() +} + +func newLock(fileName string) (Releaser, error) { + f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, os.ModeExclusive|0644) + if err != nil { + return nil, err + } + return &plan9Lock{f}, nil +} diff --git a/vendor/github.com/prometheus/prometheus/util/flock/flock_solaris.go b/vendor/github.com/prometheus/prometheus/util/flock/flock_solaris.go new file mode 100644 index 0000000000..299fc87446 --- /dev/null +++ b/vendor/github.com/prometheus/prometheus/util/flock/flock_solaris.go @@ -0,0 +1,59 @@ +// Copyright 2016 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build solaris + +package flock + +import ( + "os" + "syscall" +) + +type unixLock struct { + f *os.File +} + +func (l *unixLock) Release() error { + if err := l.set(false); err != nil { + return err + } + return l.f.Close() +} + +func (l *unixLock) set(lock bool) error { + flock := syscall.Flock_t{ + Type: syscall.F_UNLCK, + Start: 0, + Len: 0, + Whence: 1, + } + if lock { + flock.Type = syscall.F_WRLCK + } + return syscall.FcntlFlock(l.f.Fd(), syscall.F_SETLK, &flock) +} + +func newLock(fileName string) (Releaser, error) { + f, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0644) + if err != nil { + return nil, err + } + l := &unixLock{f} + err = l.set(true) + if err != nil { + f.Close() + return nil, err + } + return l, nil +} diff --git a/vendor/github.com/prometheus/prometheus/util/flock/flock_unix.go b/vendor/github.com/prometheus/prometheus/util/flock/flock_unix.go new file mode 100644 index 0000000000..7d71f8fc09 --- /dev/null +++ b/vendor/github.com/prometheus/prometheus/util/flock/flock_unix.go @@ -0,0 +1,54 @@ +// Copyright 2016 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build darwin dragonfly freebsd linux netbsd openbsd + +package flock + +import ( + "os" + "syscall" +) + +type unixLock struct { + f *os.File +} + +func (l *unixLock) Release() error { + if err := l.set(false); err != nil { + return err + } + return l.f.Close() +} + +func (l *unixLock) set(lock bool) error { + how := syscall.LOCK_UN + if lock { + how = syscall.LOCK_EX + } + return syscall.Flock(int(l.f.Fd()), how|syscall.LOCK_NB) +} + +func newLock(fileName string) (Releaser, error) { + f, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0644) + if err != nil { + return nil, err + } + l := &unixLock{f} + err = l.set(true) + if err != nil { + f.Close() + return nil, err + } + return l, nil +} diff --git a/vendor/github.com/prometheus/prometheus/util/flock/flock_windows.go b/vendor/github.com/prometheus/prometheus/util/flock/flock_windows.go new file mode 100644 index 0000000000..bf7266f14c --- /dev/null +++ b/vendor/github.com/prometheus/prometheus/util/flock/flock_windows.go @@ -0,0 +1,36 @@ +// Copyright 2016 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package flock + +import "syscall" + +type windowsLock struct { + fd syscall.Handle +} + +func (fl *windowsLock) Release() error { + return syscall.Close(fl.fd) +} + +func newLock(fileName string) (Releaser, error) { + pathp, err := syscall.UTF16PtrFromString(fileName) + if err != nil { + return nil, err + } + fd, err := syscall.CreateFile(pathp, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.CREATE_ALWAYS, syscall.FILE_ATTRIBUTE_NORMAL, 0) + if err != nil { + return nil, err + } + return &windowsLock{fd}, nil +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 9764a4783c..56c95e341f 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -255,6 +255,12 @@ "revision": "bf27d3ba8e1d9899d45a457ffac16c953eb2d647", "revisionTime": "2017-02-11T19:53:22Z" }, + { + "checksumSHA1": "WbbxCn2jUYIL5viqLo0BKXEdPrQ=", + "path": "github.com/prometheus/prometheus/util/flock", + "revision": "3101606756c53221ed58ba94ecba6b26adf89dcc", + "revisionTime": "2017-08-14T17:01:13Z" + }, { "checksumSHA1": "KAzbLjI9MzW2tjfcAsK75lVRp6I=", "path": "github.com/rcrowley/go-metrics",