diff --git a/beacon/engine/gen_ed.go b/beacon/engine/gen_ed.go index 94ef5c7f19..937853baeb 100644 --- a/beacon/engine/gen_ed.go +++ b/beacon/engine/gen_ed.go @@ -36,6 +36,7 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) { BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` BlockAccessList *bal.BlockAccessList `json:"blockAccessList"` + SlotNumber *hexutil.Uint64 `json:"slotNumber"` } var enc ExecutableData enc.ParentHash = e.ParentHash @@ -61,6 +62,7 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) { enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed) enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas) enc.BlockAccessList = e.BlockAccessList + enc.SlotNumber = (*hexutil.Uint64)(e.SlotNumber) return json.Marshal(&enc) } @@ -85,6 +87,7 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error { BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` BlockAccessList *bal.BlockAccessList `json:"blockAccessList"` + SlotNumber *hexutil.Uint64 `json:"slotNumber"` } var dec ExecutableData if err := json.Unmarshal(input, &dec); err != nil { @@ -161,5 +164,8 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error { if dec.BlockAccessList != nil { e.BlockAccessList = dec.BlockAccessList } + if dec.SlotNumber != nil { + e.SlotNumber = (*uint64)(dec.SlotNumber) + } return nil } diff --git a/beacon/engine/types.go b/beacon/engine/types.go index e8cc82f9e4..c181cc968c 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -93,6 +93,7 @@ type ExecutableData struct { BlobGasUsed *uint64 `json:"blobGasUsed"` ExcessBlobGas *uint64 `json:"excessBlobGas"` BlockAccessList *bal.BlockAccessList `json:"blockAccessList"` + SlotNumber *uint64 `json:"slotNumber"` } // JSON type overrides for executableData. @@ -107,6 +108,7 @@ type executableDataMarshaling struct { Transactions []hexutil.Bytes BlobGasUsed *hexutil.Uint64 ExcessBlobGas *hexutil.Uint64 + SlotNumber *hexutil.Uint64 } // StatelessPayloadStatusV1 is the result of a stateless payload execution. @@ -302,7 +304,6 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H balHash := data.BlockAccessList.Hash() blockAccessListHash = &balHash } - header := &types.Header{ ParentHash: data.ParentHash, UncleHash: types.EmptyUncleHash, @@ -325,6 +326,7 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H ParentBeaconRoot: beaconRoot, RequestsHash: requestsHash, BlockAccessListHash: blockAccessListHash, + SlotNumber: data.SlotNumber, } return types.NewBlockWithHeader(header).WithBody(body), nil } @@ -350,6 +352,7 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types. Withdrawals: block.Withdrawals(), BlobGasUsed: block.BlobGasUsed(), ExcessBlobGas: block.ExcessBlobGas(), + SlotNumber: block.SlotNumber(), BlockAccessList: block.Body().AccessList, } diff --git a/core/evm.go b/core/evm.go index 18d940fdd2..7549ca92a6 100644 --- a/core/evm.go +++ b/core/evm.go @@ -44,6 +44,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common baseFee *big.Int blobBaseFee *big.Int random *common.Hash + slotnum uint64 ) // 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 { random = &header.MixDigest } + if header.SlotNumber != nil { + slotnum = *header.SlotNumber + } + return vm.BlockContext{ CanTransfer: CanTransfer, Transfer: Transfer, @@ -73,6 +78,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common BlobBaseFee: blobBaseFee, GasLimit: header.GasLimit, Random: random, + Slotnum: slotnum, } } diff --git a/core/types/block.go b/core/types/block.go index 87c4087e8b..498047c509 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -103,6 +103,9 @@ type Header struct { // BlockAccessListHash was added by EIP-7928 and is ignored in legacy headers. 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 @@ -117,6 +120,7 @@ type headerMarshaling struct { Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON BlobGasUsed *hexutil.Uint64 ExcessBlobGas *hexutil.Uint64 + SlotNumber *hexutil.Uint64 } // 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 } +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 // and returning it, or returning a previously cached value. func (b *Block) Size() uint64 { diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index 66856bba36..2e2f1cdca5 100644 --- a/core/types/gen_header_json.go +++ b/core/types/gen_header_json.go @@ -38,6 +38,7 @@ func (h Header) MarshalJSON() ([]byte, error) { ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"` BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"` + SlotNumber *hexutil.Uint64 `json:"slotNumber" rlp:"optional"` Hash common.Hash `json:"hash"` } var enc Header @@ -63,6 +64,7 @@ func (h Header) MarshalJSON() ([]byte, error) { enc.ParentBeaconRoot = h.ParentBeaconRoot enc.RequestsHash = h.RequestsHash enc.BlockAccessListHash = h.BlockAccessListHash + enc.SlotNumber = (*hexutil.Uint64)(h.SlotNumber) enc.Hash = h.Hash() return json.Marshal(&enc) } @@ -92,6 +94,7 @@ func (h *Header) UnmarshalJSON(input []byte) error { ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"` BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"` + SlotNumber *hexutil.Uint64 `json:"slotNumber" rlp:"optional"` } var dec Header if err := json.Unmarshal(input, &dec); err != nil { @@ -175,5 +178,8 @@ func (h *Header) UnmarshalJSON(input []byte) error { if dec.BlockAccessListHash != nil { h.BlockAccessListHash = dec.BlockAccessListHash } + if dec.SlotNumber != nil { + h.SlotNumber = (*uint64)(dec.SlotNumber) + } return nil } diff --git a/core/types/gen_header_rlp.go b/core/types/gen_header_rlp.go index e68e8927c2..3b7eb2c926 100644 --- a/core/types/gen_header_rlp.go +++ b/core/types/gen_header_rlp.go @@ -44,7 +44,8 @@ func (obj *Header) EncodeRLP(_w io.Writer) error { _tmp5 := obj.ParentBeaconRoot != nil _tmp6 := obj.RequestsHash != 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 { w.Write(rlp.EmptyString) } else { @@ -54,48 +55,55 @@ func (obj *Header) EncodeRLP(_w io.Writer) error { w.WriteBigInt(obj.BaseFee) } } - if _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 { + if _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 || _tmp8 { if obj.WithdrawalsHash == nil { w.Write([]byte{0x80}) } else { w.WriteBytes(obj.WithdrawalsHash[:]) } } - if _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 { + if _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 || _tmp8 { if obj.BlobGasUsed == nil { w.Write([]byte{0x80}) } else { w.WriteUint64((*obj.BlobGasUsed)) } } - if _tmp4 || _tmp5 || _tmp6 || _tmp7 { + if _tmp4 || _tmp5 || _tmp6 || _tmp7 || _tmp8 { if obj.ExcessBlobGas == nil { w.Write([]byte{0x80}) } else { w.WriteUint64((*obj.ExcessBlobGas)) } } - if _tmp5 || _tmp6 || _tmp7 { + if _tmp5 || _tmp6 || _tmp7 || _tmp8 { if obj.ParentBeaconRoot == nil { w.Write([]byte{0x80}) } else { w.WriteBytes(obj.ParentBeaconRoot[:]) } } - if _tmp6 || _tmp7 { + if _tmp6 || _tmp7 || _tmp8 { if obj.RequestsHash == nil { w.Write([]byte{0x80}) } else { w.WriteBytes(obj.RequestsHash[:]) } } - if _tmp7 { + if _tmp7 || _tmp8 { if obj.BlockAccessListHash == nil { w.Write([]byte{0x80}) } else { w.WriteBytes(obj.BlockAccessListHash[:]) } } + if _tmp8 { + if obj.SlotNumber == nil { + w.Write([]byte{0x80}) + } else { + w.WriteUint64((*obj.SlotNumber)) + } + } w.ListEnd(_tmp0) return w.Flush() } diff --git a/core/vm/eips.go b/core/vm/eips.go index dfcac4b930..b0b22ad73e 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -43,6 +43,7 @@ var activators = map[int]func(*JumpTable){ 7702: enable7702, 7939: enable7939, 8024: enable8024, + 7843: enable7843, } // EnableEIP enables the given EIP on the config. @@ -579,3 +580,19 @@ func enable7702(jt *JumpTable) { jt[STATICCALL].dynamicGas = gasStaticCallEIP7702 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), + } +} diff --git a/core/vm/evm.go b/core/vm/evm.go index 1afab93912..428781713b 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -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) 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 + Slotnum uint64 // Provides information for SLOTNUM } // TxContext provides the EVM with information about a transaction. diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 9a32126a80..cb871dca6d 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -105,6 +105,7 @@ const ( BASEFEE OpCode = 0x48 BLOBHASH OpCode = 0x49 BLOBBASEFEE OpCode = 0x4a + SLOTNUM OpCode = 0x4b ) // 0x50 range - 'storage' and execution. @@ -320,6 +321,7 @@ var opCodeToString = [256]string{ BASEFEE: "BASEFEE", BLOBHASH: "BLOBHASH", BLOBBASEFEE: "BLOBBASEFEE", + SLOTNUM: "SLOTNUM", // 0x50 range - 'storage' and execution. POP: "POP", @@ -502,6 +504,7 @@ var stringToOp = map[string]OpCode{ "BASEFEE": BASEFEE, "BLOBHASH": BLOBHASH, "BLOBBASEFEE": BLOBBASEFEE, + "SLOTNUM": SLOTNUM, "DELEGATECALL": DELEGATECALL, "STATICCALL": STATICCALL, "CODESIZE": CODESIZE,