From caa2c23a38141911a570ba098a940b4fdbf0aa88 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sun, 12 Aug 2018 14:47:03 +0200 Subject: [PATCH] core,state: finish implementing Eip 1283 --- core/state/state_object.go | 10 ++++++++++ core/state/statedb.go | 8 ++++++++ core/vm/gas_table.go | 29 +++++++++++++---------------- core/vm/interface.go | 1 + core/vm/jump_table.go | 8 ++++++++ core/vm/noop.go | 1 + 6 files changed, 41 insertions(+), 16 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 0b72d01140..b05afec936 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -183,6 +183,16 @@ func (self *stateObject) GetState(db Database, key common.Hash) common.Hash { return value } +// GetOriginalStateValue returns the state value that is currently in the Trie, that is, ignoring any +// changes that have been made but not yet written to trie. +func (self *stateObject) GetOriginalStateValue(db Database, key common.Hash) common.Hash{ + if original, exist:= self.originalValue[key]; exist { + // original value has been set, return it + return original + } + return self.GetState(db, key) +} + // SetState updates a value in account storage. func (self *stateObject) SetState(db Database, key, value common.Hash) { prev := self.GetState(db, key) diff --git a/core/state/statedb.go b/core/state/statedb.go index d9300012d6..515ff57bf2 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -255,6 +255,14 @@ func (self *StateDB) GetState(addr common.Address, bhash common.Hash) common.Has return common.Hash{} } +func (self *StateDB) GetStateOriginal(addr common.Address, bhash common.Hash) common.Hash { + stateObject := self.getStateObject(addr) + if stateObject != nil { + return stateObject.GetOriginalStateValue(self.db, bhash) + } + return common.Hash{} +} + // Database retrieves the low level database supporting the lower level trie ops. func (self *StateDB) Database() Database { return self.db diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index aee6d6f6d7..77250978d9 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -17,11 +17,9 @@ package vm import ( - "bytes" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/params" - "math/big" ) // memoryGasCosts calculates the quadratic gas for memory expansion. It does so @@ -117,7 +115,7 @@ func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack * return gas, nil } -func gasSStoreOld(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { var ( y, x = stack.Back(1), stack.Back(0) val = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) @@ -139,10 +137,11 @@ func gasSStoreOld(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack } } -func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +// gasSStoreEip1283 calculates SSTORE gas cost according to EIP-1283 +func gasSStoreEip1283(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { var ( - y, x = stack.Back(1), stack.Back(0) - current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) + y, x = stack.Back(1), stack.Back(0) + current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) ) //1. If current value equals new value (this is a no-op), 200 gas is deducted. //2. If current value does not equal new value @@ -161,33 +160,31 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m // 1. current == new return 200, nil } - // Todo, get this value - original := common.Hash{} - + original := evm.StateDB.GetStateOriginal(contract.Address(), common.BigToHash(x)) // 2 if original == current { // 2.1 - if original == (common.Hash{}){ // 2.1.1 + if original == (common.Hash{}) { // 2.1.1 return 20000, nil } // 2.1.2 - if new == (common.Hash{}){ + if new == (common.Hash{}) { evm.StateDB.AddRefund(15000) } return 5000, nil } // 2.2 - if original != (common.Hash{}){ // 2.2.1 - if current == (common.Hash{}){ // 2.2.1.1 + if original != (common.Hash{}) { // 2.2.1 + if current == (common.Hash{}) { // 2.2.1.1 evm.StateDB.SubRefund(15000) - }else{ + } else { // 2.2.1.2 evm.StateDB.AddRefund(15000) } } if original == new { // 2.2.2 - if original == (common.Hash{}){ + if original == (common.Hash{}) { evm.StateDB.AddRefund(19800) - }else{ + } else { evm.StateDB.AddRefund(4800) } } diff --git a/core/vm/interface.go b/core/vm/interface.go index a5a3ff3e32..2e2e3e925a 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -44,6 +44,7 @@ type StateDB interface { GetRefund() uint64 GetState(common.Address, common.Hash) common.Hash + GetStateOriginal(common.Address, common.Hash) common.Hash SetState(common.Address, common.Hash, common.Hash) Suicide(common.Address) bool diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index deedf70cdb..8a997adc42 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -95,6 +95,14 @@ func newConstantinopleInstructionSet() [256]operation { writes: true, returns: true, } + instructionSet[SSTORE] = operation{ + execute: opSstore, + gasCost: gasSStoreEip1283, + validateStack: makeStackFunc(2, 0), + valid: true, + writes: true, + } + return instructionSet } diff --git a/core/vm/noop.go b/core/vm/noop.go index c7ed2e4515..19539d9780 100644 --- a/core/vm/noop.go +++ b/core/vm/noop.go @@ -59,6 +59,7 @@ func (NoopStateDB) AddRefund(uint64) func (NoopStateDB) SubRefund(uint64) {} func (NoopStateDB) GetRefund() uint64 { return 0 } func (NoopStateDB) GetState(common.Address, common.Hash) common.Hash { return common.Hash{} } +func (NoopStateDB) GetStateOriginal(common.Address, common.Hash) common.Hash { return common.Hash{} } func (NoopStateDB) SetState(common.Address, common.Hash, common.Hash) {} func (NoopStateDB) Suicide(common.Address) bool { return false } func (NoopStateDB) HasSuicided(common.Address) bool { return false }