diff --git a/portalnetwork/storage/content_storage.go b/portalnetwork/storage/content_storage.go index 3a01df93f6..e726d612e5 100644 --- a/portalnetwork/storage/content_storage.go +++ b/portalnetwork/storage/content_storage.go @@ -12,6 +12,9 @@ var MaxDistance = uint256.MustFromHex("0xfffffffffffffffffffffffffffffffffffffff type ContentType byte +var RadisuKey = []byte("radius") +var SizeKey = []byte("size") + type ContentKey struct { selector ContentType data []byte diff --git a/portalnetwork/storage/ethpepple/storage.go b/portalnetwork/storage/ethpepple/storage.go new file mode 100644 index 0000000000..b074de1e4c --- /dev/null +++ b/portalnetwork/storage/ethpepple/storage.go @@ -0,0 +1,79 @@ +package ethpepple + +import ( + "sync/atomic" + + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/pebble" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/portalnetwork/storage" + "github.com/holiman/uint256" +) + +var _ storage.ContentStorage = &ContentStorage{} + +type PeppleStorageConfig struct { + StorageCapacityMB uint64 + DB ethdb.KeyValueStore + NodeId enode.ID + NetworkName string +} + +func NewPeppleDB(dataDir string, cache, handles int, namespace string) (ethdb.KeyValueStore, error) { + db, err := pebble.New(dataDir + "/" + namespace, cache, handles, namespace, false) + return db, err +} + +type ContentStorage struct { + nodeId enode.ID + storageCapacityInBytes uint64 + radius atomic.Value + // size uint64 + log log.Logger + db ethdb.KeyValueStore +} + +func NewPeppleStorage(config PeppleStorageConfig) (storage.ContentStorage, error) { + cs := &ContentStorage{ + nodeId: config.NodeId, + db: config.DB, + storageCapacityInBytes: config.StorageCapacityMB * 1000_000, + log: log.New("storage", config.NetworkName), + } + cs.radius.Store(storage.MaxDistance) + exist, err := cs.db.Has(storage.RadisuKey); + if err != nil { + return nil, err + } + if exist { + radius, err := cs.db.Get(storage.RadisuKey) + if err != nil { + return nil, err + } + dis := uint256.NewInt(0) + err = dis.UnmarshalSSZ(radius) + if err != nil { + return nil, err + } + cs.radius.Store(dis) + } + return cs, nil +} + +// Get implements storage.ContentStorage. +func (c *ContentStorage) Get(contentKey []byte, contentId []byte) ([]byte, error) { + return c.db.Get(contentId) +} + +// Put implements storage.ContentStorage. +func (c *ContentStorage) Put(contentKey []byte, contentId []byte, content []byte) error { + return c.db.Put(contentId, content) +} + +// Radius implements storage.ContentStorage. +func (p *ContentStorage) Radius() *uint256.Int { + radius := p.radius.Load() + val := radius.(*uint256.Int) + return val +} diff --git a/portalnetwork/storage/ethpepple/storage_test.go b/portalnetwork/storage/ethpepple/storage_test.go new file mode 100644 index 0000000000..ddf69333e5 --- /dev/null +++ b/portalnetwork/storage/ethpepple/storage_test.go @@ -0,0 +1,74 @@ +package ethpepple + +import ( + "os" + "testing" + + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/portalnetwork/storage" + "github.com/holiman/uint256" + "github.com/stretchr/testify/assert" +) + +const dataDir = "./node1" +var testRadius = uint256.NewInt(100000) + +func clearNodeData() { + _ = os.RemoveAll(dataDir) +} + +func getTestDb() (storage.ContentStorage, error) { + db, err := NewPeppleDB(dataDir, 100, 100, "history") + if err != nil { + return nil, err + } + config := PeppleStorageConfig{ + DB: db, + StorageCapacityMB: 100, + NodeId: enode.ID{}, + NetworkName: "history", + } + return NewPeppleStorage(config) +} + +func TestReadRadius(t *testing.T) { + db, err := getTestDb() + assert.NoError(t, err) + defer clearNodeData() + assert.True(t, db.Radius().Eq(storage.MaxDistance)) + + data, err := testRadius.MarshalSSZ() + assert.NoError(t, err) + db.Put(nil, storage.RadisuKey, data) + + store := db.(*ContentStorage) + err = store.db.Close() + assert.NoError(t, err) + + db, err = getTestDb() + assert.NoError(t, err) + assert.True(t, db.Radius().Eq(testRadius)) +} + +func TestStorage(t *testing.T) { + db, err := getTestDb() + assert.NoError(t, err) + defer clearNodeData() + testcases := map[string][]byte{ + "test1": []byte("test1"), + "test2": []byte("test2"), + "test3": []byte("test3"), + "test4": []byte("test4"), + } + + for key, value := range testcases { + db.Put(nil, []byte(key), value) + } + + for key, value := range testcases { + val, err := db.Get(nil, []byte(key)) + assert.NoError(t, err) + assert.Equal(t, value, val) + } + +} \ No newline at end of file