core/vm: implement eip-7843

This commit is contained in:
MariusVanDerWijden 2026-01-12 21:55:52 +01:00 committed by Jared Wasinger
parent 4c36eaf532
commit f7ce5467e3
9 changed files with 71 additions and 8 deletions

View file

@ -36,6 +36,7 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
BlockAccessList *bal.BlockAccessList `json:"blockAccessList"` BlockAccessList *bal.BlockAccessList `json:"blockAccessList"`
SlotNumber *hexutil.Uint64 `json:"slotNumber"`
} }
var enc ExecutableData var enc ExecutableData
enc.ParentHash = e.ParentHash enc.ParentHash = e.ParentHash
@ -61,6 +62,7 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed) enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas) enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
enc.BlockAccessList = e.BlockAccessList enc.BlockAccessList = e.BlockAccessList
enc.SlotNumber = (*hexutil.Uint64)(e.SlotNumber)
return json.Marshal(&enc) return json.Marshal(&enc)
} }
@ -85,6 +87,7 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
BlockAccessList *bal.BlockAccessList `json:"blockAccessList"` BlockAccessList *bal.BlockAccessList `json:"blockAccessList"`
SlotNumber *hexutil.Uint64 `json:"slotNumber"`
} }
var dec ExecutableData var dec ExecutableData
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
@ -161,5 +164,8 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
if dec.BlockAccessList != nil { if dec.BlockAccessList != nil {
e.BlockAccessList = dec.BlockAccessList e.BlockAccessList = dec.BlockAccessList
} }
if dec.SlotNumber != nil {
e.SlotNumber = (*uint64)(dec.SlotNumber)
}
return nil return nil
} }

View file

@ -93,6 +93,7 @@ type ExecutableData struct {
BlobGasUsed *uint64 `json:"blobGasUsed"` BlobGasUsed *uint64 `json:"blobGasUsed"`
ExcessBlobGas *uint64 `json:"excessBlobGas"` ExcessBlobGas *uint64 `json:"excessBlobGas"`
BlockAccessList *bal.BlockAccessList `json:"blockAccessList"` BlockAccessList *bal.BlockAccessList `json:"blockAccessList"`
SlotNumber *uint64 `json:"slotNumber"`
} }
// JSON type overrides for executableData. // JSON type overrides for executableData.
@ -107,6 +108,7 @@ type executableDataMarshaling struct {
Transactions []hexutil.Bytes Transactions []hexutil.Bytes
BlobGasUsed *hexutil.Uint64 BlobGasUsed *hexutil.Uint64
ExcessBlobGas *hexutil.Uint64 ExcessBlobGas *hexutil.Uint64
SlotNumber *hexutil.Uint64
} }
// StatelessPayloadStatusV1 is the result of a stateless payload execution. // StatelessPayloadStatusV1 is the result of a stateless payload execution.
@ -302,7 +304,6 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
balHash := data.BlockAccessList.Hash() balHash := data.BlockAccessList.Hash()
blockAccessListHash = &balHash blockAccessListHash = &balHash
} }
header := &types.Header{ header := &types.Header{
ParentHash: data.ParentHash, ParentHash: data.ParentHash,
UncleHash: types.EmptyUncleHash, UncleHash: types.EmptyUncleHash,
@ -325,6 +326,7 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
ParentBeaconRoot: beaconRoot, ParentBeaconRoot: beaconRoot,
RequestsHash: requestsHash, RequestsHash: requestsHash,
BlockAccessListHash: blockAccessListHash, BlockAccessListHash: blockAccessListHash,
SlotNumber: data.SlotNumber,
} }
return types.NewBlockWithHeader(header).WithBody(body), nil return types.NewBlockWithHeader(header).WithBody(body), nil
} }
@ -350,6 +352,7 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
Withdrawals: block.Withdrawals(), Withdrawals: block.Withdrawals(),
BlobGasUsed: block.BlobGasUsed(), BlobGasUsed: block.BlobGasUsed(),
ExcessBlobGas: block.ExcessBlobGas(), ExcessBlobGas: block.ExcessBlobGas(),
SlotNumber: block.SlotNumber(),
BlockAccessList: block.Body().AccessList, BlockAccessList: block.Body().AccessList,
} }

View file

@ -44,6 +44,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
baseFee *big.Int baseFee *big.Int
blobBaseFee *big.Int blobBaseFee *big.Int
random *common.Hash random *common.Hash
slotnum uint64
) )
// If we don't have an explicit author (i.e. not mining), extract from the header // If we don't have an explicit author (i.e. not mining), extract from the header
@ -61,6 +62,10 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
if header.Difficulty.Sign() == 0 { if header.Difficulty.Sign() == 0 {
random = &header.MixDigest random = &header.MixDigest
} }
if header.SlotNumber != nil {
slotnum = *header.SlotNumber
}
return vm.BlockContext{ return vm.BlockContext{
CanTransfer: CanTransfer, CanTransfer: CanTransfer,
Transfer: Transfer, Transfer: Transfer,
@ -73,6 +78,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
BlobBaseFee: blobBaseFee, BlobBaseFee: blobBaseFee,
GasLimit: header.GasLimit, GasLimit: header.GasLimit,
Random: random, Random: random,
Slotnum: slotnum,
} }
} }

View file

@ -103,6 +103,9 @@ type Header struct {
// BlockAccessListHash was added by EIP-7928 and is ignored in legacy headers. // BlockAccessListHash was added by EIP-7928 and is ignored in legacy headers.
BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"` BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"`
// SlotNumber was added by EIP-7843 and is ignored in legacy headers.
SlotNumber *uint64 `json:"slotNumber" rlp:"optional"`
} }
// field type overrides for gencodec // field type overrides for gencodec
@ -117,6 +120,7 @@ type headerMarshaling struct {
Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
BlobGasUsed *hexutil.Uint64 BlobGasUsed *hexutil.Uint64
ExcessBlobGas *hexutil.Uint64 ExcessBlobGas *hexutil.Uint64
SlotNumber *hexutil.Uint64
} }
// Hash returns the block hash of the header, which is simply the keccak256 hash of its // Hash returns the block hash of the header, which is simply the keccak256 hash of its
@ -431,6 +435,15 @@ func (b *Block) BlobGasUsed() *uint64 {
return blobGasUsed return blobGasUsed
} }
func (b *Block) SlotNumber() *uint64 {
var slotNum *uint64
if b.header.SlotNumber != nil {
slotNum = new(uint64)
*slotNum = *b.header.SlotNumber
}
return slotNum
}
// Size returns the true RLP encoded storage size of the block, either by encoding // Size returns the true RLP encoded storage size of the block, either by encoding
// and returning it, or returning a previously cached value. // and returning it, or returning a previously cached value.
func (b *Block) Size() uint64 { func (b *Block) Size() uint64 {

View file

@ -38,6 +38,7 @@ func (h Header) MarshalJSON() ([]byte, error) {
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"` RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"` BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"`
SlotNumber *hexutil.Uint64 `json:"slotNumber" rlp:"optional"`
Hash common.Hash `json:"hash"` Hash common.Hash `json:"hash"`
} }
var enc Header var enc Header
@ -63,6 +64,7 @@ func (h Header) MarshalJSON() ([]byte, error) {
enc.ParentBeaconRoot = h.ParentBeaconRoot enc.ParentBeaconRoot = h.ParentBeaconRoot
enc.RequestsHash = h.RequestsHash enc.RequestsHash = h.RequestsHash
enc.BlockAccessListHash = h.BlockAccessListHash enc.BlockAccessListHash = h.BlockAccessListHash
enc.SlotNumber = (*hexutil.Uint64)(h.SlotNumber)
enc.Hash = h.Hash() enc.Hash = h.Hash()
return json.Marshal(&enc) return json.Marshal(&enc)
} }
@ -92,6 +94,7 @@ func (h *Header) UnmarshalJSON(input []byte) error {
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"` RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"` BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"`
SlotNumber *hexutil.Uint64 `json:"slotNumber" rlp:"optional"`
} }
var dec Header var dec Header
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
@ -175,5 +178,8 @@ func (h *Header) UnmarshalJSON(input []byte) error {
if dec.BlockAccessListHash != nil { if dec.BlockAccessListHash != nil {
h.BlockAccessListHash = dec.BlockAccessListHash h.BlockAccessListHash = dec.BlockAccessListHash
} }
if dec.SlotNumber != nil {
h.SlotNumber = (*uint64)(dec.SlotNumber)
}
return nil return nil
} }

View file

@ -44,7 +44,8 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
_tmp5 := obj.ParentBeaconRoot != nil _tmp5 := obj.ParentBeaconRoot != nil
_tmp6 := obj.RequestsHash != nil _tmp6 := obj.RequestsHash != nil
_tmp7 := obj.BlockAccessListHash != nil _tmp7 := obj.BlockAccessListHash != nil
if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 { _tmp8 := obj.SlotNumber != nil
if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 || _tmp8 {
if obj.BaseFee == nil { if obj.BaseFee == nil {
w.Write(rlp.EmptyString) w.Write(rlp.EmptyString)
} else { } else {
@ -54,48 +55,55 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
w.WriteBigInt(obj.BaseFee) w.WriteBigInt(obj.BaseFee)
} }
} }
if _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 { if _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 || _tmp8 {
if obj.WithdrawalsHash == nil { if obj.WithdrawalsHash == nil {
w.Write([]byte{0x80}) w.Write([]byte{0x80})
} else { } else {
w.WriteBytes(obj.WithdrawalsHash[:]) w.WriteBytes(obj.WithdrawalsHash[:])
} }
} }
if _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 { if _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 || _tmp8 {
if obj.BlobGasUsed == nil { if obj.BlobGasUsed == nil {
w.Write([]byte{0x80}) w.Write([]byte{0x80})
} else { } else {
w.WriteUint64((*obj.BlobGasUsed)) w.WriteUint64((*obj.BlobGasUsed))
} }
} }
if _tmp4 || _tmp5 || _tmp6 || _tmp7 { if _tmp4 || _tmp5 || _tmp6 || _tmp7 || _tmp8 {
if obj.ExcessBlobGas == nil { if obj.ExcessBlobGas == nil {
w.Write([]byte{0x80}) w.Write([]byte{0x80})
} else { } else {
w.WriteUint64((*obj.ExcessBlobGas)) w.WriteUint64((*obj.ExcessBlobGas))
} }
} }
if _tmp5 || _tmp6 || _tmp7 { if _tmp5 || _tmp6 || _tmp7 || _tmp8 {
if obj.ParentBeaconRoot == nil { if obj.ParentBeaconRoot == nil {
w.Write([]byte{0x80}) w.Write([]byte{0x80})
} else { } else {
w.WriteBytes(obj.ParentBeaconRoot[:]) w.WriteBytes(obj.ParentBeaconRoot[:])
} }
} }
if _tmp6 || _tmp7 { if _tmp6 || _tmp7 || _tmp8 {
if obj.RequestsHash == nil { if obj.RequestsHash == nil {
w.Write([]byte{0x80}) w.Write([]byte{0x80})
} else { } else {
w.WriteBytes(obj.RequestsHash[:]) w.WriteBytes(obj.RequestsHash[:])
} }
} }
if _tmp7 { if _tmp7 || _tmp8 {
if obj.BlockAccessListHash == nil { if obj.BlockAccessListHash == nil {
w.Write([]byte{0x80}) w.Write([]byte{0x80})
} else { } else {
w.WriteBytes(obj.BlockAccessListHash[:]) w.WriteBytes(obj.BlockAccessListHash[:])
} }
} }
if _tmp8 {
if obj.SlotNumber == nil {
w.Write([]byte{0x80})
} else {
w.WriteUint64((*obj.SlotNumber))
}
}
w.ListEnd(_tmp0) w.ListEnd(_tmp0)
return w.Flush() return w.Flush()
} }

View file

@ -43,6 +43,7 @@ var activators = map[int]func(*JumpTable){
7702: enable7702, 7702: enable7702,
7939: enable7939, 7939: enable7939,
8024: enable8024, 8024: enable8024,
7843: enable7843,
} }
// EnableEIP enables the given EIP on the config. // EnableEIP enables the given EIP on the config.
@ -579,3 +580,19 @@ func enable7702(jt *JumpTable) {
jt[STATICCALL].dynamicGas = gasStaticCallEIP7702 jt[STATICCALL].dynamicGas = gasStaticCallEIP7702
jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP7702 jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP7702
} }
// opSlotnum enables the SLOTNUM opcode
func opSlotnum(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(uint256.NewInt(evm.Context.Slotnum))
return nil, nil
}
// enable7843 enables the SLOTNUM opcode as specified in EIP-7843.
func enable7843(jt *JumpTable) {
jt[SLOTNUM] = &operation{
execute: opSlotnum,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
}
}

View file

@ -66,6 +66,7 @@ type BlockContext struct {
BaseFee *big.Int // Provides information for BASEFEE (0 if vm runs with NoBaseFee flag and 0 gas price) BaseFee *big.Int // Provides information for BASEFEE (0 if vm runs with NoBaseFee flag and 0 gas price)
BlobBaseFee *big.Int // Provides information for BLOBBASEFEE (0 if vm runs with NoBaseFee flag and 0 blob gas price) BlobBaseFee *big.Int // Provides information for BLOBBASEFEE (0 if vm runs with NoBaseFee flag and 0 blob gas price)
Random *common.Hash // Provides information for PREVRANDAO Random *common.Hash // Provides information for PREVRANDAO
Slotnum uint64 // Provides information for SLOTNUM
} }
// TxContext provides the EVM with information about a transaction. // TxContext provides the EVM with information about a transaction.

View file

@ -105,6 +105,7 @@ const (
BASEFEE OpCode = 0x48 BASEFEE OpCode = 0x48
BLOBHASH OpCode = 0x49 BLOBHASH OpCode = 0x49
BLOBBASEFEE OpCode = 0x4a BLOBBASEFEE OpCode = 0x4a
SLOTNUM OpCode = 0x4b
) )
// 0x50 range - 'storage' and execution. // 0x50 range - 'storage' and execution.
@ -320,6 +321,7 @@ var opCodeToString = [256]string{
BASEFEE: "BASEFEE", BASEFEE: "BASEFEE",
BLOBHASH: "BLOBHASH", BLOBHASH: "BLOBHASH",
BLOBBASEFEE: "BLOBBASEFEE", BLOBBASEFEE: "BLOBBASEFEE",
SLOTNUM: "SLOTNUM",
// 0x50 range - 'storage' and execution. // 0x50 range - 'storage' and execution.
POP: "POP", POP: "POP",
@ -502,6 +504,7 @@ var stringToOp = map[string]OpCode{
"BASEFEE": BASEFEE, "BASEFEE": BASEFEE,
"BLOBHASH": BLOBHASH, "BLOBHASH": BLOBHASH,
"BLOBBASEFEE": BLOBBASEFEE, "BLOBBASEFEE": BLOBBASEFEE,
"SLOTNUM": SLOTNUM,
"DELEGATECALL": DELEGATECALL, "DELEGATECALL": DELEGATECALL,
"STATICCALL": STATICCALL, "STATICCALL": STATICCALL,
"CODESIZE": CODESIZE, "CODESIZE": CODESIZE,