mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
Merge 3acffa944d into 32c05e82a3
This commit is contained in:
commit
58df708484
16 changed files with 224 additions and 95 deletions
|
|
@ -154,7 +154,7 @@ func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Addres
|
|||
return nil, errBlockNumberUnsupported
|
||||
}
|
||||
statedb, _ := b.blockchain.State()
|
||||
val := statedb.GetState(contract, key)
|
||||
val, _ := statedb.GetState(contract, key)
|
||||
return val[:], nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,9 @@ type (
|
|||
}
|
||||
storageChange struct {
|
||||
account *common.Address
|
||||
key, prevalue common.Hash
|
||||
key common.Hash
|
||||
prevValue common.Hash
|
||||
prevDirty bool
|
||||
}
|
||||
codeChange struct {
|
||||
account *common.Address
|
||||
|
|
@ -196,7 +198,7 @@ func (ch codeChange) dirtied() *common.Address {
|
|||
}
|
||||
|
||||
func (ch storageChange) revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
|
||||
s.getStateObject(*ch.account).setState(ch.key, ch.prevValue, ch.prevDirty)
|
||||
}
|
||||
|
||||
func (ch storageChange) dirtied() *common.Address {
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ type stateObject struct {
|
|||
trie Trie // storage trie, which becomes non-nil on first access
|
||||
code Code // contract bytecode, which gets set when code is loaded
|
||||
|
||||
cachedStorage Storage // Storage entry cache to avoid duplicate reads
|
||||
originStorage Storage // Storage cache of original entries to dedup rewrites
|
||||
dirtyStorage Storage // Storage entries that need to be flushed to disk
|
||||
|
||||
// Cache flags.
|
||||
|
|
@ -115,7 +115,7 @@ func newObject(db *StateDB, address common.Address, data Account) *stateObject {
|
|||
address: address,
|
||||
addrHash: crypto.Keccak256Hash(address[:]),
|
||||
data: data,
|
||||
cachedStorage: make(Storage),
|
||||
originStorage: make(Storage),
|
||||
dirtyStorage: make(Storage),
|
||||
}
|
||||
}
|
||||
|
|
@ -159,17 +159,22 @@ func (c *stateObject) getTrie(db Database) Trie {
|
|||
return c.trie
|
||||
}
|
||||
|
||||
// GetState returns a value in account storage.
|
||||
func (self *stateObject) GetState(db Database, key common.Hash) common.Hash {
|
||||
value, exists := self.cachedStorage[key]
|
||||
if exists {
|
||||
return value
|
||||
// GetState returns a value from account storage, and also whether the slot is
|
||||
// dirty in the current transaction execution context.
|
||||
func (self *stateObject) GetState(db Database, key common.Hash) (common.Hash, bool) {
|
||||
value, dirty := self.dirtyStorage[key]
|
||||
if dirty {
|
||||
return value, true
|
||||
}
|
||||
value, cached := self.originStorage[key]
|
||||
if cached {
|
||||
return value, false
|
||||
}
|
||||
// Load from DB in case it is missing.
|
||||
enc, err := self.getTrie(db).TryGet(key[:])
|
||||
if err != nil {
|
||||
self.setError(err)
|
||||
return common.Hash{}
|
||||
return common.Hash{}, false
|
||||
}
|
||||
if len(enc) > 0 {
|
||||
_, content, _, err := rlp.Split(enc)
|
||||
|
|
@ -178,23 +183,34 @@ func (self *stateObject) GetState(db Database, key common.Hash) common.Hash {
|
|||
}
|
||||
value.SetBytes(content)
|
||||
}
|
||||
self.cachedStorage[key] = value
|
||||
return value
|
||||
self.originStorage[key] = value
|
||||
return value, false
|
||||
}
|
||||
|
||||
// SetState updates a value in account storage.
|
||||
func (self *stateObject) SetState(db Database, key, value common.Hash) {
|
||||
// If the new value is the same as old, don't set and don't mark dirty
|
||||
prev, dirty := self.GetState(db, key)
|
||||
if prev == value {
|
||||
return
|
||||
}
|
||||
// New value is different, update and journal the change
|
||||
self.setState(key, value, true)
|
||||
|
||||
self.db.journal.append(storageChange{
|
||||
account: &self.address,
|
||||
key: key,
|
||||
prevalue: self.GetState(db, key),
|
||||
prevValue: prev,
|
||||
prevDirty: dirty,
|
||||
})
|
||||
self.setState(key, value)
|
||||
}
|
||||
|
||||
func (self *stateObject) setState(key, value common.Hash) {
|
||||
self.cachedStorage[key] = value
|
||||
func (self *stateObject) setState(key, value common.Hash, dirty bool) {
|
||||
if dirty {
|
||||
self.dirtyStorage[key] = value
|
||||
} else {
|
||||
delete(self.dirtyStorage, key)
|
||||
}
|
||||
}
|
||||
|
||||
// updateTrie writes cached storage modifications into the object's storage trie.
|
||||
|
|
@ -202,6 +218,13 @@ func (self *stateObject) updateTrie(db Database) Trie {
|
|||
tr := self.getTrie(db)
|
||||
for key, value := range self.dirtyStorage {
|
||||
delete(self.dirtyStorage, key)
|
||||
|
||||
// Skip noop changes, persist actual changes
|
||||
if value == self.originStorage[key] {
|
||||
continue
|
||||
}
|
||||
self.originStorage[key] = value
|
||||
|
||||
if (value == common.Hash{}) {
|
||||
self.setError(tr.TryDelete(key[:]))
|
||||
continue
|
||||
|
|
@ -279,7 +302,7 @@ func (self *stateObject) deepCopy(db *StateDB) *stateObject {
|
|||
}
|
||||
stateObject.code = self.code
|
||||
stateObject.dirtyStorage = self.dirtyStorage.Copy()
|
||||
stateObject.cachedStorage = self.dirtyStorage.Copy()
|
||||
stateObject.originStorage = self.originStorage.Copy()
|
||||
stateObject.suicided = self.suicided
|
||||
stateObject.dirtyCode = self.dirtyCode
|
||||
stateObject.deleted = self.deleted
|
||||
|
|
|
|||
|
|
@ -96,12 +96,17 @@ func (s *StateSuite) TestNull(c *checker.C) {
|
|||
s.state.CreateAccount(address)
|
||||
//value := common.FromHex("0x823140710bf13990e4500136726d8b55")
|
||||
var value common.Hash
|
||||
|
||||
s.state.SetState(address, common.Hash{}, value)
|
||||
s.state.Commit(false)
|
||||
value = s.state.GetState(address, common.Hash{})
|
||||
|
||||
value, dirty := s.state.GetState(address, common.Hash{})
|
||||
if value != (common.Hash{}) {
|
||||
c.Errorf("expected empty hash. got %x", value)
|
||||
}
|
||||
if dirty {
|
||||
c.Errorf("expected non-dirty, got dirty")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StateSuite) TestSnapshot(c *checker.C) {
|
||||
|
|
@ -110,20 +115,27 @@ func (s *StateSuite) TestSnapshot(c *checker.C) {
|
|||
data1 := common.BytesToHash([]byte{42})
|
||||
data2 := common.BytesToHash([]byte{43})
|
||||
|
||||
// set initial state object value
|
||||
// snapshot the genesis state
|
||||
genesis := s.state.Snapshot()
|
||||
|
||||
// set initial state object value and snapshot it
|
||||
s.state.SetState(stateobjaddr, storageaddr, data1)
|
||||
// get snapshot of current state
|
||||
snapshot := s.state.Snapshot()
|
||||
|
||||
// set new state object value
|
||||
// set a new state object value, revert it and ensure correct content
|
||||
s.state.SetState(stateobjaddr, storageaddr, data2)
|
||||
// restore snapshot
|
||||
s.state.RevertToSnapshot(snapshot)
|
||||
|
||||
// get state storage value
|
||||
res := s.state.GetState(stateobjaddr, storageaddr)
|
||||
value, dirty := s.state.GetState(stateobjaddr, storageaddr)
|
||||
c.Assert(data1, checker.DeepEquals, value)
|
||||
c.Assert(true, checker.DeepEquals, dirty)
|
||||
|
||||
c.Assert(data1, checker.DeepEquals, res)
|
||||
// revert up to the genesis state and ensure correct content
|
||||
s.state.RevertToSnapshot(genesis)
|
||||
|
||||
value, dirty = s.state.GetState(stateobjaddr, storageaddr)
|
||||
c.Assert(common.Hash{}, checker.DeepEquals, value)
|
||||
c.Assert(false, checker.DeepEquals, dirty)
|
||||
}
|
||||
|
||||
func (s *StateSuite) TestSnapshotEmpty(c *checker.C) {
|
||||
|
|
@ -208,17 +220,30 @@ func compareStateObjects(so0, so1 *stateObject, t *testing.T) {
|
|||
t.Fatalf("Code mismatch: have %v, want %v", so0.code, so1.code)
|
||||
}
|
||||
|
||||
if len(so1.cachedStorage) != len(so0.cachedStorage) {
|
||||
t.Errorf("Storage size mismatch: have %d, want %d", len(so1.cachedStorage), len(so0.cachedStorage))
|
||||
if len(so1.dirtyStorage) != len(so0.dirtyStorage) {
|
||||
t.Errorf("Dirty storage size mismatch: have %d, want %d", len(so1.dirtyStorage), len(so0.dirtyStorage))
|
||||
}
|
||||
for k, v := range so1.cachedStorage {
|
||||
if so0.cachedStorage[k] != v {
|
||||
t.Errorf("Storage key %x mismatch: have %v, want %v", k, so0.cachedStorage[k], v)
|
||||
for k, v := range so1.dirtyStorage {
|
||||
if so0.dirtyStorage[k] != v {
|
||||
t.Errorf("Dirty storage key %x mismatch: have %v, want %v", k, so0.dirtyStorage[k], v)
|
||||
}
|
||||
}
|
||||
for k, v := range so0.cachedStorage {
|
||||
if so1.cachedStorage[k] != v {
|
||||
t.Errorf("Storage key %x mismatch: have %v, want none.", k, v)
|
||||
for k, v := range so0.dirtyStorage {
|
||||
if so1.dirtyStorage[k] != v {
|
||||
t.Errorf("Dirty storage key %x mismatch: have %v, want none.", k, v)
|
||||
}
|
||||
}
|
||||
if len(so1.originStorage) != len(so0.originStorage) {
|
||||
t.Errorf("Origin storage size mismatch: have %d, want %d", len(so1.originStorage), len(so0.originStorage))
|
||||
}
|
||||
for k, v := range so1.originStorage {
|
||||
if so0.originStorage[k] != v {
|
||||
t.Errorf("Origin storage key %x mismatch: have %v, want %v", k, so0.originStorage[k], v)
|
||||
}
|
||||
}
|
||||
for k, v := range so0.originStorage {
|
||||
if so1.originStorage[k] != v {
|
||||
t.Errorf("Origin storage key %x mismatch: have %v, want none.", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
|
@ -236,12 +237,12 @@ func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
|
|||
return common.BytesToHash(stateObject.CodeHash())
|
||||
}
|
||||
|
||||
func (self *StateDB) GetState(addr common.Address, bhash common.Hash) common.Hash {
|
||||
func (self *StateDB) GetState(addr common.Address, bhash common.Hash) (common.Hash, bool) {
|
||||
stateObject := self.getStateObject(addr)
|
||||
if stateObject != nil {
|
||||
return stateObject.GetState(self.db, bhash)
|
||||
}
|
||||
return common.Hash{}
|
||||
return common.Hash{}, false
|
||||
}
|
||||
|
||||
// Database retrieves the low level database supporting the lower level trie ops.
|
||||
|
|
@ -430,24 +431,19 @@ func (self *StateDB) CreateAccount(addr common.Address) {
|
|||
}
|
||||
}
|
||||
|
||||
func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) {
|
||||
func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash, dirty bool) bool) {
|
||||
so := db.getStateObject(addr)
|
||||
if so == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// When iterating over the storage check the cache first
|
||||
for h, value := range so.cachedStorage {
|
||||
cb(h, value)
|
||||
}
|
||||
|
||||
it := trie.NewIterator(so.getTrie(db.db).NodeIterator(nil))
|
||||
for it.Next() {
|
||||
// ignore cached values
|
||||
key := common.BytesToHash(db.trie.GetKey(it.Key))
|
||||
if _, ok := so.cachedStorage[key]; !ok {
|
||||
cb(key, common.BytesToHash(it.Value))
|
||||
if value, dirty := so.dirtyStorage[key]; dirty {
|
||||
cb(key, value, true)
|
||||
continue
|
||||
}
|
||||
cb(key, common.BytesToHash(it.Value), false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -527,9 +523,36 @@ func (self *StateDB) RevertToSnapshot(revid int) {
|
|||
self.validRevisions = self.validRevisions[:idx]
|
||||
}
|
||||
|
||||
// GetRefund returns the current value of the refund counter.
|
||||
func (self *StateDB) GetRefund() uint64 {
|
||||
return self.refund
|
||||
// GetRefund returns the current value of the refund counter and any out-of-band
|
||||
// refunds at the end of the transaction.
|
||||
func (self *StateDB) GetRefund(netSstoreMeter bool) uint64 {
|
||||
// If legacy gas metering is used, return the current refund counter
|
||||
refund := self.refund
|
||||
if !netSstoreMeter {
|
||||
return refund
|
||||
}
|
||||
// If we're already using the Constantinople net sstore gas metering, refund noops
|
||||
for addr := range self.journal.dirties {
|
||||
object := self.stateObjects[addr]
|
||||
for key, value := range object.dirtyStorage {
|
||||
// If the slot didn't change in the end, refund most gas
|
||||
if value == object.originStorage[key] {
|
||||
if value == (common.Hash{}) {
|
||||
refund += params.NetSstoreRefundNoopZero
|
||||
} else {
|
||||
refund += params.NetSstoreRefundNoopNonZero
|
||||
}
|
||||
continue
|
||||
}
|
||||
// If the slot did change, but was set to zero, refund
|
||||
if value == (common.Hash{}) {
|
||||
refund += params.NetSstoreRefund
|
||||
continue
|
||||
}
|
||||
// Sorry, no refund for this slot
|
||||
}
|
||||
}
|
||||
return refund
|
||||
}
|
||||
|
||||
// Finalise finalises the state by removing the self destructed objects
|
||||
|
|
|
|||
|
|
@ -381,11 +381,19 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
|
|||
checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr))
|
||||
// Check storage.
|
||||
if obj := state.getStateObject(addr); obj != nil {
|
||||
state.ForEachStorage(addr, func(key, val common.Hash) bool {
|
||||
return checkeq("GetState("+key.Hex()+")", val, checkstate.GetState(addr, key))
|
||||
state.ForEachStorage(addr, func(key, value common.Hash, dirty bool) bool {
|
||||
v, d := checkstate.GetState(addr, key)
|
||||
if ok := checkeq("GetState("+key.Hex()+").value", value, v); ok {
|
||||
return ok
|
||||
}
|
||||
return checkeq("GetState("+key.Hex()+").dirty", dirty, d)
|
||||
})
|
||||
checkstate.ForEachStorage(addr, func(key, checkval common.Hash) bool {
|
||||
return checkeq("GetState("+key.Hex()+")", state.GetState(addr, key), checkval)
|
||||
checkstate.ForEachStorage(addr, func(key, value common.Hash, dirty bool) bool {
|
||||
v, d := state.GetState(addr, key)
|
||||
if ok := checkeq("GetState("+key.Hex()+").value", v, value); ok {
|
||||
return ok
|
||||
}
|
||||
return checkeq("GetState("+key.Hex()+").dirty", d, dirty)
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
|
|
@ -393,9 +401,11 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
|
|||
}
|
||||
}
|
||||
|
||||
if state.GetRefund() != checkstate.GetRefund() {
|
||||
return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d",
|
||||
state.GetRefund(), checkstate.GetRefund())
|
||||
for _, netGasMetering := range []bool{false, true} {
|
||||
if state.GetRefund(netGasMetering) != checkstate.GetRefund(netGasMetering) {
|
||||
return fmt.Errorf("got GetRefund(%v) == %d, want GetRefund(%v) == %d",
|
||||
netGasMetering, state.GetRefund(netGasMetering), netGasMetering, checkstate.GetRefund(netGasMetering))
|
||||
}
|
||||
}
|
||||
if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) {
|
||||
return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v",
|
||||
|
|
|
|||
|
|
@ -229,9 +229,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
|
|||
|
||||
func (st *StateTransition) refundGas() {
|
||||
// Apply refund counter, capped to half of the used gas.
|
||||
refund := st.gasUsed() / 2
|
||||
if refund > st.state.GetRefund() {
|
||||
refund = st.state.GetRefund()
|
||||
netSstoreMeter := st.evm.ChainConfig().IsConstantinople(st.evm.BlockNumber)
|
||||
|
||||
refund := st.state.GetRefund(netSstoreMeter)
|
||||
if refund > st.gasUsed()/2 {
|
||||
refund = st.gasUsed() / 2
|
||||
}
|
||||
st.gas += refund
|
||||
|
||||
|
|
|
|||
|
|
@ -118,24 +118,52 @@ func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *
|
|||
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))
|
||||
value, dirty = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
|
||||
)
|
||||
// The legacy gas metering only takes into consideration the current state
|
||||
if !evm.chainRules.IsConstantinople {
|
||||
// This checks for 3 scenario's and calculates gas accordingly
|
||||
// 1. From a zero-value address to a non-zero value (NEW VALUE)
|
||||
// 2. From a non-zero value address to a zero-value address (DELETE)
|
||||
// 3. From a non-zero to a non-zero (CHANGE)
|
||||
if val == (common.Hash{}) && y.Sign() != 0 {
|
||||
// 0 => non 0
|
||||
switch {
|
||||
case value == (common.Hash{}) && y.Sign() != 0: // 0 => non 0
|
||||
return params.SstoreSetGas, nil
|
||||
} else if val != (common.Hash{}) && y.Sign() == 0 {
|
||||
// non 0 => 0
|
||||
case value != (common.Hash{}) && y.Sign() == 0: // non 0 => 0
|
||||
evm.StateDB.AddRefund(params.SstoreRefundGas)
|
||||
return params.SstoreClearGas, nil
|
||||
} else {
|
||||
// non 0 => non 0 (or 0 => 0)
|
||||
default: // non 0 => non 0 (or 0 => 0)
|
||||
return params.SstoreResetGas, nil
|
||||
}
|
||||
}
|
||||
// The new gas metering is based on net gas costs (EIP-1087)
|
||||
//
|
||||
// 0. A ‘dirty map’ for each transaction is maintained, tracking all storage
|
||||
// slots in all contracts that have been modified in the current transaction.
|
||||
// The dirty map is scoped in the same manner as updates to storage, meaning
|
||||
// that changes to the dirty map in a call that later reverts are not retained.
|
||||
// 1. When a storage slot is written to with the value it already contains, 200
|
||||
// gas is deducted, but is not explicitly marked dirty.
|
||||
// 2. When a storage slot’s value is changed for the first time, the slot is
|
||||
// marked as dirty. If the slot was previously set to 0, 20000 gas is deducted;
|
||||
// otherwise, 5000 gas is deducted.
|
||||
// 2. When a storage slot that is already in the dirty map is written to, 200
|
||||
// gas is deducted.
|
||||
// 3. At the end of the transaction, for each slot in the dirty map:
|
||||
// * If the slot was 0 before the transaction and is 0 now, refund 19800 gas.
|
||||
// * If the slot was nonzero before the transaction and its value has not changed, refund 4800 gas.
|
||||
// * If the slot was nonzero before the transaction and is 0 now, refund 10000 gas.
|
||||
switch {
|
||||
case value == common.BigToHash(y): // noop
|
||||
return params.NetSstoreNoopGas, nil
|
||||
case !dirty && y.Sign() != 0 && value == (common.Hash{}): // clean(0) => anything
|
||||
return params.NetSstoreCleanInitgas, nil
|
||||
case !dirty && y.Sign() != 0: // clean(non 0) => anything
|
||||
return params.NetSstoreCleanUpdateGas, nil
|
||||
default: // dirty(anything) => anything
|
||||
return params.NetSstoreDirtyGas, nil
|
||||
}
|
||||
}
|
||||
|
||||
func makeGasLog(n uint64) gasFunc {
|
||||
return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
|
|
|
|||
|
|
@ -604,7 +604,7 @@ func opMstore8(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
|
|||
|
||||
func opSload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
loc := stack.peek()
|
||||
val := interpreter.evm.StateDB.GetState(contract.Address(), common.BigToHash(loc))
|
||||
val, _ := interpreter.evm.StateDB.GetState(contract.Address(), common.BigToHash(loc))
|
||||
loc.SetBytes(val.Bytes())
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ type StateDB interface {
|
|||
GetCodeSize(common.Address) int
|
||||
|
||||
AddRefund(uint64)
|
||||
GetRefund() uint64
|
||||
GetRefund(bool) uint64
|
||||
|
||||
GetState(common.Address, common.Hash) common.Hash
|
||||
GetState(common.Address, common.Hash) (common.Hash, bool)
|
||||
SetState(common.Address, common.Hash, common.Hash)
|
||||
|
||||
Suicide(common.Address) bool
|
||||
|
|
@ -61,7 +61,7 @@ type StateDB interface {
|
|||
AddLog(*types.Log)
|
||||
AddPreimage(common.Hash, []byte)
|
||||
|
||||
ForEachStorage(common.Address, func(common.Hash, common.Hash) bool)
|
||||
ForEachStorage(common.Address, func(common.Hash, common.Hash, bool) bool)
|
||||
}
|
||||
|
||||
// CallContext provides a basic interface for the EVM calling conventions. The EVM
|
||||
|
|
|
|||
|
|
@ -134,7 +134,6 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
in.intPool = nil
|
||||
}()
|
||||
}
|
||||
|
||||
// Increment the call depth which is restricted to 1024
|
||||
in.evm.depth++
|
||||
defer func() { in.evm.depth-- }()
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ func (dw *dbWrapper) pushObject(vm *duktape.Context) {
|
|||
hash := popSlice(ctx)
|
||||
addr := popSlice(ctx)
|
||||
|
||||
state := dw.db.GetState(common.BytesToAddress(addr), common.BytesToHash(hash))
|
||||
state, _ := dw.db.GetState(common.BytesToAddress(addr), common.BytesToHash(hash))
|
||||
|
||||
ptr := ctx.PushFixedBuffer(len(state))
|
||||
copy(makeSlice(ptr, uint(len(state))), state[:])
|
||||
|
|
|
|||
|
|
@ -597,7 +597,7 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A
|
|||
if state == nil || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := state.GetState(address, common.HexToHash(key))
|
||||
res, _ := state.GetState(address, common.HexToHash(key))
|
||||
return res[:], state.Error()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -383,7 +383,7 @@ func (err *ConfigCompatError) Error() string {
|
|||
type Rules struct {
|
||||
ChainID *big.Int
|
||||
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
|
||||
IsByzantium bool
|
||||
IsByzantium, IsConstantinople bool
|
||||
}
|
||||
|
||||
// Rules ensures c's ChainID is not nil.
|
||||
|
|
@ -392,5 +392,12 @@ func (c *ChainConfig) Rules(num *big.Int) Rules {
|
|||
if chainID == nil {
|
||||
chainID = new(big.Int)
|
||||
}
|
||||
return Rules{ChainID: new(big.Int).Set(chainID), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num), IsByzantium: c.IsByzantium(num)}
|
||||
return Rules{
|
||||
ChainID: new(big.Int).Set(chainID),
|
||||
IsHomestead: c.IsHomestead(num),
|
||||
IsEIP150: c.IsEIP150(num),
|
||||
IsEIP155: c.IsEIP155(num),
|
||||
IsEIP158: c.IsEIP158(num),
|
||||
IsByzantium: c.IsByzantium(num),
|
||||
IsConstantinople: c.IsConstantinople(num)}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,15 +32,25 @@ const (
|
|||
TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions.
|
||||
TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
|
||||
QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation.
|
||||
SstoreSetGas uint64 = 20000 // Once per SLOAD operation.
|
||||
LogDataGas uint64 = 8 // Per byte in a LOG* operation's data.
|
||||
CallStipend uint64 = 2300 // Free gas given at beginning of call.
|
||||
|
||||
Sha3Gas uint64 = 30 // Once per SHA3 operation.
|
||||
Sha3WordGas uint64 = 6 // Once per word of the SHA3 operation's data.
|
||||
|
||||
SstoreSetGas uint64 = 20000 // Once per SSTORE operation.
|
||||
SstoreResetGas uint64 = 5000 // Once per SSTORE operation if the zeroness changes from zero.
|
||||
SstoreClearGas uint64 = 5000 // Once per SSTORE operation if the zeroness doesn't change.
|
||||
SstoreRefundGas uint64 = 15000 // Once per SSTORE operation if the zeroness changes to zero.
|
||||
|
||||
NetSstoreNoopGas uint64 = 200 // Once per SSTORE operation if the value doesn't change.
|
||||
NetSstoreDirtyGas uint64 = 200 // Once per SSTORE operation from dirty.
|
||||
NetSstoreCleanInitgas uint64 = 20000 // Once per SSTORE operation from clean zero.
|
||||
NetSstoreCleanUpdateGas uint64 = 5000 // Once per SSTORE operation from clean non-zero.
|
||||
NetSstoreRefundNoopZero uint64 = 19800 // Once per dirty slot if it was changed from zero to non-zero and back to zero.
|
||||
NetSstoreRefundNoopNonZero uint64 = 4800 // Once per dirty slot if it was changed from non-zero to anything and back to the orignal.
|
||||
NetSstoreRefund uint64 = 10000 // Once per dirty slot if it was changed from non-zero to zero.
|
||||
|
||||
JumpdestGas uint64 = 1 // Refunded gas, once per SSTORE operation if the zeroness changes to zero.
|
||||
EpochDuration uint64 = 30000 // Duration between proof-of-work epochs.
|
||||
CallGas uint64 = 40 // Once per CALL operation & message call transaction.
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ func (t *VMTest) Run(vmconfig vm.Config) error {
|
|||
}
|
||||
for addr, account := range t.json.Post {
|
||||
for k, wantV := range account.Storage {
|
||||
if haveV := statedb.GetState(addr, k); haveV != wantV {
|
||||
if haveV, _ := statedb.GetState(addr, k); haveV != wantV {
|
||||
return fmt.Errorf("wrong storage value at %x:\n got %x\n want %x", k, haveV, wantV)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue