Skip to content

Commit

Permalink
task(storage/child-trie): implement store/load of child trie from DB (#…
Browse files Browse the repository at this point in the history
…2122)

Fixes #1490
  • Loading branch information
kishansagathiya authored Jan 11, 2022
1 parent 790dfb5 commit 0cc4006
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 5 deletions.
51 changes: 51 additions & 0 deletions dot/state/storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import (

"github.com/ChainSafe/gossamer/dot/state/pruner"
"github.com/ChainSafe/gossamer/dot/types"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/genesis"
runtime "github.com/ChainSafe/gossamer/lib/runtime/storage"
"github.com/ChainSafe/gossamer/lib/trie"
"github.com/ChainSafe/gossamer/lib/utils"

"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -183,3 +186,51 @@ func TestStorage_StoreTrie_NotSyncing(t *testing.T) {
require.NoError(t, err)
require.Equal(t, 2, syncMapLen(storage.tries))
}

func TestGetStorageChildAndGetStorageFromChild(t *testing.T) {
// initialise database using data directory
basepath := t.TempDir()
db, err := utils.SetupDatabase(basepath, false)
require.NoError(t, err)

_, genTrie, genHeader := genesis.NewTestGenesisWithTrieAndHeader(t)

blockState, err := NewBlockStateFromGenesis(db, genHeader)
require.NoError(t, err)

testChildTrie := trie.NewEmptyTrie()
testChildTrie.Put([]byte("keyInsidechild"), []byte("voila"))

err = genTrie.PutChild([]byte("keyToChild"), testChildTrie)
require.NoError(t, err)

storage, err := NewStorageState(db, blockState, genTrie, pruner.Config{})
require.NoError(t, err)

trieState, err := runtime.NewTrieState(genTrie)
require.NoError(t, err)

header, err := types.NewHeader(blockState.GenesisHash(), trieState.MustRoot(),
common.Hash{}, big.NewInt(1), types.NewDigest())
require.NoError(t, err)

err = storage.StoreTrie(trieState, header)
require.NoError(t, err)

rootHash, err := genTrie.Hash()
require.NoError(t, err)

_, err = storage.GetStorageChild(&rootHash, []byte("keyToChild"))
require.NoError(t, err)

// Clear trie from cache and fetch data from disk.
storage.tries.Delete(rootHash)

_, err = storage.GetStorageChild(&rootHash, []byte("keyToChild"))
require.NoError(t, err)

value, err := storage.GetStorageFromChild(&rootHash, []byte("keyToChild"), []byte("keyInsidechild"))
require.NoError(t, err)

require.Equal(t, []byte("voila"), value)
}
3 changes: 2 additions & 1 deletion lib/runtime/storage/trie_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package storage
import (
"bytes"
"encoding/binary"
"fmt"
"sort"
"testing"

Expand Down Expand Up @@ -221,7 +222,7 @@ func TestTrieState_DeleteChildLimit(t *testing.T) {
limit: optLimit2,
expectedDeleted: 0,
expectedDelAll: false,
errMsg: "child trie does not exist at key :child_storage:default:fakekey",
errMsg: fmt.Sprintf("child trie does not exist at key 0x%x", ":child_storage:default:fakekey"),
},
{key: []byte("keytochild"), limit: optLimit2, expectedDeleted: 2, expectedDelAll: false},
{key: []byte("keytochild"), limit: nil, expectedDeleted: 1, expectedDelAll: true},
Expand Down
11 changes: 7 additions & 4 deletions lib/trie/child_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package trie

import (
"errors"
"fmt"

"github.com/ChainSafe/gossamer/lib/common"
Expand All @@ -12,6 +13,8 @@ import (
// ChildStorageKeyPrefix is the prefix for all child storage keys
var ChildStorageKeyPrefix = []byte(":child_storage:default:")

var ErrChildTrieDoesNotExist = errors.New("child trie does not exist")

// PutChild inserts a child trie into the main trie at key :child_storage:[keyToChild]
func (t *Trie) PutChild(keyToChild []byte, child *Trie) error {
childHash, err := child.Hash()
Expand All @@ -32,7 +35,7 @@ func (t *Trie) GetChild(keyToChild []byte) (*Trie, error) {
key := append(ChildStorageKeyPrefix, keyToChild...)
childHash := t.Get(key)
if childHash == nil {
return nil, fmt.Errorf("child trie does not exist at key %s%s", ChildStorageKeyPrefix, keyToChild)
return nil, fmt.Errorf("%w at key 0x%x%x", ErrChildTrieDoesNotExist, ChildStorageKeyPrefix, keyToChild)
}

hash := [32]byte{}
Expand All @@ -58,7 +61,7 @@ func (t *Trie) PutIntoChild(keyToChild, key, value []byte) error {
return err
}

t.childTries[origChildHash] = nil
delete(t.childTries, origChildHash)
t.childTries[childHash] = child

return t.PutChild(keyToChild, child)
Expand All @@ -73,7 +76,7 @@ func (t *Trie) GetFromChild(keyToChild, key []byte) ([]byte, error) {
}

if child == nil {
return nil, fmt.Errorf("child trie does not exist at key %s%s", ChildStorageKeyPrefix, keyToChild)
return nil, fmt.Errorf("%w at key 0x%x%x", ErrChildTrieDoesNotExist, ChildStorageKeyPrefix, keyToChild)
}

val := child.Get(key)
Expand All @@ -93,7 +96,7 @@ func (t *Trie) ClearFromChild(keyToChild, key []byte) error {
return err
}
if child == nil {
return fmt.Errorf("child trie does not exist at key %s%s", ChildStorageKeyPrefix, keyToChild)
return fmt.Errorf("%w at key 0x%x%x", ErrChildTrieDoesNotExist, ChildStorageKeyPrefix, keyToChild)
}
child.Delete(key)
return nil
Expand Down
27 changes: 27 additions & 0 deletions lib/trie/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ var (
// and the value is the encoded node.
// Generally, this will only be used for the genesis trie.
func (t *Trie) Store(db chaindb.Database) error {
for _, v := range t.childTries {
if err := v.Store(db); err != nil {
return fmt.Errorf("failed to store child trie with root hash=0x%x in the db: %w", v.root.GetHash(), err)
}
}

batch := db.NewBatch()
err := t.store(batch, t.root)
if err != nil {
Expand Down Expand Up @@ -201,6 +207,21 @@ func (t *Trie) load(db chaindb.Database, n Node) error {
}
}

for _, key := range t.GetKeysWithPrefix(ChildStorageKeyPrefix) {
childTrie := NewEmptyTrie()
value := t.Get(key)
err := childTrie.Load(db, common.NewHash(value))
if err != nil {
return fmt.Errorf("failed to load child trie with root hash=0x%x: %w", value, err)
}

err = t.PutChild(value, childTrie)
if err != nil {
return fmt.Errorf("failed to insert child trie with root hash=0x%x into main trie: %w",
childTrie.root.GetHash(), err)
}
}

return nil
}

Expand Down Expand Up @@ -395,6 +416,12 @@ func (t *Trie) writeDirty(db chaindb.Batch, n Node) error {
}
}

for _, childTrie := range t.childTries {
if err := childTrie.writeDirty(db, childTrie.root); err != nil {
return fmt.Errorf("failed to write dirty node=0x%x to database: %w", childTrie.root.GetHash(), err)
}
}

branch.SetDirty(false)

return nil
Expand Down

0 comments on commit 0cc4006

Please sign in to comment.