-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
refactor(store/v2): updates from integration #18633
Merged
Merged
Changes from 5 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
dba0457
updates
alexanderbez 5a36fb1
updates
alexanderbez 4540db1
Merge branch 'main' into bez/store-v2-updates
alexanderbez e7bb776
Merge branch 'main' into bez/store-v2-updates
alexanderbez 1f7687b
Merge branch 'main' into bez/store-v2-updates
alexanderbez c4d660b
remove cometBFT imports from store/proof.go
alexanderbez 82560e3
Merge branch 'main' into bez/store-v2-updates
alexanderbez 2305341
Merge branch 'main' into bez/store-v2-updates
alexanderbez File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
package store | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/cometbft/cometbft/crypto/merkle" | ||
cmtcrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" | ||
alexanderbez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ics23 "github.com/cosmos/ics23/go" | ||
|
||
errorsmod "cosmossdk.io/errors" | ||
sdkmaps "cosmossdk.io/store/v2/internal/maps" | ||
sdkproofs "cosmossdk.io/store/v2/internal/proofs" | ||
) | ||
|
||
// Proof operation types | ||
const ( | ||
ProofOpIAVLCommitment = "ics23:iavl" | ||
ProofOpSimpleMerkleCommitment = "ics23:simple" | ||
ProofOpSMTCommitment = "ics23:smt" | ||
) | ||
|
||
var _ merkle.ProofOperator = CommitmentOp{} | ||
|
||
// CommitmentOp implements merkle.ProofOperator by wrapping an ics23 CommitmentProof. | ||
// It also contains a Key field to determine which key the proof is proving. | ||
// NOTE: CommitmentProof currently can either be ExistenceProof or NonexistenceProof | ||
// | ||
// Type and Spec are classified by the kind of merkle proof it represents allowing | ||
// the code to be reused by more types. Spec is never on the wire, but mapped | ||
// from type in the code. | ||
type CommitmentOp struct { | ||
Type string | ||
Key []byte | ||
Spec *ics23.ProofSpec | ||
Proof *ics23.CommitmentProof | ||
} | ||
|
||
func NewIAVLCommitmentOp(key []byte, proof *ics23.CommitmentProof) CommitmentOp { | ||
return CommitmentOp{ | ||
Type: ProofOpIAVLCommitment, | ||
Spec: ics23.IavlSpec, | ||
Key: key, | ||
Proof: proof, | ||
} | ||
} | ||
|
||
func NewSimpleMerkleCommitmentOp(key []byte, proof *ics23.CommitmentProof) CommitmentOp { | ||
return CommitmentOp{ | ||
Type: ProofOpSimpleMerkleCommitment, | ||
Spec: ics23.TendermintSpec, | ||
Key: key, | ||
Proof: proof, | ||
} | ||
} | ||
|
||
func NewSMTCommitmentOp(key []byte, proof *ics23.CommitmentProof) CommitmentOp { | ||
return CommitmentOp{ | ||
Type: ProofOpSMTCommitment, | ||
Spec: ics23.SmtSpec, | ||
Key: key, | ||
Proof: proof, | ||
} | ||
} | ||
|
||
// CommitmentOpDecoder takes a ProofOp and attempts to decode it into a CommitmentOp | ||
// ProofOperator. The proofOp.Data is just a marshaled CommitmentProof. The Key | ||
// of the CommitmentOp is extracted from the unmarshalled proof. | ||
func CommitmentOpDecoder(pop cmtcrypto.ProofOp) (merkle.ProofOperator, error) { | ||
var spec *ics23.ProofSpec | ||
switch pop.Type { | ||
case ProofOpIAVLCommitment: | ||
spec = ics23.IavlSpec | ||
|
||
case ProofOpSimpleMerkleCommitment: | ||
spec = ics23.TendermintSpec | ||
|
||
case ProofOpSMTCommitment: | ||
spec = ics23.SmtSpec | ||
|
||
default: | ||
return nil, errorsmod.Wrapf(ErrInvalidProof, "unexpected ProofOp.Type; got %s, want supported ics23 subtypes 'ProofOpSimpleMerkleCommitment', 'ProofOpIAVLCommitment', or 'ProofOpSMTCommitment'", pop.Type) | ||
} | ||
|
||
proof := &ics23.CommitmentProof{} | ||
if err := proof.Unmarshal(pop.Data); err != nil { | ||
return nil, err | ||
} | ||
|
||
return CommitmentOp{ | ||
Type: pop.Type, | ||
Key: pop.Key, | ||
Spec: spec, | ||
Proof: proof, | ||
}, nil | ||
} | ||
|
||
func (op CommitmentOp) GetKey() []byte { | ||
return op.Key | ||
} | ||
|
||
// Run takes in a list of arguments and attempts to run the proof op against these | ||
// arguments. Returns the root wrapped in [][]byte if the proof op succeeds with | ||
// given args. If not, it will return an error. | ||
// | ||
// CommitmentOp will accept args of length 1 or length 0. If length 1 args is | ||
// passed in, then CommitmentOp will attempt to prove the existence of the key | ||
// with the value provided by args[0] using the embedded CommitmentProof and returns | ||
// the CommitmentRoot of the proof. If length 0 args is passed in, then CommitmentOp | ||
// will attempt to prove the absence of the key in the CommitmentOp and return the | ||
// CommitmentRoot of the proof. | ||
func (op CommitmentOp) Run(args [][]byte) ([][]byte, error) { | ||
// calculate root from proof | ||
root, err := op.Proof.Calculate() | ||
if err != nil { | ||
return nil, errorsmod.Wrapf(ErrInvalidProof, "could not calculate root for proof: %v", err) | ||
alexanderbez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// Only support an existence proof or nonexistence proof (batch proofs currently unsupported) | ||
switch len(args) { | ||
case 0: | ||
// Args are nil, so we verify the absence of the key. | ||
absent := ics23.VerifyNonMembership(op.Spec, root, op.Proof, op.Key) | ||
if !absent { | ||
return nil, errorsmod.Wrapf(ErrInvalidProof, "proof did not verify absence of key: %s", string(op.Key)) | ||
alexanderbez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
case 1: | ||
// Args is length 1, verify existence of key with value args[0] | ||
if !ics23.VerifyMembership(op.Spec, root, op.Proof, op.Key, args[0]) { | ||
return nil, errorsmod.Wrapf(ErrInvalidProof, "proof did not verify existence of key %s with given value %x", op.Key, args[0]) | ||
alexanderbez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
default: | ||
return nil, errorsmod.Wrapf(ErrInvalidProof, "args must be length 0 or 1, got: %d", len(args)) | ||
} | ||
|
||
return [][]byte{root}, nil | ||
} | ||
|
||
// ProofOp implements ProofOperator interface and converts a CommitmentOp into a | ||
// ProofOp format that can later be decoded by CommitmentOpDecoder back into a | ||
// CommitmentOp for proof verification. | ||
func (op CommitmentOp) ProofOp() cmtcrypto.ProofOp { | ||
bz, err := op.Proof.Marshal() | ||
if err != nil { | ||
panic(fmt.Errorf("failed to marshal CommitmentProof: %w", err)) | ||
alexanderbez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
return cmtcrypto.ProofOp{ | ||
Type: op.Type, | ||
Key: op.Key, | ||
Data: bz, | ||
} | ||
} | ||
|
||
// ProofOpFromMap generates a single proof from a map and converts it to a ProofOp. | ||
func ProofOpFromMap(cmap map[string][]byte, storeName string) (cmtcrypto.ProofOp, error) { | ||
_, proofs, _ := sdkmaps.ProofsFromMap(cmap) | ||
|
||
proof := proofs[storeName] | ||
if proof == nil { | ||
return cmtcrypto.ProofOp{}, fmt.Errorf("ProofOp for %s but not registered store name", storeName) | ||
} | ||
|
||
// convert merkle.SimpleProof to CommitmentProof | ||
existProof, err := sdkproofs.ConvertExistenceProof(proof, []byte(storeName), cmap[storeName]) | ||
if err != nil { | ||
return cmtcrypto.ProofOp{}, fmt.Errorf("could not convert simple proof to existence proof: %w", err) | ||
} | ||
|
||
commitmentProof := &ics23.CommitmentProof{ | ||
Proof: &ics23.CommitmentProof_Exist{ | ||
Exist: existProof, | ||
}, | ||
} | ||
|
||
return NewSimpleMerkleCommitmentOp([]byte(storeName), commitmentProof).ProofOp(), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ import ( | |
|
||
"github.com/cockroachdb/errors" | ||
|
||
coreheader "cosmossdk.io/core/header" | ||
"cosmossdk.io/log" | ||
"cosmossdk.io/store/v2" | ||
"cosmossdk.io/store/v2/kv/branch" | ||
|
@@ -43,7 +44,7 @@ type Store struct { | |
rootKVStore store.BranchedKVStore | ||
|
||
// commitHeader reflects the header used when committing state (note, this isn't required and only used for query purposes) | ||
commitHeader store.CommitHeader | ||
commitHeader *coreheader.Info | ||
|
||
// lastCommitInfo reflects the last version/hash that has been committed | ||
lastCommitInfo *store.CommitInfo | ||
|
@@ -66,9 +67,9 @@ type Store struct { | |
|
||
func New( | ||
logger log.Logger, | ||
initVersion uint64, | ||
ss store.VersionedDatabase, | ||
sc store.Committer, | ||
ssOpts, scOpts pruning.Options, | ||
m metrics.StoreMetrics, | ||
) (store.RootStore, error) { | ||
rootKVStore, err := branch.New(defaultStoreKey, ss) | ||
|
@@ -77,10 +78,13 @@ func New( | |
} | ||
|
||
pruningManager := pruning.NewManager(logger, ss, sc) | ||
pruningManager.SetStorageOptions(ssOpts) | ||
pruningManager.SetCommitmentOptions(scOpts) | ||
pruningManager.Start() | ||
|
||
return &Store{ | ||
logger: logger.With("module", "root_store"), | ||
initialVersion: initVersion, | ||
initialVersion: 1, | ||
stateStore: ss, | ||
stateCommitment: sc, | ||
rootKVStore: rootKVStore, | ||
|
@@ -105,23 +109,22 @@ func (s *Store) Close() (err error) { | |
return err | ||
} | ||
|
||
// SetPruningOptions sets the pruning options on the SS and SC backends. | ||
// NOTE: It will also start the pruning manager. | ||
func (s *Store) SetPruningOptions(ssOpts, scOpts pruning.Options) { | ||
s.pruningManager.SetStorageOptions(ssOpts) | ||
s.pruningManager.SetCommitmentOptions(scOpts) | ||
|
||
s.pruningManager.Start() | ||
func (s *Store) SetMetrics(m metrics.Metrics) { | ||
s.telemetry = m | ||
} | ||
|
||
// MountSCStore performs a no-op as a SC backend must be provided at initialization. | ||
func (s *Store) MountSCStore(_ string, _ store.Committer) error { | ||
return errors.New("cannot mount SC store; SC must be provided on initialization") | ||
func (s *Store) SetInitialVersion(v uint64) error { | ||
s.initialVersion = v | ||
|
||
// TODO(bez): Call SetInitialVersion on s.stateCommitment. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
// | ||
// Ref: https://github.com/cosmos/cosmos-sdk/issues/18597 | ||
|
||
return nil | ||
} | ||
|
||
// GetSCStore returns the store's state commitment (SC) backend. Note, the store | ||
// key is ignored as there exists only a single SC tree. | ||
func (s *Store) GetSCStore(_ string) store.Committer { | ||
// GetSCStore returns the store's state commitment (SC) backend. | ||
func (s *Store) GetSCStore() store.Committer { | ||
return s.stateCommitment | ||
} | ||
|
||
|
@@ -191,7 +194,7 @@ func (s *Store) Query(storeKey string, version uint64, key []byte, prove bool) ( | |
return store.QueryResult{}, err | ||
} | ||
|
||
result.Proof = proof | ||
result.Proof = store.NewIAVLCommitmentOp(key, proof) | ||
} | ||
|
||
return result, nil | ||
|
@@ -274,7 +277,7 @@ func (s *Store) TracingEnabled() bool { | |
return s.traceWriter != nil | ||
} | ||
|
||
func (s *Store) SetCommitHeader(h store.CommitHeader) { | ||
func (s *Store) SetCommitHeader(h *coreheader.Info) { | ||
s.commitHeader = h | ||
} | ||
|
||
|
@@ -344,8 +347,8 @@ func (s *Store) Commit() ([]byte, error) { | |
|
||
version := s.lastCommitInfo.Version | ||
|
||
if s.commitHeader != nil && s.commitHeader.GetHeight() != version { | ||
s.logger.Debug("commit header and version mismatch", "header_height", s.commitHeader.GetHeight(), "version", version) | ||
if s.commitHeader != nil && uint64(s.commitHeader.Height) != version { | ||
s.logger.Debug("commit header and version mismatch", "header_height", s.commitHeader.Height, "version", version) | ||
} | ||
|
||
changeset := s.rootKVStore.GetChangeset() | ||
|
@@ -361,7 +364,7 @@ func (s *Store) Commit() ([]byte, error) { | |
} | ||
|
||
if s.commitHeader != nil { | ||
s.lastCommitInfo.Timestamp = s.commitHeader.GetTime() | ||
s.lastCommitInfo.Timestamp = s.commitHeader.Time | ||
} | ||
|
||
if err := s.rootKVStore.Reset(version); err != nil { | ||
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to reviewer(s): This is a direct port from store v1 (with linting/cleanup).