From 646f02d0f38cc5c4d809bea60b4f0ed262333ece Mon Sep 17 00:00:00 2001 From: Calin Martinconi Date: Thu, 10 Oct 2024 14:57:37 +0300 Subject: [PATCH] feat: add status neighborhoods endpoint (#4853) Co-authored-by: istae <14264581+istae@users.noreply.github.com> --- openapi/Swarm.yaml | 19 ++++++++- openapi/SwarmCommon.yaml | 24 +++++++++++ pkg/api/api.go | 1 + pkg/api/router.go | 8 ++++ pkg/api/status.go | 41 +++++++++++++++++++ pkg/api/status_test.go | 6 +++ pkg/storer/migration/all_steps.go | 10 ++--- pkg/storer/migration/all_steps_test.go | 6 +-- pkg/storer/migration/refCntSize.go | 6 +-- pkg/storer/migration/refCntSize_test.go | 3 +- pkg/storer/migration/step_04.go | 4 +- pkg/storer/migration/step_04_test.go | 3 +- pkg/storer/migration/step_05.go | 7 ++-- pkg/storer/migration/step_05_test.go | 3 +- pkg/storer/migration/step_06.go | 6 +-- pkg/storer/migration/step_06_test.go | 3 +- pkg/storer/mock/mockstorer.go | 4 ++ pkg/storer/reserve.go | 10 ++--- pkg/storer/reserve_test.go | 39 +++++++++++------- pkg/storer/storer.go | 6 ++- pkg/storer/storer_test.go | 1 - pkg/swarm/swarm.go | 53 +++++++++++++++++++++++++ pkg/swarm/swarm_test.go | 38 ++++++++++++++++++ 23 files changed, 255 insertions(+), 46 deletions(-) diff --git a/openapi/Swarm.yaml b/openapi/Swarm.yaml index 98afdaa4d34..f3a65275dcd 100644 --- a/openapi/Swarm.yaml +++ b/openapi/Swarm.yaml @@ -1005,7 +1005,7 @@ paths: $ref: "SwarmCommon.yaml#/components/schemas/FeedType" required: false description: "Feed indexing scheme (default: sequence)" - - $ref: "SwarmCommon.yaml#/components/headers/SwarmOnlyRootChunkParameter" + - $ref: "SwarmCommon.yaml#/components/parameters/SwarmOnlyRootChunkParameter" - $ref: "SwarmCommon.yaml#/components/parameters/SwarmCache" - $ref: "SwarmCommon.yaml#/components/parameters/SwarmRedundancyStrategyParameter" - $ref: "SwarmCommon.yaml#/components/parameters/SwarmRedundancyFallbackModeParameter" @@ -2448,6 +2448,23 @@ paths: default: description: Default response. + "/status/neighborhoods": + get: + summary: Get the current neighborhoods status of this node. + tags: + - Node Status + responses: + "200": + description: Returns the neighborhoods status of this node + content: + application/json: + schema: + $ref: "SwarmCommon.yaml#/components/schemas/StatusNeighborhoodsResponse" + "400": + $ref: "SwarmCommon.yaml#/components/responses/400" + default: + description: Default response. + components: securitySchemes: basicAuth: diff --git a/openapi/SwarmCommon.yaml b/openapi/SwarmCommon.yaml index d4b4feb8c5c..7f309582cfe 100644 --- a/openapi/SwarmCommon.yaml +++ b/openapi/SwarmCommon.yaml @@ -933,6 +933,30 @@ components: items: $ref: "#/components/schemas/StatusSnapshotResponse" + StatusNeighborhoodResponse: + type: object + properties: + neighborhood: + $ref: "#/components/schemas/Neighborhood" + reserveSizeWithinRadius: + type: integer + proximity: + type: integer + + Neighborhood: + type: string + description: Swarm address of a neighborhood in string binary format, usually limited to as many bits as the current storage radius. + example: "011010111" + + StatusNeighborhoodsResponse: + type: object + properties: + stamps: + type: array + nullable: false + items: + $ref: "#/components/schemas/StatusNeighborhoodResponse" + ApiChunkInclusionProof: type: object properties: diff --git a/pkg/api/api.go b/pkg/api/api.go index 4fc70fbfb17..4568ad96bf5 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -140,6 +140,7 @@ type Storer interface { storer.LocalStore storer.RadiusChecker storer.Debugger + storer.NeighborhoodStats } type PinIntegrity interface { diff --git a/pkg/api/router.go b/pkg/api/router.go index f9a0716b84b..eb2fbd4867d 100644 --- a/pkg/api/router.go +++ b/pkg/api/router.go @@ -634,6 +634,14 @@ func (s *Service) mountBusinessDebug() { ), }) + handle("/status/neighborhoods", jsonhttp.MethodHandler{ + "GET": web.ChainHandlers( + httpaccess.NewHTTPAccessSuppressLogHandler(), + s.statusAccessHandler, + web.FinalHandlerFunc(s.statusGetNeighborhoods), + ), + }) + handle("/rchash/{depth}/{anchor1}/{anchor2}", web.ChainHandlers( web.FinalHandler(jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.rchash), diff --git a/pkg/api/status.go b/pkg/api/status.go index 867c7d410e9..30e09e1f166 100644 --- a/pkg/api/status.go +++ b/pkg/api/status.go @@ -36,6 +36,16 @@ type statusResponse struct { Snapshots []statusSnapshotResponse `json:"snapshots"` } +type statusNeighborhoodResponse struct { + Neighborhood string `json:"neighborhood"` + ReserveSizeWithinRadius int `json:"reserveSizeWithinRadius"` + Proximity uint8 `json:"proximity"` +} + +type neighborhoodsResponse struct { + Neighborhoods []statusNeighborhoodResponse `json:"neighborhoods"` +} + // statusAccessHandler is a middleware that limits the number of simultaneous // status requests. func (s *Service) statusAccessHandler(h http.Handler) http.Handler { @@ -159,3 +169,34 @@ func (s *Service) statusGetPeersHandler(w http.ResponseWriter, r *http.Request) }) jsonhttp.OK(w, statusResponse{Snapshots: snapshots}) } + +// statusGetHandler returns the current node status. +func (s *Service) statusGetNeighborhoods(w http.ResponseWriter, r *http.Request) { + logger := s.logger.WithName("get_status_neighborhoods").Build() + + if s.beeMode == DevMode { + logger.Warning("status neighborhoods endpoint is disabled in dev mode") + jsonhttp.BadRequest(w, errUnsupportedDevNodeOperation) + return + } + + neighborhoods := make([]statusNeighborhoodResponse, 0) + + nhoods, err := s.storer.NeighborhoodsStat(r.Context()) + if err != nil { + logger.Debug("unable to get neighborhoods status", "error", err) + logger.Error(nil, "unable to get neighborhoods status") + jsonhttp.InternalServerError(w, "unable to get neighborhoods status") + return + } + + for _, n := range nhoods { + neighborhoods = append(neighborhoods, statusNeighborhoodResponse{ + Neighborhood: n.Neighborhood.String(), + ReserveSizeWithinRadius: n.ReserveSizeWithinRadius, + Proximity: swarm.Proximity(s.overlay.Bytes(), n.Neighborhood.Bytes()), + }) + } + + jsonhttp.OK(w, neighborhoodsResponse{Neighborhoods: neighborhoods}) +} diff --git a/pkg/api/status_test.go b/pkg/api/status_test.go index 31822ce789d..654e94708a8 100644 --- a/pkg/api/status_test.go +++ b/pkg/api/status_test.go @@ -5,6 +5,7 @@ package api_test import ( + "context" "net/http" "testing" @@ -14,6 +15,7 @@ import ( "github.com/ethersphere/bee/v2/pkg/log" "github.com/ethersphere/bee/v2/pkg/postage" "github.com/ethersphere/bee/v2/pkg/status" + "github.com/ethersphere/bee/v2/pkg/storer" "github.com/ethersphere/bee/v2/pkg/topology" ) @@ -119,6 +121,7 @@ type statusSnapshotMock struct { storageRadius uint8 commitment uint64 chainState *postage.ChainState + neighborhoods []*storer.NeighborhoodStat } func (m *statusSnapshotMock) SyncRate() float64 { return m.syncRate } @@ -129,3 +132,6 @@ func (m *statusSnapshotMock) GetChainState() *postage.ChainState { return m.chai func (m *statusSnapshotMock) ReserveSizeWithinRadius() uint64 { return m.reserveSizeWithinRadius } +func (m *statusSnapshotMock) NeighborhoodsStat(ctx context.Context) ([]*storer.NeighborhoodStat, error) { + return m.neighborhoods, nil +} diff --git a/pkg/storer/migration/all_steps.go b/pkg/storer/migration/all_steps.go index 8a509c194e1..674e08c1143 100644 --- a/pkg/storer/migration/all_steps.go +++ b/pkg/storer/migration/all_steps.go @@ -22,15 +22,15 @@ func AfterInitSteps( 1: step_01, 2: step_02(st), 3: ReserveRepairer(st, storage.ChunkType, logger), - 4: step_04(sharkyPath, sharkyNoOfShards, st), - 5: step_05(st), - 6: step_06(st), + 4: step_04(sharkyPath, sharkyNoOfShards, st, logger), + 5: step_05(st, logger), + 6: step_06(st, logger), } } // BeforeInitSteps lists all migration steps for localstore IndexStore before the localstore is initiated. -func BeforeInitSteps(st storage.BatchStore) migration.Steps { +func BeforeInitSteps(st storage.BatchStore, logger log.Logger) migration.Steps { return map[uint64]migration.StepFn{ - 1: RefCountSizeInc(st), + 1: RefCountSizeInc(st, logger), } } diff --git a/pkg/storer/migration/all_steps_test.go b/pkg/storer/migration/all_steps_test.go index cbe03741674..265197e8fce 100644 --- a/pkg/storer/migration/all_steps_test.go +++ b/pkg/storer/migration/all_steps_test.go @@ -49,12 +49,12 @@ func TestPostSteps(t *testing.T) { st := inmemstore.New() - assert.NotEmpty(t, localmigration.BeforeInitSteps(st)) + assert.NotEmpty(t, localmigration.BeforeInitSteps(st, log.Noop)) t.Run("version numbers", func(t *testing.T) { t.Parallel() - err := migration.ValidateVersions(localmigration.BeforeInitSteps(st)) + err := migration.ValidateVersions(localmigration.BeforeInitSteps(st, log.Noop)) assert.NoError(t, err) }) @@ -63,7 +63,7 @@ func TestPostSteps(t *testing.T) { store := inmemstore.New() - err := migration.Migrate(store, "migration", localmigration.BeforeInitSteps(store)) + err := migration.Migrate(store, "migration", localmigration.BeforeInitSteps(store, log.Noop)) assert.NoError(t, err) }) } diff --git a/pkg/storer/migration/refCntSize.go b/pkg/storer/migration/refCntSize.go index bb592c2e2b0..64f6f58b315 100644 --- a/pkg/storer/migration/refCntSize.go +++ b/pkg/storer/migration/refCntSize.go @@ -8,7 +8,6 @@ import ( "context" "encoding/binary" "errors" - "os" "github.com/ethersphere/bee/v2/pkg/log" "github.com/ethersphere/bee/v2/pkg/sharky" @@ -101,9 +100,10 @@ func (r OldRetrievalIndexItem) String() string { return storageutil.JoinFields(r.Namespace(), r.ID()) } -func RefCountSizeInc(s storage.BatchStore) func() error { +func RefCountSizeInc(s storage.BatchStore, logger log.Logger) func() error { return func() error { - logger := log.NewLogger("migration-RefCountSizeInc", log.WithSink(os.Stdout)) + + logger := logger.WithName("migration-RefCountSizeInc").Register() logger.Info("starting migration of replacing chunkstore items to increase refCnt capacity") diff --git a/pkg/storer/migration/refCntSize_test.go b/pkg/storer/migration/refCntSize_test.go index 6a2fee2ae4c..bfbc8c687e7 100644 --- a/pkg/storer/migration/refCntSize_test.go +++ b/pkg/storer/migration/refCntSize_test.go @@ -8,6 +8,7 @@ import ( "math/rand" "testing" + "github.com/ethersphere/bee/v2/pkg/log" "github.com/ethersphere/bee/v2/pkg/sharky" "github.com/ethersphere/bee/v2/pkg/storage/inmemstore" "github.com/ethersphere/bee/v2/pkg/storer/internal/chunkstore" @@ -36,7 +37,7 @@ func Test_RefCntSize(t *testing.T) { assert.NoError(t, err) } - assert.NoError(t, stepFn(store)()) + assert.NoError(t, stepFn(store, log.Noop)()) // check if all entries are migrated. for _, entry := range oldItems { diff --git a/pkg/storer/migration/step_04.go b/pkg/storer/migration/step_04.go index 2495f022eb4..481b6744d83 100644 --- a/pkg/storer/migration/step_04.go +++ b/pkg/storer/migration/step_04.go @@ -6,7 +6,6 @@ package migration import ( "context" - "os" "github.com/ethersphere/bee/v2/pkg/log" "github.com/ethersphere/bee/v2/pkg/sharky" @@ -21,13 +20,14 @@ func step_04( sharkyBasePath string, sharkyNoOfShards int, st transaction.Storage, + logger log.Logger, ) func() error { return func() error { // for in-mem store, skip this step if sharkyBasePath == "" { return nil } - logger := log.NewLogger("migration-step-04", log.WithSink(os.Stdout)) + logger := logger.WithName("migration-step-04").Register() logger.Info("starting sharky recovery") sharkyRecover, err := sharky.NewRecovery(sharkyBasePath, sharkyNoOfShards, swarm.SocMaxChunkSize) diff --git a/pkg/storer/migration/step_04_test.go b/pkg/storer/migration/step_04_test.go index e492b6a416a..758ddc7987f 100644 --- a/pkg/storer/migration/step_04_test.go +++ b/pkg/storer/migration/step_04_test.go @@ -11,6 +11,7 @@ import ( "path/filepath" "testing" + "github.com/ethersphere/bee/v2/pkg/log" "github.com/ethersphere/bee/v2/pkg/sharky" "github.com/ethersphere/bee/v2/pkg/storage/inmemstore" chunktest "github.com/ethersphere/bee/v2/pkg/storage/testing" @@ -38,7 +39,7 @@ func Test_Step_04(t *testing.T) { store := inmemstore.New() storage := transaction.NewStorage(sharkyStore, store) - stepFn := localmigration.Step_04(sharkyDir, 1, storage) + stepFn := localmigration.Step_04(sharkyDir, 1, storage, log.Noop) chunks := chunktest.GenerateTestRandomChunks(10) diff --git a/pkg/storer/migration/step_05.go b/pkg/storer/migration/step_05.go index 25857277438..94b23d9ef67 100644 --- a/pkg/storer/migration/step_05.go +++ b/pkg/storer/migration/step_05.go @@ -7,7 +7,6 @@ package migration import ( "context" "fmt" - "os" "github.com/ethersphere/bee/v2/pkg/log" "github.com/ethersphere/bee/v2/pkg/storage" @@ -16,9 +15,11 @@ import ( ) // step_05 is a migration step that removes all upload items from the store. -func step_05(st transaction.Storage) func() error { +func step_05(st transaction.Storage, logger log.Logger) func() error { return func() error { - logger := log.NewLogger("migration-step-05", log.WithSink(os.Stdout)) + + logger := logger.WithName("migration-step-05").Register() + logger.Info("start removing upload items") itemC := make(chan storage.Item) diff --git a/pkg/storer/migration/step_05_test.go b/pkg/storer/migration/step_05_test.go index 640bb2da5b9..aeacd310f3e 100644 --- a/pkg/storer/migration/step_05_test.go +++ b/pkg/storer/migration/step_05_test.go @@ -8,6 +8,7 @@ import ( "context" "testing" + "github.com/ethersphere/bee/v2/pkg/log" "github.com/ethersphere/bee/v2/pkg/sharky" "github.com/ethersphere/bee/v2/pkg/storage" "github.com/ethersphere/bee/v2/pkg/storage/leveldbstore" @@ -98,7 +99,7 @@ func Test_Step_05(t *testing.T) { wantCount(t, store.IndexStore(), 10) - err = localmigration.Step_05(store)() + err = localmigration.Step_05(store, log.Noop)() if err != nil { t.Fatalf("step 05: %v", err) } diff --git a/pkg/storer/migration/step_06.go b/pkg/storer/migration/step_06.go index ab8fec574e7..4160e198b4c 100644 --- a/pkg/storer/migration/step_06.go +++ b/pkg/storer/migration/step_06.go @@ -9,7 +9,6 @@ import ( "context" "errors" "fmt" - "os" "runtime" "sync/atomic" "time" @@ -24,9 +23,10 @@ import ( ) // step_06 is a migration step that adds a stampHash to all BatchRadiusItems, ChunkBinItems and StampIndexItems. -func step_06(st transaction.Storage) func() error { +func step_06(st transaction.Storage, logger log.Logger) func() error { return func() error { - logger := log.NewLogger("migration-step-06", log.WithSink(os.Stdout)) + logger := logger.WithName("migration-step-06").Register() + logger.Info("start adding stampHash to BatchRadiusItems, ChunkBinItems and StampIndexItems") seenCount, doneCount, err := addStampHash(logger, st) diff --git a/pkg/storer/migration/step_06_test.go b/pkg/storer/migration/step_06_test.go index d6e44d7e872..b5a5d3ecc7a 100644 --- a/pkg/storer/migration/step_06_test.go +++ b/pkg/storer/migration/step_06_test.go @@ -8,6 +8,7 @@ import ( "context" "testing" + "github.com/ethersphere/bee/v2/pkg/log" "github.com/ethersphere/bee/v2/pkg/sharky" "github.com/ethersphere/bee/v2/pkg/storage" "github.com/ethersphere/bee/v2/pkg/storage/leveldbstore" @@ -98,7 +99,7 @@ func Test_Step_06(t *testing.T) { } require.NoError(t, err) - err = localmigration.Step_06(store)() + err = localmigration.Step_06(store, log.Noop)() require.NoError(t, err) has, err := store.IndexStore().Has(&reserve.EpochItem{}) diff --git a/pkg/storer/mock/mockstorer.go b/pkg/storer/mock/mockstorer.go index a955e168d17..69e8630d846 100644 --- a/pkg/storer/mock/mockstorer.go +++ b/pkg/storer/mock/mockstorer.go @@ -225,3 +225,7 @@ func (m *mockStorer) IsWithinStorageRadius(_ swarm.Address) bool { return true } func (m *mockStorer) DebugInfo(_ context.Context) (storer.Info, error) { return m.debugInfo, nil } + +func (m *mockStorer) NeighborhoodsStat(ctx context.Context) ([]*storer.NeighborhoodStat, error) { + return nil, nil +} diff --git a/pkg/storer/reserve.go b/pkg/storer/reserve.go index a3e75ee239b..1a4ec6f21e0 100644 --- a/pkg/storer/reserve.go +++ b/pkg/storer/reserve.go @@ -498,8 +498,8 @@ func (db *DB) SubscribeBin(ctx context.Context, bin uint8, start uint64) (<-chan } type NeighborhoodStat struct { - Address swarm.Address - ChunkCount int + Neighborhood swarm.Neighborhood + ReserveSizeWithinRadius int } func (db *DB) NeighborhoodsStat(ctx context.Context) ([]*NeighborhoodStat, error) { @@ -511,13 +511,13 @@ func (db *DB) NeighborhoodsStat(ctx context.Context) ([]*NeighborhoodStat, error prefixes := neighborhoodPrefixes(db.baseAddr, int(radius), db.reserveOptions.capacityDoubling) neighs := make([]*NeighborhoodStat, len(prefixes)) for i, n := range prefixes { - neighs[i] = &NeighborhoodStat{Address: n} + neighs[i] = &NeighborhoodStat{swarm.NewNeighborhood(n, networkRadius), 0} } err := db.reserve.IterateChunksItems(0, func(ch *reserve.ChunkBinItem) (bool, error) { for _, n := range neighs { - if swarm.Proximity(ch.Address.Bytes(), n.Address.Bytes()) >= networkRadius { - n.ChunkCount++ + if swarm.Proximity(ch.Address.Bytes(), n.Neighborhood.Bytes()) >= networkRadius { + n.ReserveSizeWithinRadius++ break } } diff --git a/pkg/storer/reserve_test.go b/pkg/storer/reserve_test.go index 8fd04a0581e..564fec4ca6c 100644 --- a/pkg/storer/reserve_test.go +++ b/pkg/storer/reserve_test.go @@ -670,9 +670,9 @@ func TestNeighborhoodStats(t *testing.T) { t.Parallel() const ( - chunkCountPerPO = 32 - maxPO = 6 - networkRadius uint8 = 5 + chunkCountPerPO = 16 + maxPO = 5 + networkRadius uint8 = 4 doublingFactor uint8 = 2 localRadius uint8 = networkRadius - doublingFactor ) @@ -686,10 +686,10 @@ func TestNeighborhoodStats(t *testing.T) { } var ( - baseAddr = mustParse("100000") - sister1 = mustParse("100010") - sister2 = mustParse("100100") - sister3 = mustParse("100110") + baseAddr = mustParse("10000") + sister1 = mustParse("10010") + sister2 = mustParse("10100") + sister3 = mustParse("10110") ) putChunks := func(addr swarm.Address, startingRadius int, st *storer.DB) { @@ -711,8 +711,6 @@ func TestNeighborhoodStats(t *testing.T) { putChunks(sister2, int(networkRadius), st) putChunks(sister3, int(networkRadius), st) - time.Sleep(time.Second) - neighs, err := st.NeighborhoodsStat(context.Background()) if err != nil { t.Fatal(err) @@ -723,36 +721,47 @@ func TestNeighborhoodStats(t *testing.T) { } for _, n := range neighs { - if n.ChunkCount != chunkCountPerPO { - t.Fatalf("chunk count does not match. wanted %d, got %d", chunkCountPerPO, n.ChunkCount) + if n.ReserveSizeWithinRadius != chunkCountPerPO { + t.Fatalf("chunk count does not match. wanted %d, got %d, prox %d", chunkCountPerPO, n.ReserveSizeWithinRadius, swarm.Proximity(baseAddr.Bytes(), n.Neighborhood.Bytes())) } } - if !neighs[0].Address.Equal(baseAddr) || !neighs[1].Address.Equal(sister1) || !neighs[2].Address.Equal(sister2) || !neighs[3].Address.Equal(sister3) { + if !neighs[0].Neighborhood.Equal(swarm.NewNeighborhood(baseAddr, networkRadius)) || + !neighs[1].Neighborhood.Equal(swarm.NewNeighborhood(sister1, networkRadius)) || + !neighs[2].Neighborhood.Equal(swarm.NewNeighborhood(sister2, networkRadius)) || + !neighs[3].Neighborhood.Equal(swarm.NewNeighborhood(sister3, networkRadius)) { t.Fatal("chunk addresses do not match") } } t.Run("disk", func(t *testing.T) { t.Parallel() - opts := dbTestOps(baseAddr, 10000, nil, nil, time.Minute) + opts := dbTestOps(baseAddr, 1000, nil, nil, time.Minute) opts.ReserveCapacityDoubling = int(doublingFactor) storer, err := diskStorer(t, opts)() if err != nil { t.Fatal(err) } storer.StartReserveWorker(context.Background(), pullerMock.NewMockRateReporter(0), networkRadiusFunc(localRadius)) + err = spinlock.Wait(time.Minute, func() bool { return storer.StorageRadius() == localRadius }) + if err != nil { + t.Fatal(err) + } testF(t, storer) }) t.Run("mem", func(t *testing.T) { t.Parallel() - opts := dbTestOps(baseAddr, 10000, nil, nil, time.Minute) + opts := dbTestOps(baseAddr, 1000, nil, nil, time.Minute) opts.ReserveCapacityDoubling = int(doublingFactor) - storer, err := diskStorer(t, opts)() + storer, err := memStorer(t, opts)() if err != nil { t.Fatal(err) } storer.StartReserveWorker(context.Background(), pullerMock.NewMockRateReporter(0), networkRadiusFunc(localRadius)) + err = spinlock.Wait(time.Minute, func() bool { return storer.StorageRadius() == localRadius }) + if err != nil { + t.Fatal(err) + } testF(t, storer) }) } diff --git a/pkg/storer/storer.go b/pkg/storer/storer.go index d3bf812005d..2094596976f 100644 --- a/pkg/storer/storer.go +++ b/pkg/storer/storer.go @@ -177,6 +177,10 @@ type Debugger interface { DebugInfo(context.Context) (Info, error) } +type NeighborhoodStats interface { + NeighborhoodsStat(ctx context.Context) ([]*NeighborhoodStat, error) +} + type memFS struct { afero.Fs } @@ -279,7 +283,7 @@ func initDiskRepository( return nil, nil, nil, fmt.Errorf("failed creating levelDB index store: %w", err) } - err = migration.Migrate(store, "core-migration", localmigration.BeforeInitSteps(store)) + err = migration.Migrate(store, "core-migration", localmigration.BeforeInitSteps(store, opts.Logger)) if err != nil { return nil, nil, nil, errors.Join(store.Close(), fmt.Errorf("failed core migration: %w", err)) } diff --git a/pkg/storer/storer_test.go b/pkg/storer/storer_test.go index b85837b35ad..e5cdc655db1 100644 --- a/pkg/storer/storer_test.go +++ b/pkg/storer/storer_test.go @@ -194,7 +194,6 @@ func dbTestOps(baseAddr swarm.Address, reserveCapacity int, bs postage.Storer, r opts.ReserveCapacity = reserveCapacity opts.Batchstore = bs opts.ReserveWakeUpDuration = reserveWakeUpTime - opts.Logger = log.Noop return opts } diff --git a/pkg/swarm/swarm.go b/pkg/swarm/swarm.go index 3723a31dedd..1b2e83b2ed7 100644 --- a/pkg/swarm/swarm.go +++ b/pkg/swarm/swarm.go @@ -327,3 +327,56 @@ func bytesToAddr(b []byte) Address { copy(addr, b) return NewAddress(addr) } + +type Neighborhood struct { + b []byte + r uint8 +} + +func NewNeighborhood(a Address, bits uint8) Neighborhood { + return Neighborhood{b: a.b, r: bits} +} + +// String returns a bit string of the Neighborhood. +func (n Neighborhood) String() string { + return bitStr(n.b, n.r) +} + +// Equal returns true if two neighborhoods are identical. +func (n Neighborhood) Equal(b Neighborhood) bool { + return bytes.Equal(n.b, b.b) +} + +// Bytes returns bytes representation of the Neighborhood. +func (n Neighborhood) Bytes() []byte { + return n.b +} + +// Bytes returns bytes representation of the Neighborhood. +func (n Neighborhood) Clone() Neighborhood { + if n.b == nil { + return Neighborhood{} + } + return Neighborhood{b: append(make([]byte, 0, len(n.b)), n.Bytes()...), r: n.r} +} + +func bitStr(src []byte, bits uint8) string { + + ret := "" + + for _, b := range src { + for i := 7; i >= 0; i-- { + if b&(1< 0 { + ret += "1" + } else { + ret += "0" + } + bits-- + if bits == 0 { + return ret + } + } + } + + return ret +} diff --git a/pkg/swarm/swarm_test.go b/pkg/swarm/swarm_test.go index fdde62625be..99bc243da0e 100644 --- a/pkg/swarm/swarm_test.go +++ b/pkg/swarm/swarm_test.go @@ -5,6 +5,7 @@ package swarm_test import ( + "bytes" "encoding/hex" "encoding/json" "errors" @@ -191,3 +192,40 @@ func TestParseBitStr(t *testing.T) { } } } + +func TestNeighborhood(t *testing.T) { + t.Parallel() + + for _, tc := range []struct { + overlay swarm.Address + bitStr string + }{ + { + swarm.MustParseHexAddress("5c32a2fe3d217af8c943fa665ebcfbdf7ab9af0cf1b2a1c8e5fc163dad2f5c7b"), + "010111000", + }, + { + swarm.MustParseHexAddress("eac0903e59ff1c1a5f1d7d218b33f819b199aa0f68a19fd5fa02b7f84982b55d"), + "111010101", + }, + { + swarm.MustParseHexAddress("70143dd2863ae07edfe7c1bfee75daea06226f0678e1117337d274492226bfe0"), + "011100000", + }, + } { + + n := swarm.NewNeighborhood(tc.overlay, uint8(len(tc.bitStr))) + if n.Equal(swarm.NewNeighborhood(swarm.RandAddress(t), uint8(len(tc.bitStr)))) { + t.Fatal("addresses not should match") + } + if !n.Equal(swarm.NewNeighborhood(tc.overlay, uint8(len(tc.bitStr)))) { + t.Fatal("addresses should match") + } + if !bytes.Equal(n.Bytes(), tc.overlay.Bytes()) { + t.Fatal("bytes should match") + } + if n.String() != tc.bitStr { + t.Fatal("bit str should match") + } + } +}