diff --git a/mod/consensus-types/pkg/types/block.go b/mod/consensus-types/pkg/types/block.go index 52036d1a5c..6f0b828b97 100644 --- a/mod/consensus-types/pkg/types/block.go +++ b/mod/consensus-types/pkg/types/block.go @@ -233,8 +233,8 @@ func (b *BeaconBlock) GetHeader() *BeaconBlockHeader { } } -// GetExecutionNumber retrieves the execution number of the BeaconBlock from +// GetTimestamp retrieves the timestamp of the BeaconBlock from // the ExecutionPayload. -func (b *BeaconBlock) GetExecutionNumber() math.U64 { - return b.Body.ExecutionPayload.Number +func (b *BeaconBlock) GetTimestamp() math.U64 { + return b.Body.ExecutionPayload.Timestamp } diff --git a/mod/consensus-types/pkg/types/block_test.go b/mod/consensus-types/pkg/types/block_test.go index 8d2a2b9271..ad4ba20ad1 100644 --- a/mod/consensus-types/pkg/types/block_test.go +++ b/mod/consensus-types/pkg/types/block_test.go @@ -42,7 +42,7 @@ func generateValidBeaconBlock() *types.BeaconBlock { StateRoot: common.Root{5, 4, 3, 2, 1}, Body: &types.BeaconBlockBody{ ExecutionPayload: &types.ExecutionPayload{ - Number: 10, + Timestamp: 10, ExtraData: []byte("dummy extra data for testing"), Transactions: [][]byte{ []byte("tx1"), @@ -101,7 +101,7 @@ func TestBeaconBlock(t *testing.T) { block := generateValidBeaconBlock() require.NotNil(t, block.Body) - require.Equal(t, math.U64(10), block.GetExecutionNumber()) + require.Equal(t, math.U64(10), block.GetTimestamp()) require.Equal(t, version.Deneb, block.Version()) require.False(t, block.IsNil()) diff --git a/mod/node-api/backend/backend.go b/mod/node-api/backend/backend.go index edefe8dea6..3779cda072 100644 --- a/mod/node-api/backend/backend.go +++ b/mod/node-api/backend/backend.go @@ -150,12 +150,12 @@ func (b *Backend[ return b.sb.BlockStore().GetSlotByStateRoot(root) } -// GetSlotByExecutionNumber retrieves the slot by a given execution number from +// GetParentSlotByTimestamp retrieves the parent slot by a given timestamp from // the block store. func (b *Backend[ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, -]) GetSlotByExecutionNumber(executionNumber math.U64) (math.Slot, error) { - return b.sb.BlockStore().GetSlotByExecutionNumber(executionNumber) +]) GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) { + return b.sb.BlockStore().GetParentSlotByTimestamp(timestamp) } // stateFromSlot returns the state at the given slot, after also processing the diff --git a/mod/node-api/backend/mocks/block_store.mock.go b/mod/node-api/backend/mocks/block_store.mock.go index 2dfba3491b..4e532a619f 100644 --- a/mod/node-api/backend/mocks/block_store.mock.go +++ b/mod/node-api/backend/mocks/block_store.mock.go @@ -22,27 +22,27 @@ func (_m *BlockStore[BeaconBlockT]) EXPECT() *BlockStore_Expecter[BeaconBlockT] return &BlockStore_Expecter[BeaconBlockT]{mock: &_m.Mock} } -// GetSlotByBlockRoot provides a mock function with given fields: root -func (_m *BlockStore[BeaconBlockT]) GetSlotByBlockRoot(root common.Root) (math.U64, error) { - ret := _m.Called(root) +// GetParentSlotByTimestamp provides a mock function with given fields: timestamp +func (_m *BlockStore[BeaconBlockT]) GetParentSlotByTimestamp(timestamp math.U64) (math.U64, error) { + ret := _m.Called(timestamp) if len(ret) == 0 { - panic("no return value specified for GetSlotByBlockRoot") + panic("no return value specified for GetParentSlotByTimestamp") } var r0 math.U64 var r1 error - if rf, ok := ret.Get(0).(func(common.Root) (math.U64, error)); ok { - return rf(root) + if rf, ok := ret.Get(0).(func(math.U64) (math.U64, error)); ok { + return rf(timestamp) } - if rf, ok := ret.Get(0).(func(common.Root) math.U64); ok { - r0 = rf(root) + if rf, ok := ret.Get(0).(func(math.U64) math.U64); ok { + r0 = rf(timestamp) } else { r0 = ret.Get(0).(math.U64) } - if rf, ok := ret.Get(1).(func(common.Root) error); ok { - r1 = rf(root) + if rf, ok := ret.Get(1).(func(math.U64) error); ok { + r1 = rf(timestamp) } else { r1 = ret.Error(1) } @@ -50,55 +50,55 @@ func (_m *BlockStore[BeaconBlockT]) GetSlotByBlockRoot(root common.Root) (math.U return r0, r1 } -// BlockStore_GetSlotByBlockRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSlotByBlockRoot' -type BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT any] struct { +// BlockStore_GetParentSlotByTimestamp_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetParentSlotByTimestamp' +type BlockStore_GetParentSlotByTimestamp_Call[BeaconBlockT any] struct { *mock.Call } -// GetSlotByBlockRoot is a helper method to define mock.On call -// - root common.Root -func (_e *BlockStore_Expecter[BeaconBlockT]) GetSlotByBlockRoot(root interface{}) *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT] { - return &BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT]{Call: _e.mock.On("GetSlotByBlockRoot", root)} +// GetParentSlotByTimestamp is a helper method to define mock.On call +// - timestamp math.U64 +func (_e *BlockStore_Expecter[BeaconBlockT]) GetParentSlotByTimestamp(timestamp interface{}) *BlockStore_GetParentSlotByTimestamp_Call[BeaconBlockT] { + return &BlockStore_GetParentSlotByTimestamp_Call[BeaconBlockT]{Call: _e.mock.On("GetParentSlotByTimestamp", timestamp)} } -func (_c *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT]) Run(run func(root common.Root)) *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT] { +func (_c *BlockStore_GetParentSlotByTimestamp_Call[BeaconBlockT]) Run(run func(timestamp math.U64)) *BlockStore_GetParentSlotByTimestamp_Call[BeaconBlockT] { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(common.Root)) + run(args[0].(math.U64)) }) return _c } -func (_c *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT]) Return(_a0 math.U64, _a1 error) *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT] { +func (_c *BlockStore_GetParentSlotByTimestamp_Call[BeaconBlockT]) Return(_a0 math.U64, _a1 error) *BlockStore_GetParentSlotByTimestamp_Call[BeaconBlockT] { _c.Call.Return(_a0, _a1) return _c } -func (_c *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT]) RunAndReturn(run func(common.Root) (math.U64, error)) *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT] { +func (_c *BlockStore_GetParentSlotByTimestamp_Call[BeaconBlockT]) RunAndReturn(run func(math.U64) (math.U64, error)) *BlockStore_GetParentSlotByTimestamp_Call[BeaconBlockT] { _c.Call.Return(run) return _c } -// GetSlotByExecutionNumber provides a mock function with given fields: executionNumber -func (_m *BlockStore[BeaconBlockT]) GetSlotByExecutionNumber(executionNumber math.U64) (math.U64, error) { - ret := _m.Called(executionNumber) +// GetSlotByBlockRoot provides a mock function with given fields: root +func (_m *BlockStore[BeaconBlockT]) GetSlotByBlockRoot(root common.Root) (math.U64, error) { + ret := _m.Called(root) if len(ret) == 0 { - panic("no return value specified for GetSlotByExecutionNumber") + panic("no return value specified for GetSlotByBlockRoot") } var r0 math.U64 var r1 error - if rf, ok := ret.Get(0).(func(math.U64) (math.U64, error)); ok { - return rf(executionNumber) + if rf, ok := ret.Get(0).(func(common.Root) (math.U64, error)); ok { + return rf(root) } - if rf, ok := ret.Get(0).(func(math.U64) math.U64); ok { - r0 = rf(executionNumber) + if rf, ok := ret.Get(0).(func(common.Root) math.U64); ok { + r0 = rf(root) } else { r0 = ret.Get(0).(math.U64) } - if rf, ok := ret.Get(1).(func(math.U64) error); ok { - r1 = rf(executionNumber) + if rf, ok := ret.Get(1).(func(common.Root) error); ok { + r1 = rf(root) } else { r1 = ret.Error(1) } @@ -106,30 +106,30 @@ func (_m *BlockStore[BeaconBlockT]) GetSlotByExecutionNumber(executionNumber mat return r0, r1 } -// BlockStore_GetSlotByExecutionNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSlotByExecutionNumber' -type BlockStore_GetSlotByExecutionNumber_Call[BeaconBlockT any] struct { +// BlockStore_GetSlotByBlockRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSlotByBlockRoot' +type BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT any] struct { *mock.Call } -// GetSlotByExecutionNumber is a helper method to define mock.On call -// - executionNumber math.U64 -func (_e *BlockStore_Expecter[BeaconBlockT]) GetSlotByExecutionNumber(executionNumber interface{}) *BlockStore_GetSlotByExecutionNumber_Call[BeaconBlockT] { - return &BlockStore_GetSlotByExecutionNumber_Call[BeaconBlockT]{Call: _e.mock.On("GetSlotByExecutionNumber", executionNumber)} +// GetSlotByBlockRoot is a helper method to define mock.On call +// - root common.Root +func (_e *BlockStore_Expecter[BeaconBlockT]) GetSlotByBlockRoot(root interface{}) *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT] { + return &BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT]{Call: _e.mock.On("GetSlotByBlockRoot", root)} } -func (_c *BlockStore_GetSlotByExecutionNumber_Call[BeaconBlockT]) Run(run func(executionNumber math.U64)) *BlockStore_GetSlotByExecutionNumber_Call[BeaconBlockT] { +func (_c *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT]) Run(run func(root common.Root)) *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT] { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(math.U64)) + run(args[0].(common.Root)) }) return _c } -func (_c *BlockStore_GetSlotByExecutionNumber_Call[BeaconBlockT]) Return(_a0 math.U64, _a1 error) *BlockStore_GetSlotByExecutionNumber_Call[BeaconBlockT] { +func (_c *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT]) Return(_a0 math.U64, _a1 error) *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT] { _c.Call.Return(_a0, _a1) return _c } -func (_c *BlockStore_GetSlotByExecutionNumber_Call[BeaconBlockT]) RunAndReturn(run func(math.U64) (math.U64, error)) *BlockStore_GetSlotByExecutionNumber_Call[BeaconBlockT] { +func (_c *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT]) RunAndReturn(run func(common.Root) (math.U64, error)) *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT] { _c.Call.Return(run) return _c } diff --git a/mod/node-api/backend/types.go b/mod/node-api/backend/types.go index 0ae940772f..44e26ff4f7 100644 --- a/mod/node-api/backend/types.go +++ b/mod/node-api/backend/types.go @@ -82,8 +82,8 @@ type BlockStore[BeaconBlockT any] interface { GetSlotByBlockRoot(root common.Root) (math.Slot, error) // GetSlotByStateRoot retrieves the slot by a given state root. GetSlotByStateRoot(root common.Root) (math.Slot, error) - // GetSlotByExecutionNumber retrieves the slot by a given execution number. - GetSlotByExecutionNumber(executionNumber math.U64) (math.Slot, error) + // GetParentSlotByTimestamp retrieves the parent slot by a given timestamp. + GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) } // DepositStore defines the interface for deposit storage. diff --git a/mod/node-api/engines/echo/vaildator.go b/mod/node-api/engines/echo/vaildator.go index 8792cfbacf..0031ee4aad 100644 --- a/mod/node-api/engines/echo/vaildator.go +++ b/mod/node-api/engines/echo/vaildator.go @@ -62,7 +62,7 @@ func ConstructValidator() *validator.Validate { validators := map[string](func(fl validator.FieldLevel) bool){ "state_id": ValidateStateID, "block_id": ValidateBlockID, - "execution_id": ValidateExecutionID, + "timestamp_id": ValidateTimestampID, "validator_id": ValidateValidatorID, "epoch": ValidateUint64, "slot": ValidateUint64, @@ -96,7 +96,7 @@ func ValidateBlockID(fl validator.FieldLevel) bool { return validateStateBlockIDs(fl.Field().String(), allowedValues) } -func ValidateExecutionID(fl validator.FieldLevel) bool { +func ValidateTimestampID(fl validator.FieldLevel) bool { allowedValues := map[string]bool{ utils.StateIDHead: true, utils.StateIDGenesis: true, @@ -105,7 +105,7 @@ func ValidateExecutionID(fl validator.FieldLevel) bool { } value := fl.Field().String() - if utils.IsExecutionNumberPrefix(value) { + if utils.IsTimestampIDPrefix(value) { return ValidateUint64Dec(value[1:]) } diff --git a/mod/node-api/handlers/proof/backend.go b/mod/node-api/handlers/proof/backend.go index 376c039206..7aaa90ecb3 100644 --- a/mod/node-api/handlers/proof/backend.go +++ b/mod/node-api/handlers/proof/backend.go @@ -28,7 +28,7 @@ import ( type Backend[BeaconBlockHeaderT, BeaconStateT, ValidatorT any] interface { BlockBackend[BeaconBlockHeaderT] StateBackend[BeaconStateT] - GetSlotByExecutionNumber(executionNumber math.U64) (math.Slot, error) + GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) } type BlockBackend[BeaconBlockHeaderT any] interface { diff --git a/mod/node-api/handlers/proof/block_proposer.go b/mod/node-api/handlers/proof/block_proposer.go index 234f521091..a252ff9308 100644 --- a/mod/node-api/handlers/proof/block_proposer.go +++ b/mod/node-api/handlers/proof/block_proposer.go @@ -26,8 +26,9 @@ import ( "github.com/berachain/beacon-kit/mod/node-api/handlers/utils" ) -// GetBlockProposer returns the block proposer pubkey for the given block id -// along with a merkle proof that can be verified against the beacon block root. +// GetBlockProposer returns the block proposer pubkey for the given timestamp +// id along with a merkle proof that can be verified against the beacon block +// root. func (h *Handler[ BeaconBlockHeaderT, _, _, ContextT, _, _, ]) GetBlockProposer(c ContextT) (any, error) { @@ -37,8 +38,8 @@ func (h *Handler[ if err != nil { return nil, err } - slot, beaconState, blockHeader, err := h.resolveExecutionID( - params.ExecutionID, + slot, beaconState, blockHeader, err := h.resolveTimestampID( + params.TimestampID, ) if err != nil { return nil, err diff --git a/mod/node-api/handlers/proof/execution_fee_recipient.go b/mod/node-api/handlers/proof/execution_fee_recipient.go index 0617207bb6..1513d3a047 100644 --- a/mod/node-api/handlers/proof/execution_fee_recipient.go +++ b/mod/node-api/handlers/proof/execution_fee_recipient.go @@ -27,7 +27,7 @@ import ( ) // GetExecutionFeeRecipient returns the fee recipient from the latest execution -// payload header for the given block id, along with the proof that can be +// payload header for the given timestamp id, along with the proof that can be // verified against the beacon block root. func (h *Handler[ BeaconBlockHeaderT, _, _, ContextT, _, _, @@ -38,8 +38,8 @@ func (h *Handler[ if err != nil { return nil, err } - slot, beaconState, blockHeader, err := h.resolveExecutionID( - params.ExecutionID, + slot, beaconState, blockHeader, err := h.resolveTimestampID( + params.TimestampID, ) if err != nil { return nil, err diff --git a/mod/node-api/handlers/proof/execution_number.go b/mod/node-api/handlers/proof/execution_number.go index 1fe9e4a8f9..4c128de2cf 100644 --- a/mod/node-api/handlers/proof/execution_number.go +++ b/mod/node-api/handlers/proof/execution_number.go @@ -27,7 +27,7 @@ import ( ) // GetExecutionNumber returns the block number from the latest execution -// payload header for the given block id, along with the proof that can be +// payload header for the given timestamp id, along with the proof that can be // verified against the beacon block root. func (h *Handler[ BeaconBlockHeaderT, _, _, ContextT, _, _, @@ -38,8 +38,8 @@ func (h *Handler[ if err != nil { return nil, err } - slot, beaconState, blockHeader, err := h.resolveExecutionID( - params.ExecutionID, + slot, beaconState, blockHeader, err := h.resolveTimestampID( + params.TimestampID, ) if err != nil { return nil, err diff --git a/mod/node-api/handlers/proof/handler.go b/mod/node-api/handlers/proof/handler.go index c70eba6e52..d96dfc8f0f 100644 --- a/mod/node-api/handlers/proof/handler.go +++ b/mod/node-api/handlers/proof/handler.go @@ -71,11 +71,11 @@ func NewHandler[ return h } -// Get the slot from the given input of execution id, beacon state, and beacon +// Get the slot from the given input of timestamp id, beacon state, and beacon // block header for the resolved slot. func (h *Handler[ BeaconBlockHeaderT, BeaconStateT, _, _, _, _, -]) resolveExecutionID(executionID string) ( +]) resolveTimestampID(timestampID string) ( math.Slot, BeaconStateT, BeaconBlockHeaderT, error, ) { var ( @@ -83,7 +83,7 @@ func (h *Handler[ blockHeader BeaconBlockHeaderT ) - slot, err := utils.SlotFromExecutionID(executionID, h.backend) + slot, err := utils.ParentSlotFromTimestampID(timestampID, h.backend) if err != nil { return 0, beaconState, blockHeader, err } diff --git a/mod/node-api/handlers/proof/types/request.go b/mod/node-api/handlers/proof/types/request.go index 9d782025a2..649543c541 100644 --- a/mod/node-api/handlers/proof/types/request.go +++ b/mod/node-api/handlers/proof/types/request.go @@ -23,19 +23,19 @@ package types import "github.com/berachain/beacon-kit/mod/node-api/handlers/types" // BlockProposerRequest is the request for the -// `/proof/block_proposer/{execution_id}` endpoint. +// `/proof/block_proposer/{timestamp_id}` endpoint. type BlockProposerRequest struct { - types.ExecutionIDRequest + types.TimestampIDRequest } // ExecutionNumberRequest is the request for the -// `/proof/execution_number/{execution_id}` endpoint. +// `/proof/execution_number/{timestamp_id}` endpoint. type ExecutionNumberRequest struct { - types.ExecutionIDRequest + types.TimestampIDRequest } // ExecutionFeeRecipientRequest is the request for the -// `/proof/execution_fee_recipient/{execution_id}` endpoint. +// `/proof/execution_fee_recipient/{timestamp_id}` endpoint. type ExecutionFeeRecipientRequest struct { - types.ExecutionIDRequest + types.TimestampIDRequest } diff --git a/mod/node-api/handlers/types/request.go b/mod/node-api/handlers/types/request.go index 81df7c22a7..7d2c81aa7f 100644 --- a/mod/node-api/handlers/types/request.go +++ b/mod/node-api/handlers/types/request.go @@ -28,6 +28,6 @@ type BlockIDRequest struct { BlockID string `param:"block_id" validate:"required,block_id"` } -type ExecutionIDRequest struct { - ExecutionID string `param:"execution_id" validate:"required,execution_id"` +type TimestampIDRequest struct { + TimestampID string `param:"timestamp_id" validate:"required,timestamp_id"` } diff --git a/mod/node-api/handlers/utils/constants.go b/mod/node-api/handlers/utils/constants.go index 6f9025223e..63b5a91e6b 100644 --- a/mod/node-api/handlers/utils/constants.go +++ b/mod/node-api/handlers/utils/constants.go @@ -27,7 +27,7 @@ const ( StateIDFinalized = "finalized" StateIDJustified = "justified" StateIDHead = "head" - ExecutionIDPrefix = "n" + TimestampIDPrefix = "t" ) const ( diff --git a/mod/node-api/handlers/utils/id.go b/mod/node-api/handlers/utils/id.go index eced1532f9..a9ed206910 100644 --- a/mod/node-api/handlers/utils/id.go +++ b/mod/node-api/handlers/utils/id.go @@ -24,6 +24,7 @@ import ( "strconv" "strings" + "github.com/berachain/beacon-kit/mod/errors" "github.com/berachain/beacon-kit/mod/primitives/pkg/common" "github.com/berachain/beacon-kit/mod/primitives/pkg/math" ) @@ -70,36 +71,39 @@ func SlotFromBlockID[StorageBackendT interface { return storage.GetSlotByBlockRoot(root) } -// SlotFromExecutionID returns a slot from the execution number ID. +// ParentSlotFromTimestampID returns the parent slot corresponding to the +// timestamp ID. // -// NOTE: `executionID` shares the same semantics as `stateID`, with the -// modification of being able to query by beacon block -// instead of . +// NOTE: `timestampID` shares the same semantics as `stateID`, with the +// modification of being able to query by next block's instead of +// the current block's . // -// The must be prefixed by the 'n', followed by the execution -// number in decimal notation. For example 'n1722463215' corresponds to -// the slot with execution number 1722463215. Providing just the string -// '1722463215' (without the prefix 'n') will query for the beacon block with -// slot 1722463215. -func SlotFromExecutionID[StorageBackendT interface { - GetSlotByExecutionNumber(executionNumber math.U64) (math.Slot, error) -}](executionID string, storage StorageBackendT) (math.Slot, error) { - if !IsExecutionNumberPrefix(executionID) { - return slotFromStateID(executionID) +// The must be prefixed by the 't', followed by the timestamp +// in decimal UNIX notation. For example 't1728681738' corresponds to the slot +// which has the next block with a timestamp of 1728681738. Providing just the +// string '1728681738' (without the prefix 't') will query for the beacon block +// for slot 1728681738. +func ParentSlotFromTimestampID[StorageBackendT interface { + GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) +}](timestampID string, storage StorageBackendT) (math.Slot, error) { + if !IsTimestampIDPrefix(timestampID) { + return slotFromStateID(timestampID) } - // Parse the execution number from the executionID. - executionNumber, err := U64FromString(executionID[1:]) + // Parse the timestamp from the timestampID. + timestamp, err := U64FromString(timestampID[1:]) if err != nil { - return 0, err + return 0, errors.Wrapf( + err, "failed to parse timestamp from timestampID: %s", timestampID, + ) } - return storage.GetSlotByExecutionNumber(executionNumber) + return storage.GetParentSlotByTimestamp(timestamp) } -// IsExecutionNumberPrefix checks if the given executionID is prefixed -// with the execution number prefix. -func IsExecutionNumberPrefix(executionID string) bool { - return strings.HasPrefix(executionID, ExecutionIDPrefix) +// IsTimestampIDPrefix checks if the given timestampID is prefixed with the +// correct prefix 't'. +func IsTimestampIDPrefix(timestampID string) bool { + return strings.HasPrefix(timestampID, TimestampIDPrefix) } // U64FromString returns a math.U64 from the given string. Errors if the given diff --git a/mod/node-core/pkg/components/interfaces.go b/mod/node-core/pkg/components/interfaces.go index 62b275b576..370ae20f27 100644 --- a/mod/node-core/pkg/components/interfaces.go +++ b/mod/node-core/pkg/components/interfaces.go @@ -113,7 +113,9 @@ type ( GetParentBlockRoot() common.Root // GetStateRoot returns the state root of the block. GetStateRoot() common.Root - GetExecutionNumber() math.U64 + // GetTimestamp returns the timestamp of the block from the execution + // payload. + GetTimestamp() math.U64 } // BeaconBlockBody represents a generic interface for the body of a beacon @@ -293,10 +295,9 @@ type ( GetSlotByBlockRoot(root common.Root) (math.Slot, error) // GetSlotByStateRoot retrieves the slot by a given root from the store. GetSlotByStateRoot(root common.Root) (math.Slot, error) - // GetSlotByExecutionNumber retrieves the slot by a given execution - // number - // from the store. - GetSlotByExecutionNumber(executionNumber math.U64) (math.Slot, error) + // GetParentSlotByTimestamp retrieves the parent slot by a given + // timestamp from the store. + GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) } ConsensusEngine interface { @@ -1090,7 +1091,7 @@ type ( ChainSpec() common.ChainSpec GetSlotByBlockRoot(root common.Root) (math.Slot, error) GetSlotByStateRoot(root common.Root) (math.Slot, error) - GetSlotByExecutionNumber(executionNumber math.U64) (math.Slot, error) + GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) NodeAPIBeaconBackend[ BeaconStateT, BeaconBlockHeaderT, ForkT, ValidatorT, @@ -1122,7 +1123,7 @@ type ( ] interface { BlockBackend[BeaconBlockHeaderT] StateBackend[BeaconStateT, ForkT] - GetSlotByExecutionNumber(executionNumber math.U64) (math.Slot, error) + GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) } GenesisBackend interface { diff --git a/mod/storage/pkg/block/store.go b/mod/storage/pkg/block/store.go index 3e1c069ec9..a309d81b3c 100644 --- a/mod/storage/pkg/block/store.go +++ b/mod/storage/pkg/block/store.go @@ -23,6 +23,7 @@ package block import ( "fmt" + "github.com/berachain/beacon-kit/mod/errors" "github.com/berachain/beacon-kit/mod/log" "github.com/berachain/beacon-kit/mod/primitives/pkg/common" "github.com/berachain/beacon-kit/mod/primitives/pkg/math" @@ -32,10 +33,18 @@ import ( // KVStore is a simple memory store based implementation that stores metadata of // beacon blocks. type KVStore[BeaconBlockT BeaconBlock] struct { - blockRoots *lru.Cache[common.Root, math.Slot] - executionNumbers *lru.Cache[math.U64, math.Slot] - stateRoots *lru.Cache[common.Root, math.Slot] + // Beacon block root to slot mapping is injective for finalized blocks. + blockRoots *lru.Cache[common.Root, math.Slot] + // Timestamp to slot mapping is injective for finalized blocks. This is + // guaranteed by CometBFT consensus. So each slot will be associated with a + // different timestamp (no overwriting) as we store only finalized blocks. + timestamps *lru.Cache[math.U64, math.Slot] + + // Beacon state root to slot mapping is injective for finalized blocks. + stateRoots *lru.Cache[common.Root, math.Slot] + + // Logger for the store. logger log.Logger } @@ -48,7 +57,7 @@ func NewStore[BeaconBlockT BeaconBlock]( if err != nil { panic(err) } - executionNumbers, err := lru.New[math.U64, math.Slot](availabilityWindow) + timestamps, err := lru.New[math.U64, math.Slot](availabilityWindow) if err != nil { panic(err) } @@ -57,20 +66,20 @@ func NewStore[BeaconBlockT BeaconBlock]( panic(err) } return &KVStore[BeaconBlockT]{ - blockRoots: blockRoots, - executionNumbers: executionNumbers, - stateRoots: stateRoots, - logger: logger, + blockRoots: blockRoots, + timestamps: timestamps, + stateRoots: stateRoots, + logger: logger, } } // Set sets the block by a given index in the store, storing the block root, -// execution number, and state root. Only this function may potentially evict +// timestamp, and state root. Only this function may potentially evict // entries from the store if the availability window is reached. func (kv *KVStore[BeaconBlockT]) Set(blk BeaconBlockT) error { slot := blk.GetSlot() kv.blockRoots.Add(blk.HashTreeRoot(), slot) - kv.executionNumbers.Add(blk.GetExecutionNumber(), slot) + kv.timestamps.Add(blk.GetTimestamp(), slot) kv.stateRoots.Add(blk.GetStateRoot(), slot) return nil } @@ -86,19 +95,20 @@ func (kv *KVStore[BeaconBlockT]) GetSlotByBlockRoot( return slot, nil } -// GetSlotByExecutionNumber retrieves the slot by a given execution number from +// GetParentSlotByTimestamp retrieves the parent slot by a given timestamp from // the store. -func (kv *KVStore[BeaconBlockT]) GetSlotByExecutionNumber( - executionNumber math.U64, +func (kv *KVStore[BeaconBlockT]) GetParentSlotByTimestamp( + timestamp math.U64, ) (math.Slot, error) { - slot, ok := kv.executionNumbers.Peek(executionNumber) + slot, ok := kv.timestamps.Peek(timestamp) if !ok { - return 0, fmt.Errorf( - "slot not found at execution number: %d", - executionNumber, - ) + return slot, fmt.Errorf("slot not found at timestamp: %d", timestamp) } - return slot, nil + if slot == 0 { + return slot, errors.New("parent slot not supported for genesis slot 0") + } + + return slot - 1, nil } // GetSlotByStateRoot retrieves the slot by a given state root from the store. diff --git a/mod/storage/pkg/block/store_test.go b/mod/storage/pkg/block/store_test.go index e41553b7b4..14de7a5fef 100644 --- a/mod/storage/pkg/block/store_test.go +++ b/mod/storage/pkg/block/store_test.go @@ -42,7 +42,7 @@ func (m MockBeaconBlock) HashTreeRoot() common.Root { return [32]byte{byte(m.slot)} } -func (m MockBeaconBlock) GetExecutionNumber() math.U64 { +func (m MockBeaconBlock) GetTimestamp() math.U64 { return m.slot } @@ -65,15 +65,15 @@ func TestBlockStore(t *testing.T) { require.NoError(t, err) } - // Get the slots by roots & execution numbers. + // Get the slots by roots & timestamps. for i := math.Slot(3); i <= 7; i++ { slot, err = blockStore.GetSlotByBlockRoot([32]byte{byte(i)}) require.NoError(t, err) require.Equal(t, i, slot) - slot, err = blockStore.GetSlotByExecutionNumber(i) + slot, err = blockStore.GetParentSlotByTimestamp(i) require.NoError(t, err) - require.Equal(t, i, slot) + require.Equal(t, i-1, slot) slot, err = blockStore.GetSlotByStateRoot([32]byte{byte(i)}) require.NoError(t, err) @@ -83,6 +83,6 @@ func TestBlockStore(t *testing.T) { // Try getting a slot that doesn't exist. _, err = blockStore.GetSlotByBlockRoot([32]byte{byte(8)}) require.ErrorContains(t, err, "not found") - _, err = blockStore.GetSlotByExecutionNumber(2) + _, err = blockStore.GetParentSlotByTimestamp(2) require.ErrorContains(t, err, "not found") } diff --git a/mod/storage/pkg/block/types.go b/mod/storage/pkg/block/types.go index 07afd76035..3b02a2a9ec 100644 --- a/mod/storage/pkg/block/types.go +++ b/mod/storage/pkg/block/types.go @@ -26,10 +26,10 @@ import ( ) // BeaconBlock is a block in the beacon chain that has a slot, block root (hash -// tree root), execution number, and state root. +// tree root), timestamp, and state root. type BeaconBlock interface { GetSlot() math.U64 HashTreeRoot() common.Root - GetExecutionNumber() math.U64 + GetTimestamp() math.U64 GetStateRoot() common.Root }