feat(store/v2): Merge Feature Branch (#18150)
Co-authored-by: cool-developer <51834436+cool-develope@users.noreply.github.com> Co-authored-by: yihuang <huang@crypto.com>
This commit is contained in:
co-authored by
cool-developer
yihuang
parent
7b90fc0664
commit
03bca7b791
@@ -0,0 +1,3 @@
|
||||
# State Commitment (SC)
|
||||
|
||||
TODO
|
||||
@@ -0,0 +1,80 @@
|
||||
package commitment
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
ics23 "github.com/cosmos/ics23/go"
|
||||
|
||||
"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 store.Tree
|
||||
}
|
||||
|
||||
// NewDatabase creates a new Database instance.
|
||||
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(cs *store.Changeset) error {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
return db.tree.WriteBatch(cs)
|
||||
}
|
||||
|
||||
// WorkingHash returns the working hash of the database.
|
||||
func (db *Database) WorkingHash() []byte {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
return db.tree.WorkingHash()
|
||||
}
|
||||
|
||||
// LoadVersion loads the state at the given version.
|
||||
func (db *Database) LoadVersion(version uint64) error {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
return db.tree.LoadVersion(version)
|
||||
}
|
||||
|
||||
// Commit commits the current state to the database.
|
||||
func (db *Database) Commit() ([]byte, error) {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
return db.tree.Commit()
|
||||
}
|
||||
|
||||
// GetProof returns a proof for the given key and version.
|
||||
func (db *Database) GetProof(version uint64, key []byte) (*ics23.CommitmentProof, error) {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
return db.tree.GetProof(version, key)
|
||||
}
|
||||
|
||||
// GetLatestVersion returns the latest version of the database.
|
||||
func (db *Database) GetLatestVersion() uint64 {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
return db.tree.GetLatestVersion()
|
||||
}
|
||||
|
||||
// Close closes the database and releases all resources.
|
||||
func (db *Database) Close() error {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
return db.tree.Close()
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package commitment
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
dbm "github.com/cosmos/cosmos-db"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/store/v2"
|
||||
"cosmossdk.io/store/v2/commitment/iavl"
|
||||
)
|
||||
|
||||
func generateTree(treeType string) store.Tree {
|
||||
if treeType == "iavl" {
|
||||
cfg := iavl.DefaultConfig()
|
||||
db := dbm.NewMemDB()
|
||||
tree := iavl.NewIavlTree(db, log.NewNopLogger(), cfg)
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestIavlTree(t *testing.T) {
|
||||
// generate a new tree
|
||||
tree := generateTree("iavl")
|
||||
require.NotNil(t, tree)
|
||||
|
||||
initVersion := tree.GetLatestVersion()
|
||||
require.Equal(t, uint64(0), initVersion)
|
||||
|
||||
// write a batch of version 1
|
||||
cs1 := store.NewChangeset()
|
||||
cs1.Add([]byte("key1"), []byte("value1"))
|
||||
cs1.Add([]byte("key2"), []byte("value2"))
|
||||
cs1.Add([]byte("key3"), []byte("value3"))
|
||||
|
||||
err := tree.WriteBatch(cs1)
|
||||
require.NoError(t, err)
|
||||
|
||||
workingHash := tree.WorkingHash()
|
||||
require.NotNil(t, workingHash)
|
||||
require.Equal(t, uint64(0), tree.GetLatestVersion())
|
||||
|
||||
// commit the batch
|
||||
commitHash, err := tree.Commit()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, workingHash, commitHash)
|
||||
require.Equal(t, uint64(1), tree.GetLatestVersion())
|
||||
version1Hash := tree.WorkingHash()
|
||||
|
||||
// write a batch of version 2
|
||||
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)
|
||||
commitHash, err = tree.Commit()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, workingHash, commitHash)
|
||||
|
||||
// get proof for key1
|
||||
proof, err := tree.GetProof(1, []byte("key1"))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, proof.GetExist())
|
||||
|
||||
proof, err = tree.GetProof(2, []byte("key1"))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, proof.GetNonexist())
|
||||
|
||||
// load version 1
|
||||
err = tree.LoadVersion(1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, version1Hash, tree.WorkingHash())
|
||||
|
||||
// close the db
|
||||
require.NoError(t, tree.Close())
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package iavl
|
||||
|
||||
// Config is the configuration for the IAVL tree.
|
||||
type Config struct {
|
||||
CacheSize int `mapstructure:"cache_size"`
|
||||
SkipFastStorageUpgrade bool `mapstructure:"skip_fast_storage_upgrade"`
|
||||
}
|
||||
|
||||
// DefaultConfig returns the default configuration for the IAVL tree.
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
CacheSize: 1000,
|
||||
SkipFastStorageUpgrade: false,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package iavl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
dbm "github.com/cosmos/cosmos-db"
|
||||
"github.com/cosmos/iavl"
|
||||
ics23 "github.com/cosmos/ics23/go"
|
||||
|
||||
log "cosmossdk.io/log"
|
||||
"cosmossdk.io/store/v2"
|
||||
)
|
||||
|
||||
var _ store.Tree = (*IavlTree)(nil)
|
||||
|
||||
// IavlTree is a wrapper around iavl.MutableTree.
|
||||
type IavlTree struct {
|
||||
tree *iavl.MutableTree
|
||||
}
|
||||
|
||||
// NewIavlTree creates a new IavlTree instance.
|
||||
func NewIavlTree(db dbm.DB, logger log.Logger, cfg *Config) *IavlTree {
|
||||
tree := iavl.NewMutableTree(db, cfg.CacheSize, cfg.SkipFastStorageUpgrade, logger)
|
||||
return &IavlTree{
|
||||
tree: tree,
|
||||
}
|
||||
}
|
||||
|
||||
// WriteBatch writes a batch of key-value pairs to the database.
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
if !res {
|
||||
return fmt.Errorf("failed to delete key %X", kv.Key)
|
||||
}
|
||||
} else {
|
||||
_, err := t.tree.Set(kv.Key, kv.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WorkingHash returns the working hash of the database.
|
||||
func (t *IavlTree) WorkingHash() []byte {
|
||||
return t.tree.WorkingHash()
|
||||
}
|
||||
|
||||
// LoadVersion loads the state at the given version.
|
||||
func (t *IavlTree) LoadVersion(version uint64) error {
|
||||
return t.tree.LoadVersionForOverwriting(int64(version))
|
||||
}
|
||||
|
||||
// Commit commits the current state to the database.
|
||||
func (t *IavlTree) Commit() ([]byte, error) {
|
||||
hash, _, err := t.tree.SaveVersion()
|
||||
return hash, err
|
||||
}
|
||||
|
||||
// GetProof returns a proof for the given key and version.
|
||||
func (t *IavlTree) GetProof(version uint64, key []byte) (*ics23.CommitmentProof, error) {
|
||||
imutableTree, err := t.tree.GetImmutable(int64(version))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return imutableTree.GetProof(key)
|
||||
}
|
||||
|
||||
// GetLatestVersion returns the latest version of the database.
|
||||
func (t *IavlTree) GetLatestVersion() uint64 {
|
||||
return uint64(t.tree.Version())
|
||||
}
|
||||
|
||||
// Close closes the iavl tree.
|
||||
func (t *IavlTree) Close() error {
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user