update statedb

add transient storage
This commit is contained in:
Roy Crihfield 2023-04-10 14:57:43 +08:00
parent 7575a88b03
commit 49f3d43e46
3 changed files with 133 additions and 20 deletions

View File

@ -122,6 +122,12 @@ type (
address *common.Address address *common.Address
slot *common.Hash slot *common.Hash
} }
// Changes to the transient storage
transientStorageChange struct {
account *common.Address
key, prevalue common.Hash
}
) )
func (ch createObjectChange) revert(s *StateDB) { func (ch createObjectChange) revert(s *StateDB) {
@ -194,6 +200,14 @@ func (ch storageChange) dirtied() *common.Address {
return ch.account return ch.account
} }
func (ch transientStorageChange) revert(s *StateDB) {
s.setTransientState(*ch.account, ch.key, ch.prevalue)
}
func (ch transientStorageChange) dirtied() *common.Address {
return nil
}
func (ch refundChange) revert(s *StateDB) { func (ch refundChange) revert(s *StateDB) {
s.refund = ch.prev s.refund = ch.prev
} }

View File

@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params"
) )
/* /*
@ -77,6 +78,9 @@ type StateDB struct {
// Per-transaction access list // Per-transaction access list
accessList *accessList accessList *accessList
// Transient storage
transientStorage transientStorage
// Journal of state modifications. This is the backbone of // Journal of state modifications. This is the backbone of
// Snapshot and RevertToSnapshot. // Snapshot and RevertToSnapshot.
journal *journal journal *journal
@ -100,6 +104,7 @@ func New(blockHash common.Hash, db StateDatabase) (*StateDB, error) {
preimages: make(map[common.Hash][]byte), preimages: make(map[common.Hash][]byte),
journal: newJournal(), journal: newJournal(),
accessList: newAccessList(), accessList: newAccessList(),
transientStorage: newTransientStorage(),
hasher: crypto.NewKeccakState(), hasher: crypto.NewKeccakState(),
} }
return sdb, nil return sdb, nil
@ -307,6 +312,33 @@ func (s *StateDB) Suicide(addr common.Address) bool {
return true return true
} }
// SetTransientState sets transient storage for a given account. It
// adds the change to the journal so that it can be rolled back
// to its previous value if there is a revert.
func (s *StateDB) SetTransientState(addr common.Address, key, value common.Hash) {
prev := s.GetTransientState(addr, key)
if prev == value {
return
}
s.journal.append(transientStorageChange{
account: &addr,
key: key,
prevalue: prev,
})
s.setTransientState(addr, key, value)
}
// setTransientState is a lower level setter for transient storage. It
// is called during a revert to prevent modifications to the journal.
func (s *StateDB) setTransientState(addr common.Address, key, value common.Hash) {
s.transientStorage.Set(addr, key, value)
}
// GetTransientState gets transient storage for a given account.
func (s *StateDB) GetTransientState(addr common.Address, key common.Hash) common.Hash {
return s.transientStorage.Get(addr, key)
}
// //
// Setting, updating & deleting state object methods. // Setting, updating & deleting state object methods.
// //
@ -389,8 +421,8 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject)
// CreateAccount is called during the EVM CREATE operation. The situation might arise that // CreateAccount is called during the EVM CREATE operation. The situation might arise that
// a contract does the following: // a contract does the following:
// //
// 1. sends funds to sha(account ++ (nonce + 1)) // 1. sends funds to sha(account ++ (nonce + 1))
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1) // 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
// //
// Carrying over the balance ensures that Ether doesn't disappear. // Carrying over the balance ensures that Ether doesn't disappear.
func (s *StateDB) CreateAccount(addr common.Address) { func (s *StateDB) CreateAccount(addr common.Address) {
@ -437,33 +469,45 @@ func (s *StateDB) GetRefund() uint64 {
return s.refund return s.refund
} }
// PrepareAccessList handles the preparatory steps for executing a state transition with // Prepare handles the preparatory steps for executing a state transition with.
// regards to both EIP-2929 and EIP-2930: // This method must be invoked before state transition.
// //
// Berlin fork:
// - Add sender to access list (2929) // - Add sender to access list (2929)
// - Add destination to access list (2929) // - Add destination to access list (2929)
// - Add precompiles to access list (2929) // - Add precompiles to access list (2929)
// - Add the contents of the optional tx access list (2930) // - Add the contents of the optional tx access list (2930)
// //
// This method should only be called if Berlin/2929+2930 is applicable at the current number. // Potential EIPs:
func (s *StateDB) PrepareAccessList(sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) { // - Reset access list (Berlin)
// Clear out any leftover from previous executions // - Add coinbase to access list (EIP-3651)
s.accessList = newAccessList() // - Reset transient storage (EIP-1153)
func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
if rules.IsBerlin {
// Clear out any leftover from previous executions
al := newAccessList()
s.accessList = al
s.AddAddressToAccessList(sender) al.AddAddress(sender)
if dst != nil { if dst != nil {
s.AddAddressToAccessList(*dst) al.AddAddress(*dst)
// If it's a create-tx, the destination will be added inside evm.create // If it's a create-tx, the destination will be added inside evm.create
} }
for _, addr := range precompiles { for _, addr := range precompiles {
s.AddAddressToAccessList(addr) al.AddAddress(addr)
} }
for _, el := range list { for _, el := range list {
s.AddAddressToAccessList(el.Address) al.AddAddress(el.Address)
for _, key := range el.StorageKeys { for _, key := range el.StorageKeys {
s.AddSlotToAccessList(el.Address, key) al.AddSlot(el.Address, key)
}
}
if rules.IsShanghai { // EIP-3651: warm coinbase
al.AddAddress(coinbase)
} }
} }
// Reset transient storage at the beginning of transaction execution
s.transientStorage = newTransientStorage()
} }
// AddAddressToAccessList adds the given address to the access list // AddAddressToAccessList adds the given address to the access list

55
transient_storage.go Normal file
View File

@ -0,0 +1,55 @@
// Copyright 2022 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 <http://www.gnu.org/licenses/>.
package ipld_eth_statedb
import (
"github.com/ethereum/go-ethereum/common"
)
// transientStorage is a representation of EIP-1153 "Transient Storage".
type transientStorage map[common.Address]Storage
// newTransientStorage creates a new instance of a transientStorage.
func newTransientStorage() transientStorage {
return make(transientStorage)
}
// Set sets the transient-storage `value` for `key` at the given `addr`.
func (t transientStorage) Set(addr common.Address, key, value common.Hash) {
if _, ok := t[addr]; !ok {
t[addr] = make(Storage)
}
t[addr][key] = value
}
// Get gets the transient storage for `key` at the given `addr`.
func (t transientStorage) Get(addr common.Address, key common.Hash) common.Hash {
val, ok := t[addr]
if !ok {
return common.Hash{}
}
return val[key]
}
// Copy does a deep copy of the transientStorage
func (t transientStorage) Copy() transientStorage {
storage := make(transientStorage)
for key, value := range t {
storage[key] = value.Copy()
}
return storage
}