Skip to content

Commit 41597c2

Browse files
holisticodenonsense
authored andcommitted
swarm: Debug API and HasChunks() API endpoint (ethereum#18980)
1 parent 33d0a0e commit 41597c2

File tree

12 files changed

+145
-37
lines changed

12 files changed

+145
-37
lines changed

cmd/swarm/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,5 +468,5 @@ func setSwarmBootstrapNodes(ctx *cli.Context, cfg *node.Config) {
468468
}
469469
cfg.P2P.BootstrapNodes = append(cfg.P2P.BootstrapNodes, node)
470470
}
471-
log.Debug("added default swarm bootnodes", "length", len(cfg.P2P.BootstrapNodes))
471+
472472
}

swarm/api/inspector.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2019 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package api
18+
19+
import (
20+
"context"
21+
22+
"github.com/ethereum/go-ethereum/swarm/network"
23+
"github.com/ethereum/go-ethereum/swarm/storage"
24+
)
25+
26+
type Inspector struct {
27+
api *API
28+
hive *network.Hive
29+
netStore *storage.NetStore
30+
}
31+
32+
func NewInspector(api *API, hive *network.Hive, netStore *storage.NetStore) *Inspector {
33+
return &Inspector{api, hive, netStore}
34+
}
35+
36+
// Hive prints the kademlia table
37+
func (inspector *Inspector) Hive() string {
38+
return inspector.hive.String()
39+
}
40+
41+
type HasInfo struct {
42+
Addr string `json:"address"`
43+
Has bool `json:"has"`
44+
}
45+
46+
// Has checks whether each chunk address is present in the underlying datastore,
47+
// the bool in the returned structs indicates if the underlying datastore has
48+
// the chunk stored with the given address (true), or not (false)
49+
func (inspector *Inspector) Has(chunkAddresses []storage.Address) []HasInfo {
50+
results := make([]HasInfo, 0)
51+
for _, addr := range chunkAddresses {
52+
res := HasInfo{}
53+
res.Addr = addr.String()
54+
res.Has = inspector.netStore.Has(context.Background(), addr)
55+
results = append(results, res)
56+
}
57+
return results
58+
}

swarm/api/testapi.go

Lines changed: 0 additions & 34 deletions
This file was deleted.

swarm/network/stream/common_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ func newRoundRobinStore(stores ...storage.ChunkStore) *roundRobinStore {
214214
}
215215
}
216216

217+
// not used in this context, only to fulfill ChunkStore interface
218+
func (rrs *roundRobinStore) Has(ctx context.Context, addr storage.Address) bool {
219+
panic("RoundRobinStor doesn't support HasChunk")
220+
}
221+
217222
func (rrs *roundRobinStore) Get(ctx context.Context, addr storage.Address) (storage.Chunk, error) {
218223
return nil, errors.New("get not well defined on round robin store")
219224
}

swarm/storage/common_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,15 @@ func (m *MapChunkStore) Get(_ context.Context, ref Address) (Chunk, error) {
267267
return chunk, nil
268268
}
269269

270+
// Need to implement Has from SyncChunkStore
271+
func (m *MapChunkStore) Has(ctx context.Context, ref Address) bool {
272+
m.mu.RLock()
273+
defer m.mu.RUnlock()
274+
275+
_, has := m.chunks[ref.Hex()]
276+
return has
277+
}
278+
270279
func (m *MapChunkStore) Close() {
271280
}
272281

swarm/storage/ldbstore.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,18 @@ func (s *LDBStore) Get(_ context.Context, addr Address) (chunk Chunk, err error)
969969
return s.get(addr)
970970
}
971971

972+
// Has queries the underlying DB if a chunk with the given address is stored
973+
// Returns true if the chunk is found, false if not
974+
func (s *LDBStore) Has(_ context.Context, addr Address) bool {
975+
s.lock.RLock()
976+
defer s.lock.RUnlock()
977+
978+
ikey := getIndexKey(addr)
979+
_, err := s.db.Get(ikey)
980+
981+
return err == nil
982+
}
983+
972984
// TODO: To conform with other private methods of this object indices should not be updated
973985
func (s *LDBStore) get(addr Address) (chunk *chunk, err error) {
974986
if s.closed {

swarm/storage/localstore.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@ func (ls *LocalStore) Put(ctx context.Context, chunk Chunk) error {
132132
return err
133133
}
134134

135+
// Has queries the underlying DbStore if a chunk with the given address
136+
// is being stored there.
137+
// Returns true if it is stored, false if not
138+
func (ls *LocalStore) Has(ctx context.Context, addr Address) bool {
139+
return ls.DbStore.Has(ctx, addr)
140+
}
141+
135142
// Get(chunk *Chunk) looks up a chunk in the local stores
136143
// This method is blocking until the chunk is retrieved
137144
// so additional timeout may be needed to wrap this call if

swarm/storage/localstore_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,36 @@ func setupLocalStore(t *testing.T, ldbCap int) (ls *LocalStore, cleanup func())
209209

210210
return store, cleanup
211211
}
212+
213+
func TestHas(t *testing.T) {
214+
ldbCap := defaultGCRatio
215+
store, cleanup := setupLocalStore(t, ldbCap)
216+
defer cleanup()
217+
218+
nonStoredAddr := GenerateRandomChunk(128).Address()
219+
220+
has := store.Has(context.Background(), nonStoredAddr)
221+
if has {
222+
t.Fatal("Expected Has() to return false, but returned true!")
223+
}
224+
225+
storeChunks := GenerateRandomChunks(128, 3)
226+
for _, ch := range storeChunks {
227+
err := store.Put(context.Background(), ch)
228+
if err != nil {
229+
t.Fatalf("Expected store to store chunk, but it failed: %v", err)
230+
}
231+
232+
has := store.Has(context.Background(), ch.Address())
233+
if !has {
234+
t.Fatal("Expected Has() to return true, but returned false!")
235+
}
236+
}
237+
238+
//let's be paranoic and test again that the non-existent chunk returns false
239+
has = store.Has(context.Background(), nonStoredAddr)
240+
if has {
241+
t.Fatal("Expected Has() to return false, but returned true!")
242+
}
243+
244+
}

swarm/storage/memstore.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ func NewMemStore(params *StoreParams, _ *LDBStore) (m *MemStore) {
4848
}
4949
}
5050

51+
// Has needed to implement SyncChunkStore
52+
func (m *MemStore) Has(_ context.Context, addr Address) bool {
53+
return m.cache.Contains(addr)
54+
}
55+
5156
func (m *MemStore) Get(_ context.Context, addr Address) (Chunk, error) {
5257
if m.disabled {
5358
return nil, ErrChunkNotFound

swarm/storage/netstore.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,13 @@ func (n *NetStore) get(ctx context.Context, ref Address) (Chunk, func(context.Co
158158
return chunk, nil, nil
159159
}
160160

161+
// Has is the storage layer entry point to query the underlying
162+
// database to return if it has a chunk or not.
163+
// Called from the DebugAPI
164+
func (n *NetStore) Has(ctx context.Context, ref Address) bool {
165+
return n.store.Has(ctx, ref)
166+
}
167+
161168
// getOrCreateFetcher attempts at retrieving an existing fetchers
162169
// if none exists, creates one and saves it in the fetchers cache
163170
// caller must hold the lock

0 commit comments

Comments
 (0)