apply specular changes

Co-authored-by: Simon Oswald <git@simonoswald.xyz>
Co-authored-by: MoonShiesty <moonshiesty@protonmail.com>
This commit is contained in:
LEAFER 2023-09-12 16:36:16 +00:00 committed by MoonShiesty
parent 3f40e65c48
commit 0e4999d59f
4 changed files with 201 additions and 0 deletions

View file

@ -1375,6 +1375,99 @@ func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addre
return s.accessList.Contains(addr, slot) return s.accessList.Contains(addr, slot)
} }
// <specular modification>
func (s *StateDB) GetCurrentLogs() []*types.Log {
return s.logs[s.thash]
}
func (s *StateDB) GetCurrentAccessListForProof() (map[common.Address]int, []map[common.Hash]struct{}) {
return s.accessList.addresses, s.accessList.slots
}
func (s *StateDB) GetStateRootForProof(addr common.Address) common.Hash {
stateObject := s.getStateObject(addr)
if stateObject == nil {
return common.Hash{}
}
return stateObject.data.Root
}
func (s *StateDB) GetRootForProof() common.Hash {
return s.trie.Hash()
}
func (s *StateDB) CommitForProof() {
addressesToPrefetch := make([][]byte, 0, len(s.journal.dirties))
for addr := range s.journal.dirties {
obj, exist := s.stateObjects[addr]
if !exist {
continue
}
if obj.empty() { // rollup-specific: we ignore suicided accounts here
obj.deleted = true
// We need to maintain account deletions explicitly (will remain
// set indefinitely). Note only the first occurred self-destruct
// event is tracked.
if _, ok := s.stateObjectsDestruct[obj.address]; !ok {
s.stateObjectsDestruct[obj.address] = obj.origin
}
// Note, we can't do this only at the end of a block because multiple
// transactions within the same block might self destruct and then
// resurrect an account; but the snapshotter needs both events.
delete(s.accounts, obj.addrHash) // Clear out any previously updated account data (may be recreated via a resurrect)
delete(s.storages, obj.addrHash) // Clear out any previously updated storage data (may be recreated via a resurrect)
delete(s.accountsOrigin, obj.address) // Clear out any previously updated account data (may be recreated via a resurrect)
delete(s.storagesOrigin, obj.address) // Clear out any previously updated storage data (may be recreated via a resurrect)
} else {
obj.finalise(true) // Prefetch slots in the background
}
s.stateObjectsPending[addr] = struct{}{}
s.stateObjectsDirty[addr] = struct{}{}
addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure
}
if s.prefetcher != nil && len(addressesToPrefetch) > 0 {
s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch)
}
for addr := range s.stateObjectsPending {
if obj := s.stateObjects[addr]; !obj.deleted {
obj.updateRoot()
}
}
if s.prefetcher != nil {
if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie != nil {
s.trie = trie
}
}
for addr := range s.stateObjectsPending {
if obj := s.stateObjects[addr]; obj.deleted {
s.deleteStateObject(obj)
} else {
s.updateStateObject(obj)
}
}
if len(s.stateObjectsPending) > 0 {
s.stateObjectsPending = make(map[common.Address]struct{})
}
}
func (s *StateDB) DeleteSuicidedAccountForProof(addr common.Address) {
obj, exist := s.stateObjects[addr]
if !exist {
return
}
obj.deleted = true
if s.prefetcher != nil {
s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, [][]byte{common.CopyBytes(addr[:])})
if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie != nil {
s.trie = trie
}
}
s.deleteStateObject(obj)
}
// <specular modification/>
// convertAccountSet converts a provided account set from address keyed to hash keyed. // 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{} { func (s *StateDB) convertAccountSet(set map[common.Address]*types.StateAccount) map[common.Hash]struct{} {
ret := make(map[common.Hash]struct{}, len(set)) ret := make(map[common.Hash]struct{}, len(set))

View file

@ -146,6 +146,65 @@ type Message struct {
SkipAccountChecks bool SkipAccountChecks bool
} }
// <specular modification>
// The vm package doesn't have access to the Message type defined above.
// Getters are defined for EVMHook which uses MessageInterface instead.
func (m *Message) GetTo() *common.Address {
return m.To
}
func (m *Message) GetFrom() common.Address {
return m.From
}
func (m *Message) GetNonce() uint64 {
return m.Nonce
}
func (m *Message) GetValue() *big.Int {
return m.Value
}
func (m *Message) GetGasLimit() uint64 {
return m.GasLimit
}
func (m *Message) GetGasPrice() *big.Int {
return m.GasPrice
}
func (m *Message) GetGasFeeCap() *big.Int {
return m.GasFeeCap
}
func (m *Message) GetGasTipCap() *big.Int {
return m.GasTipCap
}
func (m *Message) GetData() []byte {
return m.Data
}
func (m *Message) GetAccessList() types.AccessList {
return m.AccessList
}
func (m *Message) GetBlobGasFeeCap() *big.Int {
return m.BlobGasFeeCap
}
func (m *Message) GetBlobHashes() []common.Hash {
return m.BlobHashes
}
func (m *Message) GetSkipAccountChecks() bool {
return m.SkipAccountChecks
}
// <specular modification/>
// TransactionToMessage converts a transaction into a Message. // TransactionToMessage converts a transaction into a Message.
func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int) (*Message, error) { func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int) (*Message, error) {
msg := &Message{ msg := &Message{
@ -389,6 +448,15 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
} }
st.gasRemaining -= gas st.gasRemaining -= gas
// <specular modification>
if st.evm.Config.SpecularEVMPreTransferHook != nil {
err = st.evm.Config.SpecularEVMPreTransferHook(st.msg, st.evm)
if err != nil {
return nil, err
}
}
// <specular modification/>
// Check clause 6 // Check clause 6
if msg.Value.Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From, msg.Value) { if msg.Value.Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From, msg.Value) {
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex()) return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())

View file

@ -20,6 +20,7 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -78,6 +79,17 @@ type StateDB interface {
AddLog(*types.Log) AddLog(*types.Log)
AddPreimage(common.Hash, []byte) AddPreimage(common.Hash, []byte)
// <specular modification>
Copy() *state.StateDB
GetCurrentLogs() []*types.Log
GetCurrentAccessListForProof() (map[common.Address]int, []map[common.Hash]struct{})
GetStateRootForProof(common.Address) common.Hash
GetRootForProof() common.Hash
GetStorageRoot(addr common.Address) common.Hash
CommitForProof()
DeleteSuicidedAccountForProof(addr common.Address)
// <specular modification/>
} }
// CallContext provides a basic interface for the EVM calling conventions. The EVM // CallContext provides a basic interface for the EVM calling conventions. The EVM

View file

@ -17,18 +17,46 @@
package vm package vm
import ( import (
"math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
// <specular modification>
type MessageInterface interface {
GetTo() *common.Address
GetFrom() common.Address
GetNonce() uint64
GetValue() *big.Int
GetGasLimit() uint64
GetGasPrice() *big.Int
GetGasFeeCap() *big.Int
GetGasTipCap() *big.Int
GetData() []byte
GetAccessList() types.AccessList
GetBlobGasFeeCap() *big.Int
GetBlobHashes() []common.Hash
GetSkipAccountChecks() bool
}
type EVMHook func(msg MessageInterface, evm *EVM) error
// <specular modification/>
// Config are the configuration options for the Interpreter // Config are the configuration options for the Interpreter
type Config struct { type Config struct {
Tracer EVMLogger // Opcode logger Tracer EVMLogger // Opcode logger
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
ExtraEips []int // Additional EIPS that are to be enabled ExtraEips []int // Additional EIPS that are to be enabled
// <specular modification>
SpecularEVMPreTransferHook EVMHook
// <specular modification/>
} }
// ScopeContext contains the things that are per-call, such as stack and memory, // ScopeContext contains the things that are per-call, such as stack and memory,