Files

127 lines
4.5 KiB
Go

// (c) 2025, Lux Industries, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package extstate
import (
"github.com/luxfi/geth/common"
"github.com/luxfi/geth/core/tracing"
"github.com/luxfi/evm/core/types"
"github.com/luxfi/evm/core/vm"
ethparams "github.com/luxfi/geth/params"
ethtypes "github.com/luxfi/geth/core/types"
"github.com/holiman/uint256"
"github.com/luxfi/evm/params"
)
type VmStateDB interface {
vm.StateDB
Logs() []*types.Log
GetTxHash() common.Hash
}
type vmStateDB = VmStateDB
type StateDB struct {
vmStateDB
// Ordered storage slots to be used in predicate verification as set in the tx access list.
// Only set in [StateDB.Prepare], and un-modified through execution.
predicateStorageSlots map[common.Address][][]byte
}
// New creates a new [*StateDB] with the given [VmStateDB], effectively wrapping it
// with additional functionality.
func New(vm VmStateDB) *StateDB {
return &StateDB{
vmStateDB: vm,
predicateStorageSlots: make(map[common.Address][][]byte),
}
}
// AddBalance wrapper to match precompile interface (2 params instead of 3)
func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int) {
// Call the underlying AddBalance with unspecified reason
s.vmStateDB.AddBalance(addr, amount, tracing.BalanceChangeUnspecified)
}
// SetState wrapper to match precompile interface (no return value)
func (s *StateDB) SetState(addr common.Address, key, value common.Hash) {
s.vmStateDB.SetState(addr, key, value)
}
// SetNonce wrapper to match precompile interface (2 params instead of 3)
func (s *StateDB) SetNonce(addr common.Address, nonce uint64) {
// Call the underlying SetNonce with unspecified reason
s.vmStateDB.SetNonce(addr, nonce, tracing.NonceChangeUnspecified)
}
// SetCode wrapper to match stateupgrade interface (no return value)
func (s *StateDB) SetCode(addr common.Address, code []byte) {
// Call the underlying SetCode
s.vmStateDB.SetCode(addr, code)
}
// AddLog wrapper to match precompile interface
func (s *StateDB) AddLog(log *types.Log) {
// The underlying StateDB has a different AddLog signature
// We need to call it with the components of the log
if log != nil {
s.vmStateDB.AddLog(log.Address, log.Topics, log.Data, log.BlockNumber)
}
}
func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
// FIXME: GetRulesExtra doesn't exist in current params package
// rulesExtra := params.GetRulesExtra(rules)
// s.predicateStorageSlots = predicate.PreparePredicateStorageSlots(rulesExtra, list)
// For now, just pass an empty Rules struct
// TODO: Map our Rules to ethereum Rules properly
ethRules := ethparams.Rules{
ChainID: rules.ChainID,
}
// Convert our AccessList to geth AccessList
var ethList ethtypes.AccessList
for _, tuple := range list {
ethList = append(ethList, ethtypes.AccessTuple{
Address: tuple.Address,
StorageKeys: tuple.StorageKeys,
})
}
s.vmStateDB.Prepare(ethRules, sender, coinbase, dst, precompiles, ethList)
}
// GetLogData returns the underlying topics and data from each log included in the [StateDB].
// Test helper function.
func (s *StateDB) GetLogData() (topics [][]common.Hash, data [][]byte) {
for _, log := range s.Logs() {
topics = append(topics, log.Topics)
data = append(data, common.CopyBytes(log.Data))
}
return topics, data
}
// GetPredicateStorageSlots returns the storage slots associated with the address+index pair as
// a byte slice as well as a boolean indicating if the address+index pair exists.
// 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 || 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) {
s.predicateStorageSlots[address] = predicates
}