Skip to content

Commit

Permalink
all: eip1153
Browse files Browse the repository at this point in the history
Implements EIP-1153 "Transient Storage"

https://eips.ethereum.org/EIPS/eip-1153

Based on ethereum/go-ethereum#26003
  • Loading branch information
tynes committed Nov 26, 2022
1 parent 8cbf316 commit 0127728
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 7 deletions.
42 changes: 35 additions & 7 deletions core/state/intra_block_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,14 @@ type IntraBlockState struct {

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

// Create a new state from a given trie
Expand All @@ -101,6 +102,7 @@ func New(stateReader StateReader) *IntraBlockState {
logs: map[common.Hash][]*types.Log{},
journal: newJournal(),
accessList: newAccessList(),
transientStorage: newTransientStorage(),
balanceInc: map[common.Address]*BalanceIncrease{},
}
}
Expand Down Expand Up @@ -136,6 +138,7 @@ func (sdb *IntraBlockState) Reset() {
sdb.logSize = 0
sdb.clearJournalAndRefund()
sdb.accessList = newAccessList()
sdb.transientStorage = newTransientStorage()
sdb.balanceInc = make(map[common.Address]*BalanceIncrease)
}

Expand Down Expand Up @@ -505,6 +508,30 @@ func (sdb *IntraBlockState) Suicide(addr common.Address) bool {
return true
}

func (sdb *IntraBlockState) SetTransientState(addr common.Address, key *common.Hash, value uint256.Int) {
var prev uint256.Int
sdb.GetTransientState(addr, key, &prev)
if prev == value {
return
}

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

sdb.setTransientState(addr, key, value)
}

func (sdb *IntraBlockState) setTransientState(addr common.Address, key *common.Hash, value uint256.Int) {
sdb.transientStorage.Set(addr, key, value)
}

func (sdb *IntraBlockState) GetTransientState(addr common.Address, key *common.Hash, value *uint256.Int) {
sdb.transientStorage.Get(addr, key, value)
}

func (sdb *IntraBlockState) getStateObject(addr common.Address) (stateObject *stateObject) {
// Prefer 'live' objects.
if obj := sdb.stateObjects[addr]; obj != nil {
Expand Down Expand Up @@ -813,6 +840,7 @@ func (sdb *IntraBlockState) Prepare(thash, bhash common.Hash, ti int) {
sdb.bhash = bhash
sdb.txIndex = ti
sdb.accessList = newAccessList()
sdb.transientStorage = newTransientStorage()
}

// no not lock
Expand Down
10 changes: 10 additions & 0 deletions core/state/intra_block_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,16 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
},
args: make([]int64, 2),
},
{
name: "SetTransientState",
fn: func(a testAction, s *IntraBlockState) {
var key common.Hash
binary.BigEndian.PutUint16(key[:], uint16(a.args[0]))
val := uint256.NewInt(uint64(a.args[1]))
s.SetTransientState(addr, &key, *val)
},
args: make([]int64, 2),
},
{
name: "SetCode",
fn: func(a testAction, s *IntraBlockState) {
Expand Down
13 changes: 13 additions & 0 deletions core/state/journal.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,11 @@ type (
key common.Hash
prevalue uint256.Int
}
transientStorageChange struct {
account *common.Address
key common.Hash
prevalue uint256.Int
}
codeChange struct {
account *common.Address
prevcode []byte
Expand Down Expand Up @@ -262,6 +267,14 @@ func (ch fakeStorageChange) dirtied() *common.Address {
return ch.account
}

func (ch transientStorageChange) revert(s *IntraBlockState) {
s.setTransientState(*ch.account, &ch.key, ch.prevalue)
}

func (ch transientStorageChange) dirtied() *common.Address {
return nil
}

func (ch refundChange) revert(s *IntraBlockState) {
s.refund = ch.prev
}
Expand Down
57 changes: 57 additions & 0 deletions core/state/transient_storage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// 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 state

import (
"github.com/holiman/uint256"
"github.com/ledgerwatch/erigon/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 *common.Hash, value uint256.Int) {
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, value *uint256.Int) {
val, ok := t[addr]
if !ok {
*value = uint256.Int{}
} else {
*value = 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
}
40 changes: 40 additions & 0 deletions core/vm/eips.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,46 @@ func enable3198(jt *JumpTable) {
}
}

// enable1153 applies EIP-1153 "Transient Storage"
// - Adds TLOAD that reads from transient storage
// - Adds TSTORE that writes to transient storage
func enable1153(jt *JumpTable) {
jt[TLOAD] = &operation{
execute: opTload,
constantGas: params.WarmStorageReadCostEIP2929,
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
}

jt[TSTORE] = &operation{
execute: opTstore,
constantGas: params.WarmStorageReadCostEIP2929,
minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
}
}

// opTload implements TLOAD opcode
func opTload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
loc := scope.Stack.Peek()
interpreter.hasherBuf = loc.Bytes32()
interpreter.evm.IntraBlockState().GetTransientState(scope.Contract.Address(), &interpreter.hasherBuf, loc)
return nil, nil
}

// opTstore implements TSTORE opcode
func opTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
return nil, ErrWriteProtection
}
loc := scope.Stack.Pop()
val := scope.Stack.Pop()
interpreter.hasherBuf = loc.Bytes32()
interpreter.evm.IntraBlockState().SetTransientState(scope.Contract.Address(), &interpreter.hasherBuf, val)

return nil, nil
}

// opBaseFee implements BASEFEE opcode
func opBaseFee(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) {
baseFee := interpreter.evm.Context().BaseFee
Expand Down
2 changes: 2 additions & 0 deletions core/vm/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ type IntraBlockState interface {
GetCommittedState(common.Address, *common.Hash, *uint256.Int)
GetState(address common.Address, slot *common.Hash, outValue *uint256.Int)
SetState(common.Address, *common.Hash, uint256.Int)
GetTransientState(address common.Address, slot *common.Hash, outValue *uint256.Int)
SetTransientState(common.Address, *common.Hash, uint256.Int)

Suicide(common.Address) bool
HasSuicided(common.Address) bool
Expand Down
12 changes: 12 additions & 0 deletions core/vm/opcodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ const (
LOG4
)

// 0xb0 range.
const (
TSTORE OpCode = 0xb3
TLOAD OpCode = 0xb4
)

// unofficial opcodes used for parsing.
const (
PUSH OpCode = 0xb0 + iota
Expand Down Expand Up @@ -374,6 +380,10 @@ var opCodeToString = map[OpCode]string{
LOG3: "LOG3",
LOG4: "LOG4",

// 0xb0 range.
TLOAD: "TLOAD",
TSTORE: "TSTORE",

// 0xf0 range.
CREATE: "CREATE",
CALL: "CALL",
Expand Down Expand Up @@ -531,6 +541,8 @@ var stringToOp = map[string]OpCode{
"SWAP14": SWAP14,
"SWAP15": SWAP15,
"SWAP16": SWAP16,
"TLOAD": TLOAD,
"TSTORE": TSTORE,
"LOG0": LOG0,
"LOG1": LOG1,
"LOG2": LOG2,
Expand Down

0 comments on commit 0127728

Please sign in to comment.