Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use upstream instruction sets #657

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
Draft
448 changes: 448 additions & 0 deletions core/contracts_stateful_test.go

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (

"github.com/ava-labs/coreth/consensus"
"github.com/ava-labs/coreth/consensus/misc/eip4844"
"github.com/ava-labs/coreth/core/extstate"
"github.com/ava-labs/coreth/core/state"
"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/core/vm"
Expand All @@ -44,9 +45,9 @@ import (
func init() {
vm.StateDbHook = func(rules params.Rules, db vm.StateDB) vm.StateDB {
if rules.IsApricotPhase1 {
return &StateDbAP1{db}
db = &StateDbAP1{db}
}
return db
return &extstate.StateDB{StateDB: db}
}
}

Expand Down
54 changes: 54 additions & 0 deletions core/extstate/statedb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// (c) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package extstate

import (
"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/core/vm"
"github.com/ava-labs/coreth/params"
"github.com/ava-labs/coreth/predicate"
"github.com/ethereum/go-ethereum/common"
)

type StateDB struct {
vm.StateDB

// Ordered storage slots to be used in predicate verification as set in the tx access list.
// Only set in PrepareAccessList, and un-modified through execution.
predicateStorageSlots map[common.Address][][]byte
}

func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
s.predicateStorageSlots = predicate.PreparePredicateStorageSlots(rules, list)
s.StateDB.Prepare(rules, sender, coinbase, dst, precompiles, list)
}

// GetPredicateStorageSlots returns the storage slots associated with the address, index pair.
// A list of access tuples can be included within transaction types post EIP-2930. The address
// is declared directly on the access tuple and the index is the i'th occurrence of an access
// tuple with the specified address.
//
// Ex. AccessList[[AddrA, Predicate1], [AddrB, Predicate2], [AddrA, Predicate3]]
// In this case, the caller could retrieve predicates 1-3 with the following calls:
// GetPredicateStorageSlots(AddrA, 0) -> Predicate1
// GetPredicateStorageSlots(AddrB, 0) -> Predicate2
// GetPredicateStorageSlots(AddrA, 1) -> Predicate3
func (s *StateDB) GetPredicateStorageSlots(address common.Address, index int) ([]byte, bool) {
predicates, exists := s.predicateStorageSlots[address]
if !exists {
return nil, false
}
if index >= len(predicates) {
return nil, false
}
return predicates[index], true
}

// SetPredicateStorageSlots sets the predicate storage slots for the given address
func (s *StateDB) SetPredicateStorageSlots(address common.Address, predicates [][]byte) {
if s.predicateStorageSlots == nil {
s.predicateStorageSlots = make(map[common.Address][][]byte)
}
s.predicateStorageSlots[address] = predicates
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
// (c) 2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package state
package extstate

import (
"testing"

"github.com/ava-labs/coreth/core/rawdb"
"github.com/ava-labs/coreth/core/state"
"github.com/ava-labs/coreth/precompile/contract"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)

func NewTestStateDB(t testing.TB) contract.StateDB {
db := rawdb.NewMemoryDatabase()
stateDB, err := New(common.Hash{}, NewDatabase(db), nil)
stateDB, err := state.New(common.Hash{}, state.NewDatabase(db), nil)
require.NoError(t, err)
return stateDB
return &StateDB{StateDB: stateDB}
}
81 changes: 17 additions & 64 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import (
"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/metrics"
"github.com/ava-labs/coreth/params"
"github.com/ava-labs/coreth/predicate"
"github.com/ava-labs/coreth/trie"
"github.com/ava-labs/coreth/trie/trienode"
"github.com/ava-labs/coreth/trie/triestate"
Expand Down Expand Up @@ -118,9 +117,6 @@ type StateDB struct {

// Per-transaction access list
accessList *accessList
// Ordered storage slots to be used in predicate verification as set in the tx access list.
// Only set in PrepareAccessList, and un-modified through execution.
predicateStorageSlots map[common.Address][][]byte

// Transient storage
transientStorage transientStorage
Expand Down Expand Up @@ -173,24 +169,23 @@ func NewWithSnapshot(root common.Hash, db Database, snap snapshot.Snapshot) (*St
return nil, err
}
sdb := &StateDB{
db: db,
trie: tr,
originalRoot: root,
accounts: make(map[common.Hash][]byte),
storages: make(map[common.Hash]map[common.Hash][]byte),
accountsOrigin: make(map[common.Address][]byte),
storagesOrigin: make(map[common.Address]map[common.Hash][]byte),
stateObjects: make(map[common.Address]*stateObject),
stateObjectsPending: make(map[common.Address]struct{}),
stateObjectsDirty: make(map[common.Address]struct{}),
stateObjectsDestruct: make(map[common.Address]*types.StateAccount),
logs: make(map[common.Hash][]*types.Log),
preimages: make(map[common.Hash][]byte),
journal: newJournal(),
predicateStorageSlots: make(map[common.Address][][]byte),
accessList: newAccessList(),
transientStorage: newTransientStorage(),
hasher: crypto.NewKeccakState(),
db: db,
trie: tr,
originalRoot: root,
accounts: make(map[common.Hash][]byte),
storages: make(map[common.Hash]map[common.Hash][]byte),
accountsOrigin: make(map[common.Address][]byte),
storagesOrigin: make(map[common.Address]map[common.Hash][]byte),
stateObjects: make(map[common.Address]*stateObject),
stateObjectsPending: make(map[common.Address]struct{}),
stateObjectsDirty: make(map[common.Address]struct{}),
stateObjectsDestruct: make(map[common.Address]*types.StateAccount),
logs: make(map[common.Hash][]*types.Log),
preimages: make(map[common.Hash][]byte),
journal: newJournal(),
accessList: newAccessList(),
transientStorage: newTransientStorage(),
hasher: crypto.NewKeccakState(),
}
if snap != nil {
if snap.Root() != root {
Expand Down Expand Up @@ -771,19 +766,6 @@ func (s *StateDB) CreateAccount(addr common.Address) {
}
}

// copyPredicateStorageSlots creates a deep copy of the provided predicateStorageSlots map.
func copyPredicateStorageSlots(predicateStorageSlots map[common.Address][][]byte) map[common.Address][][]byte {
res := make(map[common.Address][][]byte, len(predicateStorageSlots))
for address, predicates := range predicateStorageSlots {
copiedPredicates := make([][]byte, len(predicates))
for i, predicateBytes := range predicates {
copiedPredicates[i] = common.CopyBytes(predicateBytes)
}
res[address] = copiedPredicates
}
return res
}

// Copy creates a deep, independent copy of the state.
// Snapshots of the copied state cannot be applied to the copy.
func (s *StateDB) Copy() *StateDB {
Expand Down Expand Up @@ -877,7 +859,6 @@ func (s *StateDB) Copy() *StateDB {
// in the middle of a transaction.
state.accessList = s.accessList.Copy()
state.transientStorage = s.transientStorage.Copy()
state.predicateStorageSlots = copyPredicateStorageSlots(s.predicateStorageSlots)

// If there's a prefetcher running, make an inactive copy of it that can
// only access data but does not actively preload (since the user will not
Expand Down Expand Up @@ -1442,8 +1423,6 @@ func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, d
if rules.IsDurango { // EIP-3651: warm coinbase
al.AddAddress(coinbase)
}

s.predicateStorageSlots = predicate.PreparePredicateStorageSlots(rules, list)
}
// Reset transient storage at the beginning of transaction execution
s.transientStorage = newTransientStorage()
Expand Down Expand Up @@ -1489,27 +1468,6 @@ func (s *StateDB) GetTxHash() common.Hash {
return s.thash
}

// GetPredicateStorageSlots returns the storage slots associated with the address, index pair.
// A list of access tuples can be included within transaction types post EIP-2930. The address
// is declared directly on the access tuple and the index is the i'th occurrence of an access
// tuple with the specified address.
//
// Ex. AccessList[[AddrA, Predicate1], [AddrB, Predicate2], [AddrA, Predicate3]]
// In this case, the caller could retrieve predicates 1-3 with the following calls:
// GetPredicateStorageSlots(AddrA, 0) -> Predicate1
// GetPredicateStorageSlots(AddrB, 0) -> Predicate2
// GetPredicateStorageSlots(AddrA, 1) -> Predicate3
func (s *StateDB) GetPredicateStorageSlots(address common.Address, index int) ([]byte, bool) {
predicates, exists := s.predicateStorageSlots[address]
if !exists {
return nil, false
}
if index >= len(predicates) {
return nil, false
}
return predicates[index], true
}

// convertAccountSet converts a provided account set from address keyed to hash keyed.
func (s *StateDB) convertAccountSet(set map[common.Address]*types.StateAccount) map[common.Hash]struct{} {
ret := make(map[common.Hash]struct{}, len(set))
Expand All @@ -1524,11 +1482,6 @@ func (s *StateDB) convertAccountSet(set map[common.Address]*types.StateAccount)
return ret
}

// SetPredicateStorageSlots sets the predicate storage slots for the given address
func (s *StateDB) SetPredicateStorageSlots(address common.Address, predicates [][]byte) {
s.predicateStorageSlots[address] = predicates
}

// copySet returns a deep-copied set.
func copySet[k comparable](set map[k][]byte) map[k][]byte {
copied := make(map[k][]byte, len(set))
Expand Down
4 changes: 3 additions & 1 deletion core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"math/big"

"github.com/ava-labs/coreth/consensus"
"github.com/ava-labs/coreth/core/extstate"
"github.com/ava-labs/coreth/core/state"
"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/core/vm"
Expand Down Expand Up @@ -242,7 +243,8 @@ func ApplyPrecompileActivations(c *params.ChainConfig, parentTimestamp *uint64,
// can be called from within Solidity contracts. Solidity adds a check before invoking a contract to ensure
// that it does not attempt to invoke a non-existent contract.
statedb.SetCode(module.Address, []byte{0x1})
if err := module.Configure(c, activatingConfig, statedb, blockContext); err != nil {
extstatedb := &extstate.StateDB{StateDB: statedb}
if err := module.Configure(c, activatingConfig, extstatedb, blockContext); err != nil {
return fmt.Errorf("could not configure precompile, name: %s, reason: %w", module.ConfigKey, err)
}
}
Expand Down
Loading
Loading