From 58374e28d95c03d8b0e6d9035c0fb92fad3e865e Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sat, 11 Aug 2018 23:03:54 +0200 Subject: core, state: initial implementation of Eip-1283 --- core/state/state_object.go | 15 ++++++++++-- core/state/statedb.go | 11 +++++++++ core/vm/gas_table.go | 59 +++++++++++++++++++++++++++++++++++++++++++++- core/vm/interface.go | 1 + core/vm/noop.go | 1 + 5 files changed, 84 insertions(+), 3 deletions(-) (limited to 'core') diff --git a/core/state/state_object.go b/core/state/state_object.go index 091d24184..0b72d0114 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -79,7 +79,7 @@ type stateObject struct { cachedStorage Storage // Storage entry cache to avoid duplicate reads dirtyStorage Storage // Storage entries that need to be flushed to disk - + originalValue Storage // Map of original storage values, at the beginning of current call context // Cache flags. // When an object is marked suicided it will be delete from the trie // during the "update" phase of the state transition. @@ -117,6 +117,7 @@ func newObject(db *StateDB, address common.Address, data Account) *stateObject { data: data, cachedStorage: make(Storage), dirtyStorage: make(Storage), + originalValue: make(Storage), } } @@ -184,11 +185,16 @@ func (self *stateObject) GetState(db Database, key common.Hash) common.Hash { // SetState updates a value in account storage. func (self *stateObject) SetState(db Database, key, value common.Hash) { + prev := self.GetState(db, key) self.db.journal.append(storageChange{ account: &self.address, key: key, - prevalue: self.GetState(db, key), + prevalue: prev, }) + if _, isSet := self.originalValue[key]; !isSet { + // original value has not been set, so set it now + self.originalValue[key] = prev + } self.setState(key, value) } @@ -210,6 +216,10 @@ func (self *stateObject) updateTrie(db Database) Trie { v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00")) self.setError(tr.TryUpdate(key[:], v)) } + // Clean the map containing 'original' value of storage entries + for k, _ := range self.originalValue { + delete(self.originalValue, k) + } return tr } @@ -280,6 +290,7 @@ func (self *stateObject) deepCopy(db *StateDB) *stateObject { stateObject.code = self.code stateObject.dirtyStorage = self.dirtyStorage.Copy() stateObject.cachedStorage = self.dirtyStorage.Copy() + stateObject.originalValue = self.originalValue.Copy() stateObject.suicided = self.suicided stateObject.dirtyCode = self.dirtyCode stateObject.deleted = self.deleted diff --git a/core/state/statedb.go b/core/state/statedb.go index 101b03a12..d9300012d 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -169,11 +169,22 @@ func (self *StateDB) Preimages() map[common.Hash][]byte { return self.preimages } +// AddRefund adds gas to the refund counter func (self *StateDB) AddRefund(gas uint64) { self.journal.append(refundChange{prev: self.refund}) self.refund += gas } +// SubRefund removes gas from the refund counter. +// This method will panic if the refund counter goes below zero +func (self *StateDB) SubRefund(gas uint64) { + self.journal.append(refundChange{prev: self.refund}) + if gas > self.refund { + panic("Refund counter below zero") + } + self.refund -= gas +} + // Exist reports whether the given account address exists in the state. // Notably this also returns true for suicided accounts. func (self *StateDB) Exist(addr common.Address) bool { diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index f9eea319e..aee6d6f6d 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -17,9 +17,11 @@ 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 @@ -115,7 +117,7 @@ func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack * return gas, nil } -func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSStoreOld(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)) @@ -137,6 +139,61 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m } } +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) + 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 + // 2.1 If original value equals current value (this storage slot has not been changed by the current execution context) + // 2.1.1 If original value is 0, 20000 gas is deducted. + // 2.1.2 Otherwise, 5000 gas is deducted. If new value is 0, add 15000 gas to refund counter. + // 2.2 If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses. + // 2.2.1 If original value is not 0 + // 2.2.1.1 If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0. + // 2.2.1.2 If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter. + // 2.2.2 If original value equals new value (this storage slot is reset) + // 2.2.2.1 If original value is 0, add 19800 gas to refund counter. + // 2.2.2.2 Otherwise, add 4800 gas to refund counter. + new := common.BigToHash(y) + if current == new { + // 1. current == new + return 200, nil + } + // Todo, get this value + original := common.Hash{} + + // 2 + if original == current { // 2.1 + if original == (common.Hash{}){ // 2.1.1 + return 20000, nil + } + // 2.1.2 + 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 + evm.StateDB.SubRefund(15000) + }else{ + // 2.2.1.2 + evm.StateDB.AddRefund(15000) + } + } + if original == new { // 2.2.2 + if original == (common.Hash{}){ + evm.StateDB.AddRefund(19800) + }else{ + evm.StateDB.AddRefund(4800) + } + } + return 200, nil +} + func makeGasLog(n uint64) gasFunc { return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { requestedSize, overflow := bigUint64(stack.Back(1)) diff --git a/core/vm/interface.go b/core/vm/interface.go index d176f5b39..a5a3ff3e3 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -40,6 +40,7 @@ type StateDB interface { GetCodeSize(common.Address) int AddRefund(uint64) + SubRefund(uint64) GetRefund() uint64 GetState(common.Address, common.Hash) common.Hash diff --git a/core/vm/noop.go b/core/vm/noop.go index b71ead0d7..c7ed2e451 100644 --- a/core/vm/noop.go +++ b/core/vm/noop.go @@ -56,6 +56,7 @@ func (NoopStateDB) GetCode(common.Address) []byte func (NoopStateDB) SetCode(common.Address, []byte) {} func (NoopStateDB) GetCodeSize(common.Address) int { return 0 } 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) SetState(common.Address, common.Hash, common.Hash) {} -- cgit v1.2.3 From caa2c23a38141911a570ba098a940b4fdbf0aa88 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sun, 12 Aug 2018 14:47:03 +0200 Subject: 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(-) (limited to 'core') diff --git a/core/state/state_object.go b/core/state/state_object.go index 0b72d0114..b05afec93 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 d9300012d..515ff57bf 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 aee6d6f6d..77250978d 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 a5a3ff3e3..2e2e3e925 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 deedf70cd..8a997adc4 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 c7ed2e451..19539d978 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 } -- cgit v1.2.3 From 5d921fa3a0cea9d87e7fd391c0ddd3115d00d0c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 18 Sep 2018 16:24:35 +0300 Subject: core, params: polish net gas metering PR a bit --- core/state/state_object.go | 63 ++++++++++++------------ core/state/state_test.go | 58 +++++++++++++--------- core/state/statedb.go | 23 ++++----- core/state/statedb_test.go | 8 ++-- core/vm/gas_table.go | 117 +++++++++++++++++++++------------------------ core/vm/interface.go | 2 +- core/vm/jump_table.go | 8 ---- core/vm/logger_test.go | 5 -- core/vm/noop.go | 72 ---------------------------- 9 files changed, 138 insertions(+), 218 deletions(-) delete mode 100644 core/vm/noop.go (limited to 'core') diff --git a/core/state/state_object.go b/core/state/state_object.go index b05afec93..f41ab0409 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -77,9 +77,9 @@ 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 - originalValue Storage // Map of original storage values, at the beginning of current call context + // Cache flags. // When an object is marked suicided it will be delete from the trie // during the "update" phase of the state transition. @@ -115,9 +115,8 @@ 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), - originalValue: make(Storage), } } @@ -160,13 +159,25 @@ func (c *stateObject) getTrie(db Database) Trie { return c.trie } -// GetState returns a value in account storage. +// GetState retrieves a value from the account storage trie. func (self *stateObject) GetState(db Database, key common.Hash) common.Hash { - value, exists := self.cachedStorage[key] - if exists { + // If we have a dirty value for this state entry, return it + value, dirty := self.dirtyStorage[key] + if dirty { + return value + } + // Otherwise return the entry's original value + return self.GetCommittedState(db, key) +} + +// GetCommittedState retrieves a value from the committed account storage trie. +func (self *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash { + // If we have the original value cached, return that + value, cached := self.originStorage[key] + if cached { return value } - // Load from DB in case it is missing. + // Otherwise load the value from the database enc, err := self.getTrie(db).TryGet(key[:]) if err != nil { self.setError(err) @@ -179,37 +190,27 @@ func (self *stateObject) GetState(db Database, key common.Hash) common.Hash { } value.SetBytes(content) } - self.cachedStorage[key] = value + self.originStorage[key] = value 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) { + // If the new value is the same as old, don't set prev := self.GetState(db, key) + if prev == value { + return + } + // New value is different, update and journal the change self.db.journal.append(storageChange{ account: &self.address, key: key, prevalue: prev, }) - if _, isSet := self.originalValue[key]; !isSet { - // original value has not been set, so set it now - self.originalValue[key] = prev - } self.setState(key, value) } func (self *stateObject) setState(key, value common.Hash) { - self.cachedStorage[key] = value self.dirtyStorage[key] = value } @@ -218,6 +219,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 @@ -226,10 +234,6 @@ func (self *stateObject) updateTrie(db Database) Trie { v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00")) self.setError(tr.TryUpdate(key[:], v)) } - // Clean the map containing 'original' value of storage entries - for k, _ := range self.originalValue { - delete(self.originalValue, k) - } return tr } @@ -299,8 +303,7 @@ func (self *stateObject) deepCopy(db *StateDB) *stateObject { } stateObject.code = self.code stateObject.dirtyStorage = self.dirtyStorage.Copy() - stateObject.cachedStorage = self.dirtyStorage.Copy() - stateObject.originalValue = self.originalValue.Copy() + stateObject.originStorage = self.originStorage.Copy() stateObject.suicided = self.suicided stateObject.dirtyCode = self.dirtyCode stateObject.deleted = self.deleted diff --git a/core/state/state_test.go b/core/state/state_test.go index 123559ea9..a09273f3b 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -96,11 +96,15 @@ 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{}) - if value != (common.Hash{}) { - c.Errorf("expected empty hash. got %x", value) + + if value := s.state.GetState(address, common.Hash{}); value != (common.Hash{}) { + c.Errorf("expected empty current value, got %x", value) + } + if value := s.state.GetCommittedState(address, common.Hash{}); value != (common.Hash{}) { + c.Errorf("expected empty committed value, got %x", value) } } @@ -110,20 +114,24 @@ func (s *StateSuite) TestSnapshot(c *checker.C) { data1 := common.BytesToHash([]byte{42}) data2 := common.BytesToHash([]byte{43}) + // snapshot the genesis state + genesis := s.state.Snapshot() + // set initial state object value 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) + c.Assert(s.state.GetState(stateobjaddr, storageaddr), checker.DeepEquals, data1) + c.Assert(s.state.GetCommittedState(stateobjaddr, storageaddr), checker.DeepEquals, common.Hash{}) - c.Assert(data1, checker.DeepEquals, res) + // revert up to the genesis state and ensure correct content + s.state.RevertToSnapshot(genesis) + c.Assert(s.state.GetState(stateobjaddr, storageaddr), checker.DeepEquals, common.Hash{}) + c.Assert(s.state.GetCommittedState(stateobjaddr, storageaddr), checker.DeepEquals, common.Hash{}) } func (s *StateSuite) TestSnapshotEmpty(c *checker.C) { @@ -208,24 +216,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 so0.suicided != so1.suicided { - t.Fatalf("suicided mismatch: have %v, want %v", so0.suicided, so1.suicided) + 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) + } } - if so0.deleted != so1.deleted { - t.Fatalf("Deleted mismatch: have %v, want %v", so0.deleted, so1.deleted) + for k, v := range so0.originStorage { + if so1.originStorage[k] != v { + t.Errorf("Origin storage key %x mismatch: have %v, want none.", k, v) + } } } diff --git a/core/state/statedb.go b/core/state/statedb.go index 515ff57bf..216667ce9 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -247,18 +247,20 @@ 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 { +// GetState retrieves a value from the given account's storage trie. +func (self *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { stateObject := self.getStateObject(addr) if stateObject != nil { - return stateObject.GetState(self.db, bhash) + return stateObject.GetState(self.db, hash) } return common.Hash{} } -func (self *StateDB) GetStateOriginal(addr common.Address, bhash common.Hash) common.Hash { +// GetCommittedState retrieves a value from the given account's committed storage trie. +func (self *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash { stateObject := self.getStateObject(addr) if stateObject != nil { - return stateObject.GetOriginalStateValue(self.db, bhash) + return stateObject.GetCommittedState(self.db, hash) } return common.Hash{} } @@ -454,19 +456,14 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common 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) + continue } + cb(key, common.BytesToHash(it.Value)) } } diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index e2b349de8..cbd5bc75e 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -381,11 +381,11 @@ 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) bool { + return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) }) - 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) bool { + return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) }) } if err != nil { diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 77250978d..10b4f719a 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -116,79 +116,70 @@ 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)) - ) - // 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 - return params.SstoreSetGas, nil - } else if val != (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) - return params.SstoreResetGas, nil - } -} - -// 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)) ) - //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 - // 2.1 If original value equals current value (this storage slot has not been changed by the current execution context) - // 2.1.1 If original value is 0, 20000 gas is deducted. - // 2.1.2 Otherwise, 5000 gas is deducted. If new value is 0, add 15000 gas to refund counter. - // 2.2 If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses. - // 2.2.1 If original value is not 0 - // 2.2.1.1 If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0. - // 2.2.1.2 If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter. - // 2.2.2 If original value equals new value (this storage slot is reset) - // 2.2.2.1 If original value is 0, add 19800 gas to refund counter. - // 2.2.2.2 Otherwise, add 4800 gas to refund counter. - new := common.BigToHash(y) - if current == new { - // 1. current == new - return 200, nil - } - original := evm.StateDB.GetStateOriginal(contract.Address(), common.BigToHash(x)) - // 2 - if original == current { // 2.1 - if original == (common.Hash{}) { // 2.1.1 - return 20000, nil + // 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) + switch { + case current == (common.Hash{}) && y.Sign() != 0: // 0 => non 0 + return params.SstoreSetGas, nil + case current != (common.Hash{}) && y.Sign() == 0: // non 0 => 0 + evm.StateDB.AddRefund(params.SstoreRefundGas) + return params.SstoreClearGas, nil + default: // non 0 => non 0 (or 0 => 0) + return params.SstoreResetGas, nil + } + } + // The new gas metering is based on net gas costs (EIP-1283): + // + // 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 + // 2.1. If original value equals current value (this storage slot has not been changed by the current execution context) + // 2.1.1. If original value is 0, 20000 gas is deducted. + // 2.1.2. Otherwise, 5000 gas is deducted. If new value is 0, add 15000 gas to refund counter. + // 2.2. If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses. + // 2.2.1. If original value is not 0 + // 2.2.1.1. If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0. + // 2.2.1.2. If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter. + // 2.2.2. If original value equals new value (this storage slot is reset) + // 2.2.2.1. If original value is 0, add 19800 gas to refund counter. + // 2.2.2.2. Otherwise, add 4800 gas to refund counter. + value := common.BigToHash(y) + if current == value { // noop (1) + return params.NetSstoreNoopGas, nil + } + original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x)) + if original == current { + if original == (common.Hash{}) { // create slot (2.1.1) + return params.NetSstoreInitGas, nil } - // 2.1.2 - if new == (common.Hash{}) { - evm.StateDB.AddRefund(15000) + if value == (common.Hash{}) { // delete slot (2.1.2b) + evm.StateDB.AddRefund(params.NetSstoreClearRefund) } - return 5000, nil - } - // 2.2 - if original != (common.Hash{}) { // 2.2.1 - if current == (common.Hash{}) { // 2.2.1.1 - evm.StateDB.SubRefund(15000) - } else { - // 2.2.1.2 - evm.StateDB.AddRefund(15000) + return params.NetSstoreCleanGas, nil // write existing slot (2.1.2) + } + if original != (common.Hash{}) { + if current == (common.Hash{}) { // recreate slot (2.2.1.1) + evm.StateDB.SubRefund(params.NetSstoreClearRefund) + } else if value == (common.Hash{}) { // delete slot (2.2.1.2) + evm.StateDB.AddRefund(params.NetSstoreClearRefund) } } - if original == new { // 2.2.2 - if original == (common.Hash{}) { - evm.StateDB.AddRefund(19800) - } else { - evm.StateDB.AddRefund(4800) + if original == value { + if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1) + evm.StateDB.AddRefund(params.NetSstoreResetClearRefund) + } else { // reset to original existing slot (2.2.2.2) + evm.StateDB.AddRefund(params.NetSstoreResetRefund) } } - return 200, nil + return params.NetSstoreDirtyGas, nil } func makeGasLog(n uint64) gasFunc { diff --git a/core/vm/interface.go b/core/vm/interface.go index 2e2e3e925..fc15082f1 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -43,8 +43,8 @@ type StateDB interface { SubRefund(uint64) GetRefund() uint64 + GetCommittedState(common.Address, common.Hash) common.Hash 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 8a997adc4..deedf70cd 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -95,14 +95,6 @@ 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/logger_test.go b/core/vm/logger_test.go index 28830c445..cdbb70dc4 100644 --- a/core/vm/logger_test.go +++ b/core/vm/logger_test.go @@ -41,11 +41,6 @@ func (d *dummyContractRef) SetBalance(*big.Int) {} func (d *dummyContractRef) SetNonce(uint64) {} func (d *dummyContractRef) Balance() *big.Int { return new(big.Int) } -type dummyStateDB struct { - NoopStateDB - ref *dummyContractRef -} - func TestStoreCapture(t *testing.T) { var ( env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) diff --git a/core/vm/noop.go b/core/vm/noop.go deleted file mode 100644 index 19539d978..000000000 --- a/core/vm/noop.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package vm - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" -) - -func NoopCanTransfer(db StateDB, from common.Address, balance *big.Int) bool { - return true -} -func NoopTransfer(db StateDB, from, to common.Address, amount *big.Int) {} - -type NoopEVMCallContext struct{} - -func (NoopEVMCallContext) Call(caller ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) { - return nil, nil -} -func (NoopEVMCallContext) CallCode(caller ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) { - return nil, nil -} -func (NoopEVMCallContext) Create(caller ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error) { - return nil, common.Address{}, nil -} -func (NoopEVMCallContext) DelegateCall(me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error) { - return nil, nil -} - -type NoopStateDB struct{} - -func (NoopStateDB) CreateAccount(common.Address) {} -func (NoopStateDB) SubBalance(common.Address, *big.Int) {} -func (NoopStateDB) AddBalance(common.Address, *big.Int) {} -func (NoopStateDB) GetBalance(common.Address) *big.Int { return nil } -func (NoopStateDB) GetNonce(common.Address) uint64 { return 0 } -func (NoopStateDB) SetNonce(common.Address, uint64) {} -func (NoopStateDB) GetCodeHash(common.Address) common.Hash { return common.Hash{} } -func (NoopStateDB) GetCode(common.Address) []byte { return nil } -func (NoopStateDB) SetCode(common.Address, []byte) {} -func (NoopStateDB) GetCodeSize(common.Address) int { return 0 } -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 } -func (NoopStateDB) Exist(common.Address) bool { return false } -func (NoopStateDB) Empty(common.Address) bool { return false } -func (NoopStateDB) RevertToSnapshot(int) {} -func (NoopStateDB) Snapshot() int { return 0 } -func (NoopStateDB) AddLog(*types.Log) {} -func (NoopStateDB) AddPreimage(common.Hash, []byte) {} -func (NoopStateDB) ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) {} -- cgit v1.2.3 From faa69bea1cade1d0f8b00814fc0616c5a57f0709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 19 Sep 2018 11:47:09 +0300 Subject: core, eth: fix goimports for Go 1.11 --- core/genesis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core') diff --git a/core/genesis.go b/core/genesis.go index 9190e2ba2..6e71afd61 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -355,7 +355,7 @@ func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis { common.BytesToAddress([]byte{6}): {Balance: big.NewInt(1)}, // ECAdd common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing - faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))}, + faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))}, }, } } -- cgit v1.2.3 From da29332c5f4c368ff03ec4e7132eefac48fed1ae Mon Sep 17 00:00:00 2001 From: Guillaume Ballet Date: Thu, 20 Sep 2018 09:44:35 +0200 Subject: core/vm: add switches to select evm+ewasm interpreters (#17687) Interpreter initialization is left to the PRs implementing them. Options for external interpreters are passed after a colon in the `--vm.ewasm` and `--vm.evm` switches. --- core/vm/evm.go | 22 ++++++++++++++++++++-- core/vm/interpreter.go | 5 +++++ 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'core') diff --git a/core/vm/evm.go b/core/vm/evm.go index 58618f811..fc040c621 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -136,10 +136,28 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon vmConfig: vmConfig, chainConfig: chainConfig, chainRules: chainConfig.Rules(ctx.BlockNumber), - interpreters: make([]Interpreter, 1), + interpreters: make([]Interpreter, 0, 1), } - evm.interpreters[0] = NewEVMInterpreter(evm, vmConfig) + if chainConfig.IsEWASM(ctx.BlockNumber) { + // to be implemented by EVM-C and Wagon PRs. + // if vmConfig.EWASMInterpreter != "" { + // extIntOpts := strings.Split(vmConfig.EWASMInterpreter, ":") + // path := extIntOpts[0] + // options := []string{} + // if len(extIntOpts) > 1 { + // options = extIntOpts[1..] + // } + // evm.interpreters = append(evm.interpreters, NewEVMVCInterpreter(evm, vmConfig, options)) + // } else { + // evm.interpreters = append(evm.interpreters, NewEWASMInterpreter(evm, vmConfig)) + // } + panic("No supported ewasm interpreter yet.") + } + + // vmConfig.EVMInterpreter will be used by EVM-C, it won't be checked here + // as we always want to have the built-in EVM as the failover option. + evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, vmConfig)) evm.interpreter = evm.interpreters[0] return evm diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 0f1b07342..8e934f60e 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -39,6 +39,11 @@ type Config struct { // may be left uninitialised and will be set to the default // table. JumpTable [256]operation + + // Type of the EWASM interpreter + EWASMInterpreter string + // Type of the EVM interpreter + EVMInterpreter string } // Interpreter is used to run Ethereum based contracts and will utilise the -- cgit v1.2.3 From 0f2ba07c4122fbc2d836a2f374e5da8d8546e99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 20 Sep 2018 11:41:59 +0300 Subject: common, core, light: add block age into info logs --- core/blockchain.go | 28 ++++++++++++++++++---------- core/headerchain.go | 14 ++++++++++++-- 2 files changed, 30 insertions(+), 12 deletions(-) (limited to 'core') diff --git a/core/blockchain.go b/core/blockchain.go index 63f60ca28..7a3b09705 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -251,9 +251,9 @@ func (bc *BlockChain) loadLastState() error { blockTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) fastTd := bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64()) - log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd) - log.Info("Loaded most recent local full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "td", blockTd) - log.Info("Loaded most recent local fast block", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash(), "td", fastTd) + log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(currentHeader.Time.Int64(), 0))) + log.Info("Loaded most recent local full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(currentBlock.Time().Int64(), 0))) + log.Info("Loaded most recent local fast block", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash(), "td", fastTd, "age", common.PrettyAge(time.Unix(currentFastBlock.Time().Int64(), 0))) return nil } @@ -850,13 +850,16 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ } bc.mu.Unlock() - log.Info("Imported new block receipts", - "count", stats.processed, - "elapsed", common.PrettyDuration(time.Since(start)), - "number", head.Number(), - "hash", head.Hash(), + context := []interface{}{ + "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)), + "number", head.Number(), "hash", head.Hash(), "age", common.PrettyAge(time.Unix(head.Time().Int64(), 0)), "size", common.StorageSize(bytes), - "ignored", stats.ignored) + } + if stats.ignored > 0 { + context = append(context, []interface{}{"ignored", stats.ignored}...) + } + log.Info("Imported new block receipts", context...) + return 0, nil } @@ -1229,8 +1232,13 @@ func (st *insertStats) report(chain []*types.Block, index int, cache common.Stor context := []interface{}{ "blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000, "elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed), - "number", end.Number(), "hash", end.Hash(), "cache", cache, + "number", end.Number(), "hash", end.Hash(), } + if timestamp := time.Unix(end.Time().Int64(), 0); time.Since(timestamp) > time.Minute { + context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...) + } + context = append(context, []interface{}{"cache", cache}...) + if st.queued > 0 { context = append(context, []interface{}{"queued", st.queued}...) } diff --git a/core/headerchain.go b/core/headerchain.go index 2bbec28bf..d2093113c 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -281,8 +281,18 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, writeHeader WhCa } // Report some public statistics so the user has a clue what's going on last := chain[len(chain)-1] - log.Info("Imported new block headers", "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)), - "number", last.Number, "hash", last.Hash(), "ignored", stats.ignored) + + context := []interface{}{ + "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)), + "number", last.Number, "hash", last.Hash(), + } + if timestamp := time.Unix(last.Time.Int64(), 0); time.Since(timestamp) > time.Minute { + context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...) + } + if stats.ignored > 0 { + context = append(context, []interface{}{"ignored", stats.ignored}...) + } + log.Info("Imported new block headers", context...) return 0, nil } -- cgit v1.2.3 From d6254f827bf493c1471a806b7b8a0e9b86c8c420 Mon Sep 17 00:00:00 2001 From: gary rong Date: Thu, 20 Sep 2018 20:09:30 +0800 Subject: all: protect self-mined block during reorg (#17656) --- core/bench_test.go | 4 ++-- core/block_validator_test.go | 8 ++++---- core/blockchain.go | 48 ++++++++++++++++++++++++++++++++++++++++---- core/blockchain_test.go | 32 ++++++++++++++--------------- core/chain_makers.go | 2 +- core/chain_makers_test.go | 2 +- core/dao_test.go | 12 +++++------ core/genesis_test.go | 2 +- 8 files changed, 75 insertions(+), 35 deletions(-) (limited to 'core') diff --git a/core/bench_test.go b/core/bench_test.go index 8d95456e9..53cba0517 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -175,7 +175,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { // Time the insertion of the new chain. // State and blocks are stored in the same DB. - chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer chainman.Stop() b.ReportAllocs() b.ResetTimer() @@ -287,7 +287,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { if err != nil { b.Fatalf("error opening database at %v: %v", dir, err) } - chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}) + chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil) if err != nil { b.Fatalf("error creating chain: %v", err) } diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 2a171218e..9319a7835 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -42,7 +42,7 @@ func TestHeaderVerification(t *testing.T) { headers[i] = block.Header() } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil) defer chain.Stop() for i := 0; i < len(blocks); i++ { @@ -106,11 +106,11 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) { var results <-chan error if valid { - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } else { - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } @@ -173,7 +173,7 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) { defer runtime.GOMAXPROCS(old) // Start the verifications and immediately abort - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil) defer chain.Stop() abort, results := chain.engine.VerifyHeaders(chain, headers, seals) diff --git a/core/blockchain.go b/core/blockchain.go index 7a3b09705..2f12ca62b 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -128,13 +129,14 @@ type BlockChain struct { validator Validator // block and state validator interface vmConfig vm.Config - badBlocks *lru.Cache // Bad block cache + badBlocks *lru.Cache // Bad block cache + isLocalFn func(common.Address) bool // Function used to determine whether the block author is a local miner account. } // NewBlockChain returns a fully initialised block chain using information // available in the database. It initialises the default Ethereum Validator and // Processor. -func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config) (*BlockChain, error) { +func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, isLocalFn func(common.Address) bool) (*BlockChain, error) { if cacheConfig == nil { cacheConfig = &CacheConfig{ TrieNodeLimit: 256 * 1024 * 1024, @@ -154,6 +156,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par triegc: prque.New(nil), stateCache: state.NewDatabase(db), quit: make(chan struct{}), + isLocalFn: isLocalFn, bodyCache: bodyCache, bodyRLPCache: bodyRLPCache, blockCache: blockCache, @@ -967,8 +970,45 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. reorg := externTd.Cmp(localTd) > 0 currentBlock = bc.CurrentBlock() if !reorg && externTd.Cmp(localTd) == 0 { - // Split same-difficulty blocks by number, then at random - reorg = block.NumberU64() < currentBlock.NumberU64() || (block.NumberU64() == currentBlock.NumberU64() && mrand.Float64() < 0.5) + // Split same-difficulty blocks by number, then preferentially select + // the block generated by the local miner as the canonical block. + if block.NumberU64() < currentBlock.NumberU64() { + reorg = true + } else if block.NumberU64() == currentBlock.NumberU64() { + if _, ok := bc.engine.(*clique.Clique); ok { + // The reason we need to disable the self-reorg preserving for clique + // is it can be probable to introduce a deadlock. + // + // e.g. If there are 7 available signers + // + // r1 A + // r2 B + // r3 C + // r4 D + // r5 A [X] F G + // r6 [X] + // + // In the round5, the inturn signer E is offline, so the worst case + // is A, F and G sign the block of round5 and reject the block of opponents + // and in the round6, the last available signer B is offline, the whole + // network is stuck. + reorg = mrand.Float64() < 0.5 + } else { + currentAuthor, err := bc.engine.Author(currentBlock.Header()) + if err != nil { + return NonStatTy, err + } + blockAuthor, err := bc.engine.Author(block.Header()) + if err != nil { + return NonStatTy, err + } + var currentLocal, blockLocal bool + if bc.isLocalFn != nil { + currentLocal, blockLocal = bc.isLocalFn(currentAuthor), bc.isLocalFn(blockAuthor) + } + reorg = !currentLocal && (blockLocal || mrand.Float64() < 0.5) + } + } } if reorg { // Reorganise the chain if the parent is not the head block diff --git a/core/blockchain_test.go b/core/blockchain_test.go index e452d6936..aef810050 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -52,7 +52,7 @@ func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *B ) // Initialize a fresh chain with only a genesis block - blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil) // Create and inject the requested chain if n == 0 { return db, blockchain, nil @@ -523,7 +523,7 @@ func testReorgBadHashes(t *testing.T, full bool) { blockchain.Stop() // Create a new BlockChain and check that it rolled back the state. - ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}) + ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } @@ -635,7 +635,7 @@ func TestFastVsFullChains(t *testing.T) { // Import the chain as an archive node for the comparison baseline archiveDb := ethdb.NewMemDatabase() gspec.MustCommit(archiveDb) - archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer archive.Stop() if n, err := archive.InsertChain(blocks); err != nil { @@ -644,7 +644,7 @@ func TestFastVsFullChains(t *testing.T) { // Fast import the chain as a non-archive node to test fastDb := ethdb.NewMemDatabase() gspec.MustCommit(fastDb) - fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -722,7 +722,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { archiveDb := ethdb.NewMemDatabase() gspec.MustCommit(archiveDb) - archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) } @@ -735,7 +735,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a non-archive node and ensure all pointers are updated fastDb := ethdb.NewMemDatabase() gspec.MustCommit(fastDb) - fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -756,7 +756,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { lightDb := ethdb.NewMemDatabase() gspec.MustCommit(lightDb) - light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) if n, err := light.InsertHeaderChain(headers, 1); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } @@ -825,7 +825,7 @@ func TestChainTxReorgs(t *testing.T) { } }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } @@ -896,7 +896,7 @@ func TestLogReorgs(t *testing.T) { signer = types.NewEIP155Signer(gspec.Config.ChainID) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() rmLogsCh := make(chan RemovedLogsEvent) @@ -943,7 +943,7 @@ func TestReorgSideEvent(t *testing.T) { signer = types.NewEIP155Signer(gspec.Config.ChainID) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {}) @@ -1072,7 +1072,7 @@ func TestEIP155Transition(t *testing.T) { genesis = gspec.MustCommit(db) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) { @@ -1179,7 +1179,7 @@ func TestEIP161AccountRemoval(t *testing.T) { } genesis = gspec.MustCommit(db) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) { @@ -1254,7 +1254,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { diskdb := ethdb.NewMemDatabase() new(Genesis).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1298,7 +1298,7 @@ func TestTrieForkGC(t *testing.T) { diskdb := ethdb.NewMemDatabase() new(Genesis).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1337,7 +1337,7 @@ func TestLargeReorgTrieGC(t *testing.T) { diskdb := ethdb.NewMemDatabase() new(Genesis).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1419,7 +1419,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in diskdb := ethdb.NewMemDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) if err != nil { b.Fatalf("failed to create tester chain: %v", err) } diff --git a/core/chain_makers.go b/core/chain_makers.go index 351673477..0bc453fdf 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -177,7 +177,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) { // TODO(karalabe): This is needed for clique, which depends on multiple blocks. // It's nonetheless ugly to spin up a blockchain here. Get rid of this somehow. - blockchain, _ := NewBlockChain(db, nil, config, engine, vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, config, engine, vm.Config{}, nil) defer blockchain.Stop() b := &BlockGen{i: i, parent: parent, chain: blocks, chainReader: blockchain, statedb: statedb, config: config, engine: engine} diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 5015d1f48..64b64fd6a 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -79,7 +79,7 @@ func ExampleGenerateChain() { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() if i, err := blockchain.InsertChain(chain); err != nil { diff --git a/core/dao_test.go b/core/dao_test.go index 284b1d98b..966139bce 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -45,7 +45,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { proConf.DAOForkBlock = forkBlock proConf.DAOForkSupport = true - proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}) + proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil) defer proBc.Stop() conDb := ethdb.NewMemDatabase() @@ -55,7 +55,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { conConf.DAOForkBlock = forkBlock conConf.DAOForkSupport = false - conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}) + conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil) defer conBc.Stop() if _, err := proBc.InsertChain(prefix); err != nil { @@ -69,7 +69,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Create a pro-fork block, and try to feed into the no-fork chain db = ethdb.NewMemDatabase() gspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}) + bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) @@ -94,7 +94,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Create a no-fork block, and try to feed into the pro-fork chain db = ethdb.NewMemDatabase() gspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}) + bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) @@ -120,7 +120,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Verify that contra-forkers accept pro-fork extra-datas after forking finishes db = ethdb.NewMemDatabase() gspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}) + bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) @@ -140,7 +140,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Verify that pro-forkers accept contra-fork extra-datas after forking finishes db = ethdb.NewMemDatabase() gspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}) + bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) diff --git a/core/genesis_test.go b/core/genesis_test.go index 2d7f94f8f..c7d54f205 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -120,7 +120,7 @@ func TestSetupGenesis(t *testing.T) { // Advance to block #4, past the homestead transition block of customg. genesis := oldcustomg.MustCommit(db) - bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}) + bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil) defer bc.Stop() blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil) -- cgit v1.2.3 From ba0a8b7887cbaea861dca3f1408e59b88c174815 Mon Sep 17 00:00:00 2001 From: gary rong Date: Fri, 21 Sep 2018 01:02:15 +0800 Subject: core, eth: fix dependency cycle (#17720) --- core/blockchain.go | 71 ++++++++++++++++-------------------------------------- 1 file changed, 21 insertions(+), 50 deletions(-) (limited to 'core') diff --git a/core/blockchain.go b/core/blockchain.go index 2f12ca62b..fe961e0c4 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -129,14 +128,14 @@ type BlockChain struct { validator Validator // block and state validator interface vmConfig vm.Config - badBlocks *lru.Cache // Bad block cache - isLocalFn func(common.Address) bool // Function used to determine whether the block author is a local miner account. + badBlocks *lru.Cache // Bad block cache + shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block. } // NewBlockChain returns a fully initialised block chain using information // available in the database. It initialises the default Ethereum Validator and // Processor. -func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, isLocalFn func(common.Address) bool) (*BlockChain, error) { +func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(block *types.Block) bool) (*BlockChain, error) { if cacheConfig == nil { cacheConfig = &CacheConfig{ TrieNodeLimit: 256 * 1024 * 1024, @@ -150,20 +149,20 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par badBlocks, _ := lru.New(badBlockLimit) bc := &BlockChain{ - chainConfig: chainConfig, - cacheConfig: cacheConfig, - db: db, - triegc: prque.New(nil), - stateCache: state.NewDatabase(db), - quit: make(chan struct{}), - isLocalFn: isLocalFn, - bodyCache: bodyCache, - bodyRLPCache: bodyRLPCache, - blockCache: blockCache, - futureBlocks: futureBlocks, - engine: engine, - vmConfig: vmConfig, - badBlocks: badBlocks, + chainConfig: chainConfig, + cacheConfig: cacheConfig, + db: db, + triegc: prque.New(nil), + stateCache: state.NewDatabase(db), + quit: make(chan struct{}), + shouldPreserve: shouldPreserve, + bodyCache: bodyCache, + bodyRLPCache: bodyRLPCache, + blockCache: blockCache, + futureBlocks: futureBlocks, + engine: engine, + vmConfig: vmConfig, + badBlocks: badBlocks, } bc.SetValidator(NewBlockValidator(chainConfig, bc, engine)) bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine)) @@ -975,39 +974,11 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. if block.NumberU64() < currentBlock.NumberU64() { reorg = true } else if block.NumberU64() == currentBlock.NumberU64() { - if _, ok := bc.engine.(*clique.Clique); ok { - // The reason we need to disable the self-reorg preserving for clique - // is it can be probable to introduce a deadlock. - // - // e.g. If there are 7 available signers - // - // r1 A - // r2 B - // r3 C - // r4 D - // r5 A [X] F G - // r6 [X] - // - // In the round5, the inturn signer E is offline, so the worst case - // is A, F and G sign the block of round5 and reject the block of opponents - // and in the round6, the last available signer B is offline, the whole - // network is stuck. - reorg = mrand.Float64() < 0.5 - } else { - currentAuthor, err := bc.engine.Author(currentBlock.Header()) - if err != nil { - return NonStatTy, err - } - blockAuthor, err := bc.engine.Author(block.Header()) - if err != nil { - return NonStatTy, err - } - var currentLocal, blockLocal bool - if bc.isLocalFn != nil { - currentLocal, blockLocal = bc.isLocalFn(currentAuthor), bc.isLocalFn(blockAuthor) - } - reorg = !currentLocal && (blockLocal || mrand.Float64() < 0.5) + var currentPreserve, blockPreserve bool + if bc.shouldPreserve != nil { + currentPreserve, blockPreserve = bc.shouldPreserve(currentBlock), bc.shouldPreserve(block) } + reorg = !currentPreserve && (blockPreserve || mrand.Float64() < 0.5) } } if reorg { -- cgit v1.2.3 From 81080bf8cb7f60f59a68cf48998a29a1a2e10cb9 Mon Sep 17 00:00:00 2001 From: Wuxiang Date: Fri, 21 Sep 2018 18:45:42 +0800 Subject: core: fix a typo (#17733) --- core/tx_pool.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'core') diff --git a/core/tx_pool.go b/core/tx_pool.go index a0a6ff851..f6da5da2a 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -525,7 +525,7 @@ func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common return pending, queued } -// Pending retrieves all currently processable transactions, groupped by origin +// Pending retrieves all currently processable transactions, grouped by origin // account and sorted by nonce. The returned transaction set is a copy and can be // freely modified by calling code. func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) { @@ -547,7 +547,7 @@ func (pool *TxPool) Locals() []common.Address { return pool.locals.flatten() } -// local retrieves all currently known local transactions, groupped by origin +// local retrieves all currently known local transactions, grouped by origin // account and sorted by nonce. The returned transaction set is a copy and can be // freely modified by calling code. func (pool *TxPool) local() map[common.Address]types.Transactions { -- cgit v1.2.3 From 6663e5da10e7198f7ff5e883fd857240e59d476c Mon Sep 17 00:00:00 2001 From: Liang ZOU Date: Tue, 25 Sep 2018 18:26:35 +0800 Subject: all: fix various comment typos (#17748) --- core/vm/instructions.go | 2 +- core/vm/memory.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'core') diff --git a/core/vm/instructions.go b/core/vm/instructions.go index ca9e775ac..4d1bd4a34 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -727,7 +727,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo } func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // Pop gas. The actual gas in in interpreter.evm.callGasTemp. + // Pop gas. The actual gas in interpreter.evm.callGasTemp. interpreter.intPool.put(stack.pop()) gas := interpreter.evm.callGasTemp // Pop other call parameters. diff --git a/core/vm/memory.go b/core/vm/memory.go index 722862b1d..7e6f0eb94 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -29,7 +29,7 @@ type Memory struct { lastGasCost uint64 } -// NewMemory returns a new memory memory model. +// NewMemory returns a new memory model. func NewMemory() *Memory { return &Memory{} } -- cgit v1.2.3