From ff472fa8b51978e3c81c41bc186795dcaaeb9462 Mon Sep 17 00:00:00 2001 From: istae <14264581+istae@users.noreply.github.com> Date: Thu, 10 Oct 2024 02:10:40 +0300 Subject: [PATCH] fix: new neighborhood type and cleanup --- openapi/SwarmCommon.yaml | 11 ++++++-- pkg/api/api.go | 1 + pkg/api/status.go | 20 ++++--------- pkg/status/status.go | 15 ---------- pkg/status/status_test.go | 12 ++------ pkg/storer/mock/mockstorer.go | 4 +++ pkg/storer/reserve.go | 6 ++-- pkg/storer/reserve_test.go | 5 +++- pkg/storer/storer.go | 4 +++ pkg/swarm/swarm.go | 53 +++++++++++++++++++++++++++++++++++ pkg/swarm/swarm_test.go | 38 +++++++++++++++++++++++++ 11 files changed, 124 insertions(+), 45 deletions(-) diff --git a/openapi/SwarmCommon.yaml b/openapi/SwarmCommon.yaml index 2ef4e155f37..0cdf8b3208f 100644 --- a/openapi/SwarmCommon.yaml +++ b/openapi/SwarmCommon.yaml @@ -936,11 +936,18 @@ components: StatusNeighborhoodResponse: type: object properties: - address: - type: string + neighborhood: + $ref: "#/components/schemas/Neighborhood" reserveSizeWithinRadius: type: integer + proximity: + type: integer + Neighborhood: + type: string + description: Swarm address of a neighborhood in string binary format showing, usually limited to as many bits as the current storage radius. + example: "011010111" + StatusNeighborhoodsResponse: 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/status.go b/pkg/api/status.go index 3a61e62d354..30e09e1f166 100644 --- a/pkg/api/status.go +++ b/pkg/api/status.go @@ -6,7 +6,6 @@ package api import ( "context" - "fmt" "net/http" "sort" "sync" @@ -38,8 +37,9 @@ type statusResponse struct { } type statusNeighborhoodResponse struct { - Address string `json:"address"` + Neighborhood string `json:"neighborhood"` ReserveSizeWithinRadius int `json:"reserveSizeWithinRadius"` + Proximity uint8 `json:"proximity"` } type neighborhoodsResponse struct { @@ -171,7 +171,7 @@ func (s *Service) statusGetPeersHandler(w http.ResponseWriter, r *http.Request) } // statusGetHandler returns the current node status. -func (s *Service) statusGetNeighborhoods(w http.ResponseWriter, _ *http.Request) { +func (s *Service) statusGetNeighborhoods(w http.ResponseWriter, r *http.Request) { logger := s.logger.WithName("get_status_neighborhoods").Build() if s.beeMode == DevMode { @@ -182,7 +182,7 @@ func (s *Service) statusGetNeighborhoods(w http.ResponseWriter, _ *http.Request) neighborhoods := make([]statusNeighborhoodResponse, 0) - nhoods, err := s.statusService.NeighborhoodsSnapshot() + 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") @@ -190,19 +190,11 @@ func (s *Service) statusGetNeighborhoods(w http.ResponseWriter, _ *http.Request) return } - if len(nhoods) == 0 { - jsonhttp.NotFound(w, "neighborhoods not found") - return - } - for _, n := range nhoods { - binaryAddr := "" - for _, b := range n.Address.Bytes() { - binaryAddr += fmt.Sprintf("%08b ", b) - } neighborhoods = append(neighborhoods, statusNeighborhoodResponse{ - Address: binaryAddr, + Neighborhood: n.Neighborhood.String(), ReserveSizeWithinRadius: n.ReserveSizeWithinRadius, + Proximity: swarm.Proximity(s.overlay.Bytes(), n.Neighborhood.Bytes()), }) } diff --git a/pkg/status/status.go b/pkg/status/status.go index cea9a3df21d..d8106b4e4fb 100644 --- a/pkg/status/status.go +++ b/pkg/status/status.go @@ -13,7 +13,6 @@ import ( "github.com/ethersphere/bee/v2/pkg/p2p/protobuf" "github.com/ethersphere/bee/v2/pkg/postage" "github.com/ethersphere/bee/v2/pkg/status/internal/pb" - "github.com/ethersphere/bee/v2/pkg/storer" "github.com/ethersphere/bee/v2/pkg/swarm" "github.com/ethersphere/bee/v2/pkg/topology" ) @@ -40,7 +39,6 @@ type Reserve interface { ReserveSize() int ReserveSizeWithinRadius() uint64 StorageRadius() uint8 - NeighborhoodsStat(ctx context.Context) ([]*storer.NeighborhoodStat, error) } type topologyDriver interface { @@ -133,19 +131,6 @@ func (s *Service) LocalSnapshot() (*Snapshot, error) { }, nil } -func (s *Service) NeighborhoodsSnapshot() ([]*storer.NeighborhoodStat, error) { - var err error - neighborhoods := make([]*storer.NeighborhoodStat, 0) - - if s.reserve != nil { - neighborhoods, err = s.reserve.NeighborhoodsStat(context.Background()) - if err != nil { - return neighborhoods, err - } - } - return neighborhoods, err -} - // PeerSnapshot sends request for status snapshot to the peer. func (s *Service) PeerSnapshot(ctx context.Context, peer swarm.Address) (*Snapshot, error) { stream, err := s.streamer.NewStream(ctx, peer, nil, protocolName, protocolVersion, streamName) diff --git a/pkg/status/status_test.go b/pkg/status/status_test.go index d2883ecd3c3..019cdae578c 100644 --- a/pkg/status/status_test.go +++ b/pkg/status/status_test.go @@ -16,7 +16,6 @@ import ( "github.com/ethersphere/bee/v2/pkg/postage" "github.com/ethersphere/bee/v2/pkg/status" "github.com/ethersphere/bee/v2/pkg/status/internal/pb" - "github.com/ethersphere/bee/v2/pkg/storer" "github.com/ethersphere/bee/v2/pkg/swarm" "github.com/ethersphere/bee/v2/pkg/topology" "github.com/google/go-cmp/cmp" @@ -36,7 +35,7 @@ func TestStatus(t *testing.T) { LastSyncedBlock: 6092500, } - sssMock := &statusSnapshotMock{want, nil} + sssMock := &statusSnapshotMock{want} peersIterMock := new(topologyPeersIterNoopMock) @@ -116,9 +115,7 @@ func TestStatusLightNode(t *testing.T) { StorageRadius: 100, // should be ignored BatchCommitment: 1024, LastSyncedBlock: 6092500, - }, - nil, - } + }} peersIterMock := new(topologyPeersIterNoopMock) @@ -194,7 +191,6 @@ func (m *topologyPeersIterNoopMock) IsReachable() bool { // - SyncReporter type statusSnapshotMock struct { *pb.Snapshot - neighborhoods []*storer.NeighborhoodStat } func (m *statusSnapshotMock) SyncRate() float64 { return m.Snapshot.PullsyncRate } @@ -207,7 +203,3 @@ func (m *statusSnapshotMock) GetChainState() *postage.ChainState { func (m *statusSnapshotMock) ReserveSizeWithinRadius() uint64 { return m.Snapshot.ReserveSizeWithinRadius } - -func (m *statusSnapshotMock) NeighborhoodsStat(ctx context.Context) ([]*storer.NeighborhoodStat, error) { - return m.neighborhoods, nil -} 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 8f85e72f7a3..1a4ec6f21e0 100644 --- a/pkg/storer/reserve.go +++ b/pkg/storer/reserve.go @@ -498,7 +498,7 @@ func (db *DB) SubscribeBin(ctx context.Context, bin uint8, start uint64) (<-chan } type NeighborhoodStat struct { - Address swarm.Address + Neighborhood swarm.Neighborhood ReserveSizeWithinRadius int } @@ -511,12 +511,12 @@ 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 { + 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 72f569b720b..d79e49fec46 100644 --- a/pkg/storer/reserve_test.go +++ b/pkg/storer/reserve_test.go @@ -728,7 +728,10 @@ func TestNeighborhoodStats(t *testing.T) { } } - 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") } } diff --git a/pkg/storer/storer.go b/pkg/storer/storer.go index d3bf812005d..266b92bdce6 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 } 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") + } + } +}