diff --git a/node-api/handlers/utils/mappings.go b/node-api/handlers/utils/mappings.go index 2baefee05f..415adfad0e 100644 --- a/node-api/handlers/utils/mappings.go +++ b/node-api/handlers/utils/mappings.go @@ -26,12 +26,13 @@ import ( "strings" "github.com/berachain/beacon-kit/errors" + handlertypes "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" + "github.com/berachain/beacon-kit/storage/block" ) var ( - ErrNoSlotForStateRoot = errors.New("slot not found at state root") ErrFailedMappingHeightTooHigh = errors.New("failed mapping height too high") ) @@ -57,7 +58,10 @@ func StateIDToHeight[StorageBackendT interface { } slot, err := storage.GetSlotByStateRoot(root) if err != nil { - return 0, ErrNoSlotForStateRoot + if errors.Is(err, block.ErrBlockStoreNotEnabled) { + return 0, err + } + return 0, fmt.Errorf("%w: %w", handlertypes.ErrNotFound, err) } if slot > stdmath.MaxInt64 { // appease linters return 0, fmt.Errorf("%w: slot %d", ErrFailedMappingHeightTooHigh, slot) diff --git a/node-api/handlers/utils/mappings_test.go b/node-api/handlers/utils/mappings_test.go new file mode 100644 index 0000000000..d6e4edb1bc --- /dev/null +++ b/node-api/handlers/utils/mappings_test.go @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2025, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package utils_test + +import ( + "errors" + "strings" + "testing" + + "github.com/berachain/beacon-kit/node-api/handlers/types" + "github.com/berachain/beacon-kit/node-api/handlers/utils" + "github.com/berachain/beacon-kit/primitives/common" + "github.com/berachain/beacon-kit/primitives/math" + "github.com/berachain/beacon-kit/storage/block" + "github.com/stretchr/testify/require" +) + +type stateRootStorage struct { + slot math.Slot + err error +} + +func (s stateRootStorage) GetSlotByStateRoot(_ common.Root) (math.Slot, error) { + return s.slot, s.err +} + +func TestStateIDToHeight(t *testing.T) { + t.Parallel() + + unknownRoot := "0x" + strings.Repeat("01", 32) + + tests := []struct { + name string + stateID string + storage stateRootStorage + want int64 + errIs []error + errNot []error + }{ + { + name: "head", + stateID: utils.StateIDHead, + want: utils.Head, + }, + { + name: "slot", + stateID: "42", + want: 42, + }, + { + name: "known state root", + stateID: unknownRoot, + storage: stateRootStorage{slot: math.Slot(7)}, + want: 7, + }, + { + name: "unknown state root", + stateID: unknownRoot, + storage: stateRootStorage{err: errors.New("slot not found at state root")}, + errIs: []error{types.ErrNotFound}, + }, + { + name: "block store not enabled", + stateID: unknownRoot, + storage: stateRootStorage{err: block.ErrBlockStoreNotEnabled}, + errIs: []error{block.ErrBlockStoreNotEnabled}, + errNot: []error{types.ErrNotFound}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + got, err := utils.StateIDToHeight(tc.stateID, tc.storage) + if len(tc.errIs) == 0 { + require.NoError(t, err) + require.Equal(t, tc.want, got) + return + } + + require.Error(t, err) + require.Zero(t, got) + for _, target := range tc.errIs { + require.ErrorIs(t, err, target) + } + for _, target := range tc.errNot { + require.NotErrorIs(t, err, target) + } + if tc.storage.err != nil { + require.ErrorIs(t, err, tc.storage.err) + } + }) + } +}