Skip to content

Commit

Permalink
Implement EIP-1153 transient storage (#7405)
Browse files Browse the repository at this point in the history
Port ethereum/go-ethereum#26003

---------

Co-authored-by: Mark Tyneway <[email protected]>
  • Loading branch information
yperbasis and tynes authored May 1, 2023
1 parent d475bab commit 1533674
Show file tree
Hide file tree
Showing 29 changed files with 331 additions and 93 deletions.
4 changes: 2 additions & 2 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
}
}
gasCap = hi
b.pendingState.Prepare(libcommon.Hash{}, libcommon.Hash{}, len(b.pendingBlock.Transactions()))
b.pendingState.SetTxContext(libcommon.Hash{}, libcommon.Hash{}, len(b.pendingBlock.Transactions()))

// Create a helper to check if a gas allowance results in an executable transaction
executable := func(gas uint64) (bool, *core.ExecutionResult, error) {
Expand Down Expand Up @@ -715,7 +715,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx types.Transac
return fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.GetNonce(), nonce)
}

b.pendingState.Prepare(tx.Hash(), libcommon.Hash{}, len(b.pendingBlock.Transactions()))
b.pendingState.SetTxContext(tx.Hash(), libcommon.Hash{}, len(b.pendingBlock.Transactions()))
//fmt.Printf("==== Start producing block %d, header: %d\n", b.pendingBlock.NumberU64(), b.pendingHeader.Number.Uint64())
if _, _, err := core.ApplyTransaction(
b.m.ChainConfig, core.GetHashFn(b.pendingHeader, b.getHeader), b.m.Engine,
Expand Down
2 changes: 1 addition & 1 deletion cmd/integration/commands/state_domains.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ func (b *blockProcessor) applyBlock(
for i, tx := range block.Transactions() {
if b.txNum >= b.startTxNum {
ibs := state.New(b.reader)
ibs.Prepare(tx.Hash(), block.Hash(), i)
ibs.SetTxContext(tx.Hash(), block.Hash(), i)
ct := exec3.NewCallTracer()
b.vmConfig.Tracer = ct
receipt, _, err := core.ApplyTransaction(b.chainConfig, getHashFn, b.engine, nil, gp, ibs, b.writer, header, tx, usedGas, b.vmConfig, parentHeader.ExcessDataGas)
Expand Down
2 changes: 1 addition & 1 deletion cmd/rpcdaemon/commands/eth_callMany.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func (api *APIImpl) CallMany(ctx context.Context, bundles []Bundle, simulateCont
// and apply the message.
gp := new(core.GasPool).AddGas(math.MaxUint64)
for idx, txn := range replayTransactions {
st.Prepare(txn.Hash(), block.Hash(), idx)
st.SetTxContext(txn.Hash(), block.Hash(), idx)
msg, err := txn.AsMessage(*signer, block.BaseFee(), rules)
if err != nil {
return nil, err
Expand Down
4 changes: 2 additions & 2 deletions cmd/rpcdaemon/commands/eth_receipts.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (api *BaseAPI) getReceipts(ctx context.Context, tx kv.Tx, chainConfig *chai
header := block.Header()
excessDataGas := header.ParentExcessDataGas(getHeader)
for i, txn := range block.Transactions() {
ibs.Prepare(txn.Hash(), block.Hash(), i)
ibs.SetTxContext(txn.Hash(), block.Hash(), i)
receipt, _, err := core.ApplyTransaction(chainConfig, core.GetHashFn(header, getHeader), engine, nil, gp, ibs, noopWriter, header, txn, usedGas, vm.Config{}, excessDataGas)
if err != nil {
return nil, err
Expand Down Expand Up @@ -515,7 +515,7 @@ func (e *intraBlockExec) execTx(txNum uint64, txIndex int, txn types.Transaction
e.stateReader.SetTxNum(txNum)
txHash := txn.Hash()
e.ibs.Reset()
e.ibs.Prepare(txHash, e.blockHash, txIndex)
e.ibs.SetTxContext(txHash, e.blockHash, txIndex)
gp := new(core.GasPool).AddGas(txn.GetGas())
msg, err := txn.AsMessage(*e.signer, e.header.BaseFee, e.rules)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/rpcdaemon/commands/otterscan_generic_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (api *OtterscanAPIImpl) genericTracer(dbtx kv.Tx, ctx context.Context, bloc
excessDataGas := header.ParentExcessDataGas(getHeader)
rules := chainConfig.Rules(block.NumberU64(), header.Time)
for idx, tx := range block.Transactions() {
ibs.Prepare(tx.Hash(), block.Hash(), idx)
ibs.SetTxContext(tx.Hash(), block.Hash(), idx)

msg, _ := tx.AsMessage(*signer, header.BaseFee, rules)

Expand Down
2 changes: 1 addition & 1 deletion cmd/rpcdaemon/commands/otterscan_search_trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func (api *OtterscanAPIImpl) traceBlock(dbtx kv.Tx, ctx context.Context, blockNu
rules := chainConfig.Rules(block.NumberU64(), header.Time)
found := false
for idx, tx := range block.Transactions() {
ibs.Prepare(tx.Hash(), block.Hash(), idx)
ibs.SetTxContext(tx.Hash(), block.Hash(), idx)

msg, _ := tx.AsMessage(*signer, header.BaseFee, rules)

Expand Down
6 changes: 3 additions & 3 deletions cmd/rpcdaemon/commands/trace_adhoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,7 @@ func (api *TraceAPIImpl) Call(ctx context.Context, args TraceCallParam, traceTyp

gp := new(core.GasPool).AddGas(msg.Gas())
var execResult *core.ExecutionResult
ibs.Prepare(libcommon.Hash{}, libcommon.Hash{}, 0)
ibs.SetTxContext(libcommon.Hash{}, libcommon.Hash{}, 0)
execResult, err = core.ApplyMessage(evm, msg, gp, true /* refunds */, true /* gasBailout */)
if err != nil {
return nil, err
Expand Down Expand Up @@ -1196,9 +1196,9 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, msgs []type
cloneReader = state.NewCachedReader(stateReader, cloneCache)
}
if args.txHash != nil {
ibs.Prepare(*args.txHash, header.Hash(), txIndex)
ibs.SetTxContext(*args.txHash, header.Hash(), txIndex)
} else {
ibs.Prepare(libcommon.Hash{}, header.Hash(), txIndex)
ibs.SetTxContext(libcommon.Hash{}, header.Hash(), txIndex)
}
execResult, err = core.ApplyMessage(evm, msg, gp, true /* refunds */, gasBailout /* gasBailout */)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/rpcdaemon/commands/trace_filtering.go
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,7 @@ func (api *TraceAPIImpl) filterV3(ctx context.Context, dbtx kv.TemporalTx, fromB
evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vmConfig)

gp := new(core.GasPool).AddGas(msg.Gas())
ibs.Prepare(txHash, lastBlockHash, txIndex)
ibs.SetTxContext(txHash, lastBlockHash, txIndex)
var execResult *core.ExecutionResult
execResult, err = core.ApplyMessage(evm, msg, gp, true /* refunds */, false /* gasBailout */)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions cmd/rpcdaemon/commands/tracing.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (api *PrivateDebugAPIImpl) traceBlock(ctx context.Context, blockNrOrHash rp
stream.WriteNil()
return ctx.Err()
}
ibs.Prepare(txn.Hash(), block.Hash(), idx)
ibs.SetTxContext(txn.Hash(), block.Hash(), idx)
msg, _ := txn.AsMessage(*signer, block.BaseFee(), rules)

if msg.FeeCap().IsZero() && engine != nil {
Expand Down Expand Up @@ -451,7 +451,7 @@ func (api *PrivateDebugAPIImpl) TraceCallMany(ctx context.Context, bundles []Bun
// and apply the message.
gp := new(core.GasPool).AddGas(math.MaxUint64)
for idx, txn := range replayTransactions {
st.Prepare(txn.Hash(), block.Hash(), idx)
st.SetTxContext(txn.Hash(), block.Hash(), idx)
msg, err := txn.AsMessage(*signer, block.BaseFee(), rules)
if err != nil {
stream.WriteNil()
Expand Down Expand Up @@ -494,7 +494,7 @@ func (api *PrivateDebugAPIImpl) TraceCallMany(ctx context.Context, bundles []Bun
}
txCtx = core.NewEVMTxContext(msg)
ibs := evm.IntraBlockState().(*state.IntraBlockState)
ibs.Prepare(common.Hash{}, parent.Hash(), txn_index)
ibs.SetTxContext(common.Hash{}, parent.Hash(), txn_index)
err = transactions.TraceTx(ctx, msg, blockCtx, txCtx, evm.IntraBlockState(), config, chainConfig, stream, api.evmCallTimeout)

if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/state/commands/erigon4.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ func processBlock23(startTxNum uint64, trace bool, txNumStart uint64, rw *StateR
for i, tx := range block.Transactions() {
if txNum >= startTxNum {
ibs := state.New(rw)
ibs.Prepare(tx.Hash(), block.Hash(), i)
ibs.SetTxContext(tx.Hash(), block.Hash(), i)
ct := exec3.NewCallTracer()
vmConfig.Tracer = ct
receipt, _, err := core.ApplyTransaction(chainConfig, getHashFn, engine, nil, gp, ibs, ww, header, tx, usedGas, vmConfig, excessDataGas)
Expand Down
2 changes: 1 addition & 1 deletion cmd/state/commands/history22.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ func runHistory22(trace bool, blockNum, txNumStart uint64, hw *state.HistoryRead
for i, tx := range block.Transactions() {
hw.SetTxNum(txNum)
ibs := state.New(hw)
ibs.Prepare(tx.Hash(), block.Hash(), i)
ibs.SetTxContext(tx.Hash(), block.Hash(), i)
receipt, _, err := core.ApplyTransaction(chainConfig, core.GetHashFn(header, getHeader), engine, nil, gp, ibs, ww, header, tx, usedGas, vmConfig, excessDataGas)
if err != nil {
return 0, nil, fmt.Errorf("could not apply tx %d [%x] failed: %w", i, tx.Hash(), err)
Expand Down
2 changes: 1 addition & 1 deletion cmd/state/commands/opcode_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ func runBlock(engine consensus.Engine, ibs *state.IntraBlockState, txnWriter sta
systemcontracts.UpgradeBuildInSystemContract(chainConfig, header.Number, ibs)
rules := chainConfig.Rules(block.NumberU64(), block.Time())
for i, tx := range block.Transactions() {
ibs.Prepare(tx.Hash(), block.Hash(), i)
ibs.SetTxContext(tx.Hash(), block.Hash(), i)
receipt, _, err := core.ApplyTransaction(chainConfig, core.GetHashFn(header, getHeader), engine, nil, gp, ibs, txnWriter, header, tx, usedGas, vmConfig, excessDataGas)
if err != nil {
return nil, fmt.Errorf("could not apply tx %d [%x] failed: %w", i, tx.Hash(), err)
Expand Down
2 changes: 1 addition & 1 deletion cmd/state/exec3/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ func (rw *Worker) RunTxTaskNoLock(txTask *exec22.TxTask) {
rw.taskGasPool.Reset(txTask.Tx.GetGas())
rw.callTracer.Reset()
vmConfig := vm.Config{Debug: true, Tracer: rw.callTracer, SkipAnalysis: txTask.SkipAnalysis}
ibs.Prepare(txHash, txTask.BlockHash, txTask.TxIndex)
ibs.SetTxContext(txHash, txTask.BlockHash, txTask.TxIndex)
msg := txTask.TxAsMessage

blockContext := txTask.EvmBlockContext
Expand Down
2 changes: 1 addition & 1 deletion cmd/state/exec3/state_recon.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ func (rw *ReconWorker) runTxTask(txTask *exec22.TxTask) error {
} else {
gp := new(core.GasPool).AddGas(txTask.Tx.GetGas())
vmConfig := vm.Config{NoReceipts: true, SkipAnalysis: txTask.SkipAnalysis}
ibs.Prepare(txTask.Tx.Hash(), txTask.BlockHash, txTask.TxIndex)
ibs.SetTxContext(txTask.Tx.Hash(), txTask.BlockHash, txTask.TxIndex)
msg := txTask.TxAsMessage

rw.evm.ResetBetweenBlocks(txTask.EvmBlockContext, core.NewEVMTxContext(msg), ibs, vmConfig, txTask.Rules)
Expand Down
4 changes: 2 additions & 2 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func ExecuteBlockEphemerally(
noop := state.NewNoopWriter()
//fmt.Printf("====txs processing start: %d====\n", block.NumberU64())
for i, tx := range block.Transactions() {
ibs.Prepare(tx.Hash(), block.Hash(), i)
ibs.SetTxContext(tx.Hash(), block.Hash(), i)
writeTrace := false
if vmConfig.Debug && vmConfig.Tracer == nil {
tracer, err := getTracer(i, tx.Hash())
Expand Down Expand Up @@ -226,7 +226,7 @@ func ExecuteBlockEphemerallyBor(
noop := state.NewNoopWriter()
//fmt.Printf("====txs processing start: %d====\n", block.NumberU64())
for i, tx := range block.Transactions() {
ibs.Prepare(tx.Hash(), block.Hash(), i)
ibs.SetTxContext(tx.Hash(), block.Hash(), i)
writeTrace := false
if vmConfig.Debug && vmConfig.Tracer == nil {
tracer, err := getTracer(i, tx.Hash())
Expand Down
4 changes: 2 additions & 2 deletions core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func (b *BlockGen) AddTxWithChain(getHeader func(hash libcommon.Hash, number uin
if b.gasPool == nil {
b.SetCoinbase(libcommon.Address{})
}
b.ibs.Prepare(tx.Hash(), libcommon.Hash{}, len(b.txs))
b.ibs.SetTxContext(tx.Hash(), libcommon.Hash{}, len(b.txs))
receipt, _, err := ApplyTransaction(b.config, GetHashFn(b.header, getHeader), engine, &b.header.Coinbase, b.gasPool, b.ibs, state.NewNoopWriter(), b.header, tx, &b.header.GasUsed, vm.Config{}, b.parent.ExcessDataGas())
if err != nil {
panic(err)
Expand All @@ -129,7 +129,7 @@ func (b *BlockGen) AddFailedTxWithChain(getHeader func(hash libcommon.Hash, numb
if b.gasPool == nil {
b.SetCoinbase(libcommon.Address{})
}
b.ibs.Prepare(tx.Hash(), libcommon.Hash{}, len(b.txs))
b.ibs.SetTxContext(tx.Hash(), libcommon.Hash{}, len(b.txs))
receipt, _, err := ApplyTransaction(b.config, GetHashFn(b.header, getHeader), engine, &b.header.Coinbase, b.gasPool, b.ibs, state.NewNoopWriter(), b.header, tx, &b.header.GasUsed, vm.Config{}, b.parent.ExcessDataGas())
_ = err // accept failed transactions
b.txs = append(b.txs, tx)
Expand Down
103 changes: 78 additions & 25 deletions core/state/intra_block_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,18 @@ type IntraBlockState struct {
logs map[libcommon.Hash][]*types.Log
logSize uint

// Per-transaction access list
accessList *accessList

// Transient storage
transientStorage transientStorage

// Journal of state modifications. This is the backbone of
// Snapshot and RevertToSnapshot.
journal *journal
validRevisions []revision
nextRevisionID int
trace bool
accessList *accessList
balanceInc map[libcommon.Address]*BalanceIncrease // Map of balance increases (without first reading the account)
}

Expand All @@ -95,6 +100,7 @@ func New(stateReader StateReader) *IntraBlockState {
logs: map[libcommon.Hash][]*types.Log{},
journal: newJournal(),
accessList: newAccessList(),
transientStorage: newTransientStorage(),
balanceInc: map[libcommon.Address]*BalanceIncrease{},
}
}
Expand Down Expand Up @@ -414,6 +420,35 @@ func (sdb *IntraBlockState) Selfdestruct(addr libcommon.Address) bool {
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 (sdb *IntraBlockState) SetTransientState(addr libcommon.Address, key libcommon.Hash, value uint256.Int) {
prev := sdb.GetTransientState(addr, key)
if prev == value {
return
}

sdb.journal.append(transientStorageChange{
account: &addr,
key: key,
prevalue: prev,
})

sdb.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 (sdb *IntraBlockState) setTransientState(addr libcommon.Address, key libcommon.Hash, value uint256.Int) {
sdb.transientStorage.Set(addr, key, value)
}

// GetTransientState gets transient storage for a given account.
func (sdb *IntraBlockState) GetTransientState(addr libcommon.Address, key libcommon.Hash) uint256.Int {
return sdb.transientStorage.Get(addr, key)
}

func (sdb *IntraBlockState) getStateObject(addr libcommon.Address) (stateObject *stateObject) {
// Prefer 'live' objects.
if obj := sdb.stateObjects[addr]; obj != nil {
Expand Down Expand Up @@ -701,13 +736,13 @@ func (sdb *IntraBlockState) Print(chainRules chain.Rules) {
}
}

// Prepare sets the current transaction hash and index and block hash which is
// used when the EVM emits new state logs.
func (sdb *IntraBlockState) Prepare(thash, bhash libcommon.Hash, ti int) {
// SetTxContext sets the current transaction hash and index and block hash which are
// used when the EVM emits new state logs. It should be invoked before
// transaction execution.
func (sdb *IntraBlockState) SetTxContext(thash, bhash libcommon.Hash, ti int) {
sdb.thash = thash
sdb.bhash = bhash
sdb.txIndex = ti
sdb.accessList = newAccessList()
}

// no not lock
Expand All @@ -717,30 +752,48 @@ func (sdb *IntraBlockState) clearJournalAndRefund() {
sdb.refund = 0
}

// PrepareAccessList handles the preparatory steps for executing a state transition with
// regards to both EIP-2929 and EIP-2930:
// Prepare handles the preparatory steps for executing a state transition.
// This method must be invoked before state transition.
//
// Berlin fork:
// - Add sender to access list (EIP-2929)
// - Add destination to access list (EIP-2929)
// - Add precompiles to access list (EIP-2929)
// - Add the contents of the optional tx access list (EIP-2930)
//
// - Add sender to access list (2929)
// - Add destination to access list (2929)
// - Add precompiles to access list (2929)
// - Add the contents of the optional tx access list (2930)
// Shanghai fork:
// - Add coinbase to access list (EIP-3651)
//
// This method should only be called if Yolov3/Berlin/2929+2930 is applicable at the current number.
func (sdb *IntraBlockState) PrepareAccessList(sender libcommon.Address, dst *libcommon.Address, precompiles []libcommon.Address, list types2.AccessList) {
sdb.AddAddressToAccessList(sender)
if dst != nil {
sdb.AddAddressToAccessList(*dst)
// If it's a create-tx, the destination will be added inside evm.create
}
for _, addr := range precompiles {
sdb.AddAddressToAccessList(addr)
}
for _, el := range list {
sdb.AddAddressToAccessList(el.Address)
for _, key := range el.StorageKeys {
sdb.AddSlotToAccessList(el.Address, key)
// Cancun fork:
// - Reset transient storage (EIP-1153)
func (sdb *IntraBlockState) Prepare(rules *chain.Rules, sender, coinbase libcommon.Address, dst *libcommon.Address,
precompiles []libcommon.Address, list types2.AccessList,
) {
if rules.IsBerlin {
// Clear out any leftover from previous executions
al := newAccessList()
sdb.accessList = al

al.AddAddress(sender)
if dst != nil {
al.AddAddress(*dst)
// If it's a create-tx, the destination will be added inside evm.create
}
for _, addr := range precompiles {
al.AddAddress(addr)
}
for _, el := range list {
al.AddAddress(el.Address)
for _, key := range el.StorageKeys {
al.AddSlot(el.Address, key)
}
}
if rules.IsShanghai { // EIP-3651: warm coinbase
al.AddAddress(coinbase)
}
}
// Reset transient storage at the beginning of transaction execution
sdb.transientStorage = newTransientStorage()
}

// AddAddressToAccessList adds the given address to the access list
Expand Down
Loading

0 comments on commit 1533674

Please sign in to comment.