From 0eec40047b4f5e37753a622f374e942577ea7d79 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Fri, 11 Oct 2024 17:39:20 -0400 Subject: [PATCH 1/9] feat(node-api): use timestamp ID instead of execution ID for proof namespace --- mod/consensus-types/pkg/types/block.go | 6 +-- mod/consensus-types/pkg/types/block_test.go | 3 +- mod/node-api/backend/backend.go | 6 +-- mod/node-api/backend/types.go | 4 +- mod/node-api/engines/echo/vaildator.go | 6 +-- mod/node-api/handlers/proof/backend.go | 2 +- mod/node-api/handlers/proof/block_proposer.go | 4 +- .../handlers/proof/execution_fee_recipient.go | 4 +- .../handlers/proof/execution_number.go | 4 +- mod/node-api/handlers/proof/handler.go | 6 +-- mod/node-api/handlers/proof/types/request.go | 12 +++--- mod/node-api/handlers/types/request.go | 4 +- mod/node-api/handlers/utils/constants.go | 2 +- mod/node-api/handlers/utils/id.go | 41 +++++++++---------- mod/node-core/pkg/components/interfaces.go | 12 +++--- mod/storage/pkg/block/store.go | 34 +++++++-------- mod/storage/pkg/block/store_test.go | 6 +-- mod/storage/pkg/block/types.go | 4 +- 18 files changed, 79 insertions(+), 81 deletions(-) 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..9da54a2e4b 100644 --- a/mod/consensus-types/pkg/types/block_test.go +++ b/mod/consensus-types/pkg/types/block_test.go @@ -43,6 +43,7 @@ func generateValidBeaconBlock() *types.BeaconBlock { Body: &types.BeaconBlockBody{ ExecutionPayload: &types.ExecutionPayload{ Number: 10, + Timestamp: 10, ExtraData: []byte("dummy extra data for testing"), Transactions: [][]byte{ []byte("tx1"), @@ -101,7 +102,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..4b5165c342 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 +// GetSlotByTimestamp retrieves the 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) +]) GetSlotByTimestamp(timestamp math.U64) (math.Slot, error) { + return b.sb.BlockStore().GetSlotByTimestamp(timestamp) } // stateFromSlot returns the state at the given slot, after also processing the diff --git a/mod/node-api/backend/types.go b/mod/node-api/backend/types.go index 0ae940772f..7eb7c67c60 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) + // GetSlotByTimestamp retrieves the slot by a given timestamp. + GetSlotByTimestamp(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..d1b2c9386f 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, + "execution_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..e6d84b7938 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) + GetSlotByTimestamp(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..c7e141db7a 100644 --- a/mod/node-api/handlers/proof/block_proposer.go +++ b/mod/node-api/handlers/proof/block_proposer.go @@ -37,8 +37,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..5e4864931d 100644 --- a/mod/node-api/handlers/proof/execution_fee_recipient.go +++ b/mod/node-api/handlers/proof/execution_fee_recipient.go @@ -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..1bb1d58ee5 100644 --- a/mod/node-api/handlers/proof/execution_number.go +++ b/mod/node-api/handlers/proof/execution_number.go @@ -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..c944766b28 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.SlotFromTimestampID(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..93e7a5a0fb 100644 --- a/mod/node-api/handlers/utils/id.go +++ b/mod/node-api/handlers/utils/id.go @@ -70,36 +70,35 @@ func SlotFromBlockID[StorageBackendT interface { return storage.GetSlotByBlockRoot(root) } -// SlotFromExecutionID returns a slot from the execution number ID. +// SlotFromTimestampID returns a slot from the block 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 block instead of +// . // -// 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 notation. For example 't1728681738' corresponds to the slot with +// timestamp 1728681738. Providing just the string '1728681738' (without the +// prefix 't') will query for the beacon block with slot 1728681738. +func SlotFromTimestampID[StorageBackendT interface { + GetSlotByTimestamp(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 storage.GetSlotByExecutionNumber(executionNumber) + return storage.GetSlotByTimestamp(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..8fabc29070 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,10 @@ 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 + // GetSlotByTimestamp retrieves the slot by a given execution // number // from the store. - GetSlotByExecutionNumber(executionNumber math.U64) (math.Slot, error) + GetSlotByTimestamp(executionNumber math.U64) (math.Slot, error) } ConsensusEngine interface { @@ -1090,7 +1092,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) + GetSlotByTimestamp(executionNumber math.U64) (math.Slot, error) NodeAPIBeaconBackend[ BeaconStateT, BeaconBlockHeaderT, ForkT, ValidatorT, @@ -1122,7 +1124,7 @@ type ( ] interface { BlockBackend[BeaconBlockHeaderT] StateBackend[BeaconStateT, ForkT] - GetSlotByExecutionNumber(executionNumber math.U64) (math.Slot, error) + GetSlotByTimestamp(executionNumber 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..26976814ab 100644 --- a/mod/storage/pkg/block/store.go +++ b/mod/storage/pkg/block/store.go @@ -32,9 +32,9 @@ 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] + blockRoots *lru.Cache[common.Root, math.Slot] + timestamps *lru.Cache[math.U64, math.Slot] + stateRoots *lru.Cache[common.Root, math.Slot] logger log.Logger } @@ -48,7 +48,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 +57,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,17 +86,13 @@ func (kv *KVStore[BeaconBlockT]) GetSlotByBlockRoot( return slot, nil } -// GetSlotByExecutionNumber retrieves the slot by a given execution number from -// the store. -func (kv *KVStore[BeaconBlockT]) GetSlotByExecutionNumber( - executionNumber math.U64, +// GetSlotByTimestamp retrieves the slot by a given timestamp from the store. +func (kv *KVStore[BeaconBlockT]) GetSlotByTimestamp( + 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 0, fmt.Errorf("slot not found at timestamp: %d", timestamp) } return slot, nil } diff --git a/mod/storage/pkg/block/store_test.go b/mod/storage/pkg/block/store_test.go index e41553b7b4..9e4dd00ac6 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 } @@ -71,7 +71,7 @@ func TestBlockStore(t *testing.T) { require.NoError(t, err) require.Equal(t, i, slot) - slot, err = blockStore.GetSlotByExecutionNumber(i) + slot, err = blockStore.GetSlotByTimestamp(i) require.NoError(t, err) require.Equal(t, i, slot) @@ -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.GetSlotByTimestamp(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 } From be58e454453ec9ddd777d3141e0a0175b243ff09 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Fri, 11 Oct 2024 17:48:37 -0400 Subject: [PATCH 2/9] gen --- .../backend/mocks/block_store.mock.go | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/mod/node-api/backend/mocks/block_store.mock.go b/mod/node-api/backend/mocks/block_store.mock.go index e19547d3e9..47ac3f3ca4 100644 --- a/mod/node-api/backend/mocks/block_store.mock.go +++ b/mod/node-api/backend/mocks/block_store.mock.go @@ -78,27 +78,27 @@ func (_c *BlockStore_GetSlotByBlockRoot_Call[BeaconBlockT]) RunAndReturn(run fun 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) +// GetSlotByStateRoot provides a mock function with given fields: root +func (_m *BlockStore[BeaconBlockT]) GetSlotByStateRoot(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 GetSlotByStateRoot") } 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,55 +106,55 @@ 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_GetSlotByStateRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSlotByStateRoot' +type BlockStore_GetSlotByStateRoot_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)} +// GetSlotByStateRoot is a helper method to define mock.On call +// - root common.Root +func (_e *BlockStore_Expecter[BeaconBlockT]) GetSlotByStateRoot(root interface{}) *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT] { + return &BlockStore_GetSlotByStateRoot_Call[BeaconBlockT]{Call: _e.mock.On("GetSlotByStateRoot", root)} } -func (_c *BlockStore_GetSlotByExecutionNumber_Call[BeaconBlockT]) Run(run func(executionNumber math.U64)) *BlockStore_GetSlotByExecutionNumber_Call[BeaconBlockT] { +func (_c *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT]) Run(run func(root common.Root)) *BlockStore_GetSlotByStateRoot_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_GetSlotByStateRoot_Call[BeaconBlockT]) Return(_a0 math.U64, _a1 error) *BlockStore_GetSlotByStateRoot_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_GetSlotByStateRoot_Call[BeaconBlockT]) RunAndReturn(run func(common.Root) (math.U64, error)) *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT] { _c.Call.Return(run) return _c } -// GetSlotByStateRoot provides a mock function with given fields: root -func (_m *BlockStore[BeaconBlockT]) GetSlotByStateRoot(root common.Root) (math.U64, error) { - ret := _m.Called(root) +// GetSlotByTimestamp provides a mock function with given fields: timestamp +func (_m *BlockStore[BeaconBlockT]) GetSlotByTimestamp(timestamp math.U64) (math.U64, error) { + ret := _m.Called(timestamp) if len(ret) == 0 { - panic("no return value specified for GetSlotByStateRoot") + panic("no return value specified for GetSlotByTimestamp") } 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) } @@ -162,30 +162,30 @@ func (_m *BlockStore[BeaconBlockT]) GetSlotByStateRoot(root common.Root) (math.U return r0, r1 } -// BlockStore_GetSlotByStateRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSlotByStateRoot' -type BlockStore_GetSlotByStateRoot_Call[BeaconBlockT any] struct { +// BlockStore_GetSlotByTimestamp_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSlotByTimestamp' +type BlockStore_GetSlotByTimestamp_Call[BeaconBlockT any] struct { *mock.Call } -// GetSlotByStateRoot is a helper method to define mock.On call -// - root common.Root -func (_e *BlockStore_Expecter[BeaconBlockT]) GetSlotByStateRoot(root interface{}) *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT] { - return &BlockStore_GetSlotByStateRoot_Call[BeaconBlockT]{Call: _e.mock.On("GetSlotByStateRoot", root)} +// GetSlotByTimestamp is a helper method to define mock.On call +// - timestamp math.U64 +func (_e *BlockStore_Expecter[BeaconBlockT]) GetSlotByTimestamp(timestamp interface{}) *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT] { + return &BlockStore_GetSlotByTimestamp_Call[BeaconBlockT]{Call: _e.mock.On("GetSlotByTimestamp", timestamp)} } -func (_c *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT]) Run(run func(root common.Root)) *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT] { +func (_c *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT]) Run(run func(timestamp math.U64)) *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT] { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(common.Root)) + run(args[0].(math.U64)) }) return _c } -func (_c *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT]) Return(_a0 math.U64, _a1 error) *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT] { +func (_c *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT]) Return(_a0 math.U64, _a1 error) *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT] { _c.Call.Return(_a0, _a1) return _c } -func (_c *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT]) RunAndReturn(run func(common.Root) (math.U64, error)) *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT] { +func (_c *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT]) RunAndReturn(run func(math.U64) (math.U64, error)) *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT] { _c.Call.Return(run) return _c } From 3c6b004634f60d4d63520f404710ef279cea67ec Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Sat, 12 Oct 2024 16:12:52 -0400 Subject: [PATCH 3/9] parent slot --- mod/node-api/backend/backend.go | 6 +++--- mod/node-api/backend/types.go | 4 ++-- mod/node-api/handlers/proof/backend.go | 2 +- mod/node-api/handlers/proof/handler.go | 2 +- mod/node-api/handlers/utils/id.go | 15 ++++++++------- mod/node-core/pkg/components/interfaces.go | 11 +++++------ mod/storage/pkg/block/store.go | 16 ++++++++++------ mod/storage/pkg/block/store_test.go | 4 ++-- 8 files changed, 32 insertions(+), 28 deletions(-) diff --git a/mod/node-api/backend/backend.go b/mod/node-api/backend/backend.go index 4b5165c342..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) } -// GetSlotByTimestamp retrieves the slot by a given timestamp from +// GetParentSlotByTimestamp retrieves the parent slot by a given timestamp from // the block store. func (b *Backend[ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, -]) GetSlotByTimestamp(timestamp math.U64) (math.Slot, error) { - return b.sb.BlockStore().GetSlotByTimestamp(timestamp) +]) 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/types.go b/mod/node-api/backend/types.go index 7eb7c67c60..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) - // GetSlotByTimestamp retrieves the slot by a given timestamp. - GetSlotByTimestamp(timestamp 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/handlers/proof/backend.go b/mod/node-api/handlers/proof/backend.go index e6d84b7938..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] - GetSlotByTimestamp(timestamp 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/handler.go b/mod/node-api/handlers/proof/handler.go index c944766b28..d96dfc8f0f 100644 --- a/mod/node-api/handlers/proof/handler.go +++ b/mod/node-api/handlers/proof/handler.go @@ -83,7 +83,7 @@ func (h *Handler[ blockHeader BeaconBlockHeaderT ) - slot, err := utils.SlotFromTimestampID(timestampID, h.backend) + slot, err := utils.ParentSlotFromTimestampID(timestampID, h.backend) if err != nil { return 0, beaconState, blockHeader, err } diff --git a/mod/node-api/handlers/utils/id.go b/mod/node-api/handlers/utils/id.go index 93e7a5a0fb..25469c8a1e 100644 --- a/mod/node-api/handlers/utils/id.go +++ b/mod/node-api/handlers/utils/id.go @@ -70,18 +70,19 @@ func SlotFromBlockID[StorageBackendT interface { return storage.GetSlotByBlockRoot(root) } -// SlotFromTimestampID returns a slot from the block timestamp ID. +// ParentSlotFromTimestampID returns the slot from the block timestamp ID. // // NOTE: `timestampID` shares the same semantics as `stateID`, with the -// modification of being able to query by block instead of +// modification of being able to query by next block instead of // . // // The must be prefixed by the 't', followed by the timestamp // in decimal notation. For example 't1728681738' corresponds to the slot with -// timestamp 1728681738. Providing just the string '1728681738' (without the -// prefix 't') will query for the beacon block with slot 1728681738. -func SlotFromTimestampID[StorageBackendT interface { - GetSlotByTimestamp(timestamp math.U64) (math.Slot, error) +// next block timestamp of 1728681738. Providing just the string '1728681738' +// (without the prefix 't') will query for the beacon block with 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) @@ -92,7 +93,7 @@ func SlotFromTimestampID[StorageBackendT interface { if err != nil { return 0, err } - return storage.GetSlotByTimestamp(timestamp) + return storage.GetParentSlotByTimestamp(timestamp) } // IsTimestampIDPrefix checks if the given timestampID is prefixed with the diff --git a/mod/node-core/pkg/components/interfaces.go b/mod/node-core/pkg/components/interfaces.go index 8fabc29070..594a19e954 100644 --- a/mod/node-core/pkg/components/interfaces.go +++ b/mod/node-core/pkg/components/interfaces.go @@ -295,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) - // GetSlotByTimestamp retrieves the slot by a given execution - // number - // from the store. - GetSlotByTimestamp(executionNumber math.U64) (math.Slot, error) + // GetParentSlotByTimestamp retrieves the parent slot by a given + // timestamp from the store. + GetParentSlotByTimestamp(executionNumber math.U64) (math.Slot, error) } ConsensusEngine interface { @@ -1092,7 +1091,7 @@ type ( ChainSpec() common.ChainSpec GetSlotByBlockRoot(root common.Root) (math.Slot, error) GetSlotByStateRoot(root common.Root) (math.Slot, error) - GetSlotByTimestamp(executionNumber math.U64) (math.Slot, error) + GetParentSlotByTimestamp(executionNumber math.U64) (math.Slot, error) NodeAPIBeaconBackend[ BeaconStateT, BeaconBlockHeaderT, ForkT, ValidatorT, @@ -1124,7 +1123,7 @@ type ( ] interface { BlockBackend[BeaconBlockHeaderT] StateBackend[BeaconStateT, ForkT] - GetSlotByTimestamp(executionNumber math.U64) (math.Slot, error) + GetParentSlotByTimestamp(executionNumber math.U64) (math.Slot, error) } GenesisBackend interface { diff --git a/mod/storage/pkg/block/store.go b/mod/storage/pkg/block/store.go index 26976814ab..dadd1e4bcc 100644 --- a/mod/storage/pkg/block/store.go +++ b/mod/storage/pkg/block/store.go @@ -86,15 +86,19 @@ func (kv *KVStore[BeaconBlockT]) GetSlotByBlockRoot( return slot, nil } -// GetSlotByTimestamp retrieves the slot by a given timestamp from the store. -func (kv *KVStore[BeaconBlockT]) GetSlotByTimestamp( +// GetParentSlotByTimestamp retrieves the parent slot by a given timestamp from +// the store. +func (kv *KVStore[BeaconBlockT]) GetParentSlotByTimestamp( timestamp math.U64, ) (math.Slot, error) { - slot, ok := kv.timestamps.Peek(timestamp) - if !ok { - return 0, fmt.Errorf("slot not found at timestamp: %d", timestamp) + slot, _ := kv.timestamps.Peek(timestamp) + if slot == 0 { + return slot, fmt.Errorf( + "parent slot not found at timestamp: %d", timestamp, + ) } - return slot, nil + + 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 9e4dd00ac6..6416a463f6 100644 --- a/mod/storage/pkg/block/store_test.go +++ b/mod/storage/pkg/block/store_test.go @@ -71,7 +71,7 @@ func TestBlockStore(t *testing.T) { require.NoError(t, err) require.Equal(t, i, slot) - slot, err = blockStore.GetSlotByTimestamp(i) + slot, err = blockStore.GetParentSlotByTimestamp(i) require.NoError(t, err) require.Equal(t, i, slot) @@ -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.GetSlotByTimestamp(2) + _, err = blockStore.GetParentSlotByTimestamp(2) require.ErrorContains(t, err, "not found") } From 1404bf95d8c3a61621a75c2af2e71211bb6ef785 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Sat, 12 Oct 2024 17:50:32 -0400 Subject: [PATCH 4/9] gen --- .../backend/mocks/block_store.mock.go | 102 +++++++++--------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/mod/node-api/backend/mocks/block_store.mock.go b/mod/node-api/backend/mocks/block_store.mock.go index 47ac3f3ca4..943ed8550b 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,40 +50,40 @@ 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 } -// GetSlotByStateRoot provides a mock function with given fields: root -func (_m *BlockStore[BeaconBlockT]) GetSlotByStateRoot(root common.Root) (math.U64, error) { +// 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 GetSlotByStateRoot") + panic("no return value specified for GetSlotByBlockRoot") } var r0 math.U64 @@ -106,55 +106,55 @@ func (_m *BlockStore[BeaconBlockT]) GetSlotByStateRoot(root common.Root) (math.U return r0, r1 } -// BlockStore_GetSlotByStateRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSlotByStateRoot' -type BlockStore_GetSlotByStateRoot_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 } -// GetSlotByStateRoot is a helper method to define mock.On call +// GetSlotByBlockRoot is a helper method to define mock.On call // - root common.Root -func (_e *BlockStore_Expecter[BeaconBlockT]) GetSlotByStateRoot(root interface{}) *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT] { - return &BlockStore_GetSlotByStateRoot_Call[BeaconBlockT]{Call: _e.mock.On("GetSlotByStateRoot", 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_GetSlotByStateRoot_Call[BeaconBlockT]) Run(run func(root common.Root)) *BlockStore_GetSlotByStateRoot_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].(common.Root)) }) return _c } -func (_c *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT]) Return(_a0 math.U64, _a1 error) *BlockStore_GetSlotByStateRoot_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_GetSlotByStateRoot_Call[BeaconBlockT]) RunAndReturn(run func(common.Root) (math.U64, error)) *BlockStore_GetSlotByStateRoot_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 } -// GetSlotByTimestamp provides a mock function with given fields: timestamp -func (_m *BlockStore[BeaconBlockT]) GetSlotByTimestamp(timestamp math.U64) (math.U64, error) { - ret := _m.Called(timestamp) +// GetSlotByStateRoot provides a mock function with given fields: root +func (_m *BlockStore[BeaconBlockT]) GetSlotByStateRoot(root common.Root) (math.U64, error) { + ret := _m.Called(root) if len(ret) == 0 { - panic("no return value specified for GetSlotByTimestamp") + panic("no return value specified for GetSlotByStateRoot") } var r0 math.U64 var r1 error - 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, error)); ok { + return rf(root) } - if rf, ok := ret.Get(0).(func(math.U64) math.U64); ok { - r0 = rf(timestamp) + 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(timestamp) + if rf, ok := ret.Get(1).(func(common.Root) error); ok { + r1 = rf(root) } else { r1 = ret.Error(1) } @@ -162,30 +162,30 @@ func (_m *BlockStore[BeaconBlockT]) GetSlotByTimestamp(timestamp math.U64) (math return r0, r1 } -// BlockStore_GetSlotByTimestamp_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSlotByTimestamp' -type BlockStore_GetSlotByTimestamp_Call[BeaconBlockT any] struct { +// BlockStore_GetSlotByStateRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSlotByStateRoot' +type BlockStore_GetSlotByStateRoot_Call[BeaconBlockT any] struct { *mock.Call } -// GetSlotByTimestamp is a helper method to define mock.On call -// - timestamp math.U64 -func (_e *BlockStore_Expecter[BeaconBlockT]) GetSlotByTimestamp(timestamp interface{}) *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT] { - return &BlockStore_GetSlotByTimestamp_Call[BeaconBlockT]{Call: _e.mock.On("GetSlotByTimestamp", timestamp)} +// GetSlotByStateRoot is a helper method to define mock.On call +// - root common.Root +func (_e *BlockStore_Expecter[BeaconBlockT]) GetSlotByStateRoot(root interface{}) *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT] { + return &BlockStore_GetSlotByStateRoot_Call[BeaconBlockT]{Call: _e.mock.On("GetSlotByStateRoot", root)} } -func (_c *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT]) Run(run func(timestamp math.U64)) *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT] { +func (_c *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT]) Run(run func(root common.Root)) *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT] { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(math.U64)) + run(args[0].(common.Root)) }) return _c } -func (_c *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT]) Return(_a0 math.U64, _a1 error) *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT] { +func (_c *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT]) Return(_a0 math.U64, _a1 error) *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT] { _c.Call.Return(_a0, _a1) return _c } -func (_c *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT]) RunAndReturn(run func(math.U64) (math.U64, error)) *BlockStore_GetSlotByTimestamp_Call[BeaconBlockT] { +func (_c *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT]) RunAndReturn(run func(common.Root) (math.U64, error)) *BlockStore_GetSlotByStateRoot_Call[BeaconBlockT] { _c.Call.Return(run) return _c } From c7a690d3982e664d17ef5e4b93623f847e31f5ea Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Sun, 13 Oct 2024 12:49:55 -0400 Subject: [PATCH 5/9] nit --- mod/node-api/handlers/proof/block_proposer.go | 5 +++-- .../handlers/proof/execution_fee_recipient.go | 2 +- mod/node-api/handlers/proof/execution_number.go | 2 +- mod/node-api/handlers/utils/id.go | 15 ++++++++------- mod/storage/pkg/block/store.go | 4 +--- mod/storage/pkg/block/store_test.go | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/mod/node-api/handlers/proof/block_proposer.go b/mod/node-api/handlers/proof/block_proposer.go index c7e141db7a..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) { diff --git a/mod/node-api/handlers/proof/execution_fee_recipient.go b/mod/node-api/handlers/proof/execution_fee_recipient.go index 5e4864931d..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, _, _, diff --git a/mod/node-api/handlers/proof/execution_number.go b/mod/node-api/handlers/proof/execution_number.go index 1bb1d58ee5..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, _, _, diff --git a/mod/node-api/handlers/utils/id.go b/mod/node-api/handlers/utils/id.go index 25469c8a1e..e31cda61af 100644 --- a/mod/node-api/handlers/utils/id.go +++ b/mod/node-api/handlers/utils/id.go @@ -70,17 +70,18 @@ func SlotFromBlockID[StorageBackendT interface { return storage.GetSlotByBlockRoot(root) } -// ParentSlotFromTimestampID returns the slot from the block timestamp ID. +// ParentSlotFromTimestampID returns the parent slot corresponding to the +// timestamp ID. // // NOTE: `timestampID` shares the same semantics as `stateID`, with the -// modification of being able to query by next block instead of -// . +// modification of being able to query by next block's instead of +// the current block's . // // The must be prefixed by the 't', followed by the timestamp -// in decimal notation. For example 't1728681738' corresponds to the slot with -// next block timestamp of 1728681738. Providing just the string '1728681738' -// (without the prefix 't') will query for the beacon block with slot -// 1728681738. +// 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) { diff --git a/mod/storage/pkg/block/store.go b/mod/storage/pkg/block/store.go index dadd1e4bcc..30cd59d900 100644 --- a/mod/storage/pkg/block/store.go +++ b/mod/storage/pkg/block/store.go @@ -93,9 +93,7 @@ func (kv *KVStore[BeaconBlockT]) GetParentSlotByTimestamp( ) (math.Slot, error) { slot, _ := kv.timestamps.Peek(timestamp) if slot == 0 { - return slot, fmt.Errorf( - "parent slot not found at timestamp: %d", timestamp, - ) + return slot, fmt.Errorf("slot not found at timestamp: %d", timestamp) } return slot - 1, nil diff --git a/mod/storage/pkg/block/store_test.go b/mod/storage/pkg/block/store_test.go index 6416a463f6..14de7a5fef 100644 --- a/mod/storage/pkg/block/store_test.go +++ b/mod/storage/pkg/block/store_test.go @@ -65,7 +65,7 @@ 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) @@ -73,7 +73,7 @@ func TestBlockStore(t *testing.T) { 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) From a960cedfb82342880266dbdb23dd06caa27e813b Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Tue, 15 Oct 2024 15:07:14 -0400 Subject: [PATCH 6/9] address comments --- mod/node-core/pkg/components/interfaces.go | 6 +++--- mod/storage/pkg/block/store.go | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/mod/node-core/pkg/components/interfaces.go b/mod/node-core/pkg/components/interfaces.go index 594a19e954..370ae20f27 100644 --- a/mod/node-core/pkg/components/interfaces.go +++ b/mod/node-core/pkg/components/interfaces.go @@ -297,7 +297,7 @@ type ( GetSlotByStateRoot(root common.Root) (math.Slot, error) // GetParentSlotByTimestamp retrieves the parent slot by a given // timestamp from the store. - GetParentSlotByTimestamp(executionNumber math.U64) (math.Slot, error) + GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) } ConsensusEngine interface { @@ -1091,7 +1091,7 @@ type ( ChainSpec() common.ChainSpec GetSlotByBlockRoot(root common.Root) (math.Slot, error) GetSlotByStateRoot(root common.Root) (math.Slot, error) - GetParentSlotByTimestamp(executionNumber math.U64) (math.Slot, error) + GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) NodeAPIBeaconBackend[ BeaconStateT, BeaconBlockHeaderT, ForkT, ValidatorT, @@ -1123,7 +1123,7 @@ type ( ] interface { BlockBackend[BeaconBlockHeaderT] StateBackend[BeaconStateT, ForkT] - GetParentSlotByTimestamp(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 30cd59d900..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 { + // 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 } @@ -91,10 +100,13 @@ func (kv *KVStore[BeaconBlockT]) GetSlotByBlockRoot( func (kv *KVStore[BeaconBlockT]) GetParentSlotByTimestamp( timestamp math.U64, ) (math.Slot, error) { - slot, _ := kv.timestamps.Peek(timestamp) - if slot == 0 { + slot, ok := kv.timestamps.Peek(timestamp) + if !ok { return slot, fmt.Errorf("slot not found at timestamp: %d", timestamp) } + if slot == 0 { + return slot, errors.New("parent slot not supported for genesis slot 0") + } return slot - 1, nil } From 0efdc2de72b6da2a3a56d719a983db70de176331 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Tue, 15 Oct 2024 15:09:01 -0400 Subject: [PATCH 7/9] nit --- mod/node-api/engines/echo/vaildator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/node-api/engines/echo/vaildator.go b/mod/node-api/engines/echo/vaildator.go index d1b2c9386f..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": ValidateTimestampID, + "timestamp_id": ValidateTimestampID, "validator_id": ValidateValidatorID, "epoch": ValidateUint64, "slot": ValidateUint64, From 1767d2ca2e981d004077d64a315b347a07cbca42 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Tue, 15 Oct 2024 15:13:30 -0400 Subject: [PATCH 8/9] descriptive err --- mod/node-api/handlers/utils/id.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mod/node-api/handlers/utils/id.go b/mod/node-api/handlers/utils/id.go index e31cda61af..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" ) @@ -92,7 +93,9 @@ func ParentSlotFromTimestampID[StorageBackendT interface { // 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.GetParentSlotByTimestamp(timestamp) } From 9f5214eeb96e326f015f1d41b40465fc1903bfbe Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Tue, 15 Oct 2024 15:19:57 -0400 Subject: [PATCH 9/9] remove --- mod/consensus-types/pkg/types/block_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/mod/consensus-types/pkg/types/block_test.go b/mod/consensus-types/pkg/types/block_test.go index 9da54a2e4b..ad4ba20ad1 100644 --- a/mod/consensus-types/pkg/types/block_test.go +++ b/mod/consensus-types/pkg/types/block_test.go @@ -42,7 +42,6 @@ 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{