Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(store/v2): RootStore Implementation #17577

Merged
merged 54 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
089280f
updates
alexanderbez Aug 29, 2023
6f868c3
updates
alexanderbez Aug 29, 2023
54dd27a
updates
alexanderbez Aug 29, 2023
466d06f
updates
alexanderbez Aug 29, 2023
ee79932
updates
alexanderbez Aug 30, 2023
92e7767
updates
alexanderbez Sep 3, 2023
57b675f
updates
alexanderbez Sep 3, 2023
63e167b
updates
alexanderbez Sep 3, 2023
f8e9543
updates
alexanderbez Sep 3, 2023
61259cd
updates
alexanderbez Sep 5, 2023
b1c4d42
updates
alexanderbez Sep 5, 2023
e0d188d
updates
alexanderbez Sep 5, 2023
849413c
updates
alexanderbez Sep 5, 2023
cfc1c5f
updates
alexanderbez Sep 5, 2023
45da8a0
updates
alexanderbez Sep 6, 2023
71fd8b2
updates
alexanderbez Sep 6, 2023
a8c1bef
updates
alexanderbez Sep 6, 2023
1e9c0bd
updates
alexanderbez Sep 6, 2023
9869523
updates
alexanderbez Sep 6, 2023
499de87
updates
alexanderbez Sep 6, 2023
2601546
updates
alexanderbez Sep 6, 2023
4dd4c02
updates
alexanderbez Sep 6, 2023
e690be3
updates
alexanderbez Sep 7, 2023
b0b740b
updates
alexanderbez Sep 7, 2023
026c5e5
updates
alexanderbez Sep 7, 2023
73c48dd
updates
alexanderbez Sep 7, 2023
60b3f62
updates
alexanderbez Sep 7, 2023
6882953
updates
alexanderbez Sep 7, 2023
c5d8d27
updates
alexanderbez Sep 7, 2023
860c4a9
Merge branch 'feature/store-v2' into bez/multi-store-poc
alexanderbez Sep 8, 2023
d6a9ef8
updates
alexanderbez Sep 8, 2023
940e062
updates
alexanderbez Sep 10, 2023
d148d71
updates
alexanderbez Sep 10, 2023
a1a1105
updates
alexanderbez Sep 10, 2023
d1bf221
updates
alexanderbez Sep 10, 2023
e292c87
updates
alexanderbez Sep 10, 2023
c64d3f3
updates
alexanderbez Sep 11, 2023
6225e3e
updates
alexanderbez Sep 11, 2023
5588971
updates
alexanderbez Sep 11, 2023
000dca8
updates
alexanderbez Sep 11, 2023
5b65da5
updates
alexanderbez Sep 12, 2023
403f009
lint
alexanderbez Sep 12, 2023
d459bb1
updates
alexanderbez Sep 12, 2023
05a3170
updates
alexanderbez Sep 14, 2023
b830c93
updates
alexanderbez Sep 14, 2023
6b3fc00
updates
alexanderbez Sep 14, 2023
ecb5e91
updates
alexanderbez Sep 14, 2023
e0c423b
Merge branch 'feature/store-v2' into bez/multi-store-poc
alexanderbez Sep 27, 2023
aa335e7
updates
alexanderbez Sep 27, 2023
5e8d7ee
Merge branch 'feature/store-v2' into bez/multi-store-poc
alexanderbez Sep 27, 2023
01320e2
lint++
alexanderbez Sep 27, 2023
b6ab2fb
updates
alexanderbez Sep 27, 2023
451d994
refactor WorkingHash + Commit()
alexanderbez Sep 27, 2023
86efa09
updates
alexanderbez Sep 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions store/branch/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package branch

import (
"io"

"golang.org/x/exp/maps"
"slices"

"cosmossdk.io/store/v2"
)

var (
_ store.KVStore = (*Store)(nil)
_ store.BranchedKVStore = (*Store)(nil)
)

// Store implements both a KVStore and BranchedKVStore interfaces. It is used to
// accumulate writes that can be later committed to backing SS and SC engines or
// discarded altogether. If a read is not found through an uncommitted write, it
// will be delegated to the SS backend.
type Store struct {
// storage reflects backing storage for reads that are not found in uncommitted volatile state
//
// XXX/TODO: We use a SC backend here instead of SS since not all SS backends
// may support reverse iteration (which is needed for state machine logic).
storage store.Tree

// storeKey reflects the store key used for the store
storeKey string
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved

// parent reflects a parent store if branched (it may be nil)
parent store.KVStore

// changeSet reflects the uncommitted writes to the store
//
// Note, this field might be removed depending on how the branching fields
// below are defined and used.
changeSet map[string]store.KVPair

// TODO: Fields for branching functionality. These fields should most likely
// reflect what currently exists in cachekv.Store.
}

func New(storeKey string, sc store.Tree) store.KVStore {
return &Store{
storage: sc,
storeKey: storeKey,
changeSet: make(map[string]store.KVPair),
}
}

func (s *Store) GetStoreType() store.StoreType {
return store.StoreTypeBranch
}

// GetChangeSet returns the uncommitted writes to the store, ordered by key.
func (s *Store) GetChangeSet() *store.ChangeSet {
keys := maps.Keys(s.changeSet)
slices.Sort(keys)

pairs := make([]store.KVPair, len(keys))
for i, key := range keys {
pairs[i] = s.changeSet[key]
}

return store.NewChangeSet(pairs...)
}

func (s *Store) Reset() {
clear(s.changeSet)
}

func (s *Store) Branch() store.BranchedKVStore {
panic("not implemented!")
}

func (s *Store) BranchWithTrace(w io.Writer, tc store.TraceContext) store.BranchedKVStore {
panic("not implemented!")
}

func (s *Store) Iterator(start, end []byte) store.Iterator {
panic("not implemented!")
}

func (s *Store) ReverseIterator(start, end []byte) store.Iterator {
panic("not implemented!")
}

func (s *Store) Get(key []byte) []byte {
panic("not implemented!")
}

func (s *Store) Has(key []byte) bool {
panic("not implemented!")
}

func (s *Store) Set(key, value []byte) {
panic("not implemented!")
}

func (s *Store) Delete(key []byte) {
panic("not implemented!")
}

func (s *Store) Write() {
panic("not implemented!")
}
39 changes: 39 additions & 0 deletions store/change_set.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package store

// KVPair defines a key-value pair with additional metadata that is used to
// track writes. Deletion can be denoted by a nil value or explicitly by the
// Delete field.
type KVPair struct {
Key []byte
Value []byte
StoreKey string // optional
}

// ChangeSet defines a set of KVPair entries.
type ChangeSet struct {
Pairs []KVPair
}

func NewChangeSet(pairs ...KVPair) *ChangeSet {
return &ChangeSet{
Pairs: pairs,
}
}

// Size returns the number of key-value pairs in the batch.
func (cs *ChangeSet) Size() int {
return len(cs.Pairs)
}

// Add adds a key-value pair to the ChangeSet.
func (cs *ChangeSet) Add(key, value []byte) {
cs.Pairs = append(cs.Pairs, KVPair{
Key: key,
Value: value,
})
}

// AddKVPair adds a KVPair to the ChangeSet.
func (cs *ChangeSet) AddKVPair(pair KVPair) {
cs.Pairs = append(cs.Pairs, pair)
}
82 changes: 82 additions & 0 deletions store/commit_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package store

import (
"fmt"
"time"

"cosmossdk.io/store/v2/internal/maps"
)

type (
// CommitHeader defines the interface for a block header that can be provided
// to a MultiStore upon Commit. This should be optional and used to facilitate
// time-based queries only.
CommitHeader interface {
GetTime() time.Time
GetHeight() uint64
}

// CommitInfo defines commit information used by the multi-store when committing
// a version/height.
CommitInfo struct {
Version uint64
StoreInfos []StoreInfo
Timestamp time.Time
}

// StoreInfo defines store-specific commit information. It contains a reference
// between a store name/key and the commit ID.
StoreInfo struct {
Name string
CommitID CommitID
}

// CommitID defines the commitment information when a specific store is
// committed.
CommitID struct {
Version uint64
Hash []byte
}
)

func (si StoreInfo) GetHash() []byte {
return si.CommitID.Hash
}

// Hash returns the root hash of all committed stores represented by CommitInfo,
// sorted by store name/key.
func (ci CommitInfo) Hash() []byte {
if len(ci.StoreInfos) == 0 {
return nil
}

rootHash, _, _ := maps.ProofsFromMap(ci.toMap())
return rootHash
}

func (ci CommitInfo) toMap() map[string][]byte {
m := make(map[string][]byte, len(ci.StoreInfos))
for _, storeInfo := range ci.StoreInfos {
m[storeInfo.Name] = storeInfo.GetHash()
}

return m
}

func (ci CommitInfo) CommitID() CommitID {
return CommitID{
Version: ci.Version,
Hash: ci.Hash(),
}
}

func (m *CommitInfo) GetVersion() uint64 {
if m != nil {
return m.Version
}
return 0
}

func (cid CommitID) String() string {
return fmt.Sprintf("CommitID{%v:%X}", cid.Hash, cid.Version)
}
3 changes: 3 additions & 0 deletions store/commitment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# State Commitment (SC)

TODO
10 changes: 5 additions & 5 deletions store/commitment/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,30 @@ import (

ics23 "github.com/cosmos/ics23/go"

"cosmossdk.io/store/v2/commitment/types"
"cosmossdk.io/store/v2"
)

// Database represents a state commitment store. It is designed to securely store
// and manage the most recent state information, crucial for achieving consensus.
// Each module creates its own instance of Database for managing its specific state.
type Database struct {
mu sync.Mutex
tree types.Tree
tree store.Tree
}

// NewDatabase creates a new Database instance.
func NewDatabase(tree types.Tree) *Database {
func NewDatabase(tree store.Tree) *Database {
return &Database{
tree: tree,
}
}

// WriteBatch writes a batch of key-value pairs to the database.
func (db *Database) WriteBatch(batch *types.Batch) error {
func (db *Database) WriteBatch(cs *store.ChangeSet) error {
db.mu.Lock()
defer db.mu.Unlock()

return db.tree.WriteBatch(batch)
return db.tree.WriteBatch(cs)
}

// WorkingHash returns the working hash of the database.
Expand Down
30 changes: 15 additions & 15 deletions store/commitment/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import (
"github.com/stretchr/testify/require"

"cosmossdk.io/log"
"cosmossdk.io/store/v2"
"cosmossdk.io/store/v2/commitment/iavl"
"cosmossdk.io/store/v2/commitment/types"
)

func generateTree(treeType string) types.Tree {
func generateTree(treeType string) store.Tree {
if treeType == "iavl" {
cfg := iavl.DefaultConfig()
db := dbm.NewMemDB()
Expand All @@ -28,16 +28,16 @@ func TestIavlTree(t *testing.T) {
tree := generateTree("iavl")
require.NotNil(t, tree)

intialVersion := tree.GetLatestVersion()
require.Equal(t, uint64(0), intialVersion)
initVersion := tree.GetLatestVersion()
require.Equal(t, uint64(0), initVersion)

// write a batch of version 1
batch1 := types.NewBatch()
batch1.Add([]byte("key1"), []byte("value1"))
batch1.Add([]byte("key2"), []byte("value2"))
batch1.Add([]byte("key3"), []byte("value3"))
cs1 := store.NewChangeSet()
cs1.Add([]byte("key1"), []byte("value1"))
cs1.Add([]byte("key2"), []byte("value2"))
cs1.Add([]byte("key3"), []byte("value3"))

err := tree.WriteBatch(batch1)
err := tree.WriteBatch(cs1)
require.NoError(t, err)

workingHash := tree.WorkingHash()
Expand All @@ -52,12 +52,12 @@ func TestIavlTree(t *testing.T) {
version1Hash := tree.WorkingHash()

// write a batch of version 2
batch2 := types.NewBatch()
batch2.Add([]byte("key4"), []byte("value4"))
batch2.Add([]byte("key5"), []byte("value5"))
batch2.Add([]byte("key6"), []byte("value6"))
batch2.Add([]byte("key1"), nil) // delete key1
err = tree.WriteBatch(batch2)
cs2 := store.NewChangeSet()
cs2.Add([]byte("key4"), []byte("value4"))
cs2.Add([]byte("key5"), []byte("value5"))
cs2.Add([]byte("key6"), []byte("value6"))
cs2.Add([]byte("key1"), nil) // delete key1
err = tree.WriteBatch(cs2)
require.NoError(t, err)
workingHash = tree.WorkingHash()
require.NotNil(t, workingHash)
Expand Down
8 changes: 4 additions & 4 deletions store/commitment/iavl/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import (
ics23 "github.com/cosmos/ics23/go"

log "cosmossdk.io/log"
commitmenttypes "cosmossdk.io/store/v2/commitment/types"
"cosmossdk.io/store/v2"
)

var _ commitmenttypes.Tree = (*IavlTree)(nil)
var _ store.Tree = (*IavlTree)(nil)

// IavlTree is a wrapper around iavl.MutableTree.
type IavlTree struct {
Expand All @@ -27,8 +27,8 @@ func NewIavlTree(db dbm.DB, logger log.Logger, cfg *Config) *IavlTree {
}

// WriteBatch writes a batch of key-value pairs to the database.
func (t *IavlTree) WriteBatch(batch *commitmenttypes.Batch) error {
for _, kv := range batch.Pairs {
func (t *IavlTree) WriteBatch(cs *store.ChangeSet) error {
for _, kv := range cs.Pairs {
if kv.Value == nil {
_, res, err := t.tree.Remove(kv.Key)
if err != nil {
Expand Down
33 changes: 0 additions & 33 deletions store/commitment/types/batch.go

This file was deleted.

Loading
Loading