Skip to content

Commit

Permalink
feat(node-api): use timestamp ID instead of execution ID for proof na…
Browse files Browse the repository at this point in the history
…mespace
  • Loading branch information
calbera committed Oct 11, 2024
1 parent 05ce9dc commit 0eec400
Show file tree
Hide file tree
Showing 18 changed files with 79 additions and 81 deletions.
6 changes: 3 additions & 3 deletions mod/consensus-types/pkg/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
3 changes: 2 additions & 1 deletion mod/consensus-types/pkg/types/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down Expand Up @@ -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())

Expand Down
6 changes: 3 additions & 3 deletions mod/node-api/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions mod/node-api/backend/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions mod/node-api/engines/echo/vaildator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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:])
}

Expand Down
2 changes: 1 addition & 1 deletion mod/node-api/handlers/proof/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions mod/node-api/handlers/proof/block_proposer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions mod/node-api/handlers/proof/execution_fee_recipient.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions mod/node-api/handlers/proof/execution_number.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions mod/node-api/handlers/proof/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,19 @@ 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 (
beaconState BeaconStateT
blockHeader BeaconBlockHeaderT
)

slot, err := utils.SlotFromExecutionID(executionID, h.backend)
slot, err := utils.SlotFromTimestampID(timestampID, h.backend)
if err != nil {
return 0, beaconState, blockHeader, err
}
Expand Down
12 changes: 6 additions & 6 deletions mod/node-api/handlers/proof/types/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
4 changes: 2 additions & 2 deletions mod/node-api/handlers/types/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}
2 changes: 1 addition & 1 deletion mod/node-api/handlers/utils/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const (
StateIDFinalized = "finalized"
StateIDJustified = "justified"
StateIDHead = "head"
ExecutionIDPrefix = "n"
TimestampIDPrefix = "t"
)

const (
Expand Down
41 changes: 20 additions & 21 deletions mod/node-api/handlers/utils/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 <executionNumber>
// instead of <stateRoot>.
// NOTE: `timestampID` shares the same semantics as `stateID`, with the
// modification of being able to query by block <timestamp> instead of
// <stateRoot>.
//
// The <executionNumber> 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 <timestamp> 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
Expand Down
12 changes: 7 additions & 5 deletions mod/node-core/pkg/components/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down
34 changes: 15 additions & 19 deletions mod/storage/pkg/block/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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)
}
Expand All @@ -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
}
Expand All @@ -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
}
Expand Down
6 changes: 3 additions & 3 deletions mod/storage/pkg/block/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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)

Expand All @@ -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")
}
Loading

0 comments on commit 0eec400

Please sign in to comment.