-
Notifications
You must be signed in to change notification settings - Fork 14
feat: Fraud Proof generation and partial verification using IAVL store #1
feat: Fraud Proof generation and partial verification using IAVL store #1
Conversation
4e5b2c6
to
d6b7a07
Compare
|
||
appHash, err := cms.GetAppHash() | ||
if err != nil { | ||
panic(err) |
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.
Is calling panic a standard pulled from the cosmos sdk?
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.
Yes, for ABCI
methods, if something goes wrong, there's no way to gracefully throw an error other than panic
. If you look at the BeginBlock
implementation, you'll see panic
calls.
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.
💪
As discussed Yesterday, small issues should be addressed now, bigger ones can be extracted as followup-issues and implemented later.
cms := app.cms.(*rootmulti.Store) | ||
err := cms.LoadLastVersion() | ||
if err != nil { | ||
panic(err) |
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.
Is there any situation when this can happen? Because of pruning settings, genesis block?
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.
Happens when there is no last state to load form, added a inline comment mentioning it
baseapp/abci.go
Outdated
} | ||
|
||
func (app *BaseApp) executeNonFraudulentTransactions(req abci.RequestGenerateFraudProof) { | ||
nonFraudulentRequests := req.DeliverTxRequests[:len(req.DeliverTxRequests)-1] |
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.
What if EndBlock
is fraudulent? Then all TXs are not fraudulent, but the last one will be skipped.
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.
Fixed this case.
baseapp/baseapp_test.go
Outdated
4. Generate a fraudproof which should ignore the uncommitted set of transactions, and export S1 into a fraudProof data structure (minimal snapshot) | ||
5. Verify the fraudproof and check verification passes (done in light client) | ||
6. Load a fresh baseapp, B2, with the contents of fraud proof data structure from (4) so it can begin from state S1. | ||
7. Check if the SMT root hashes of the new app with saved SMT root hash |
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.
7. Check if the SMT root hashes of the new app with saved SMT root hash | |
7. Check if the root hashes of the new app with saved root hash |
6. Load a fresh baseapp, B2, with the contents of fraud proof data structure from (4) so it can begin from state S1. | ||
7. Check if the SMT root hashes of the new app with saved SMT root hash | ||
|
||
Tests to write in future: |
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.
👍 👍 👍
I think we should create tracking issue for those tests and later implement them one by one.
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.
Created a tracking issue: #3
Tests can be child issues of this issue later.
} | ||
|
||
// Returns true only if only one of the three pointers is nil | ||
func (fraudProof *FraudProof) checkFraudulentStateTransition() bool { |
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.
Please add unit test covering all possible cases.
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.
Added.
baseapp/fraudproof.go
Outdated
|
||
func (fraudProof *FraudProof) verifyFraudProof() (bool, error) { | ||
if !fraudProof.checkFraudulentStateTransition() { | ||
return false, fmt.Errorf("fraudProof has more than one type of fradulent state transitions marked nil") |
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.
errors.New
should be used instead of fmt.Errorf
. This error should be extracted as package level sentinel error.
store/tracekv/store.go
Outdated
@@ -17,6 +20,10 @@ const ( | |||
iterValueOp operation = "iterValue" | |||
) | |||
|
|||
var ( | |||
ErrBufferEmpty = fmt.Errorf("provided buffer is empty") |
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.
ErrBufferEmpty = fmt.Errorf("provided buffer is empty") | |
ErrBufferEmpty = errors.New("provided buffer is empty") |
for k := range fraudProof.stateWitness { | ||
keys = append(keys, k) | ||
} |
Check warning
Code scanning / CodeQL
Iteration over map
for storeKey, stateWitness := range fraudProof.stateWitness { | ||
proofOp := stateWitness.Proof | ||
proof, err := types.CommitmentOpDecoder(proofOp) | ||
if err != nil { | ||
return false, err | ||
} | ||
if !bytes.Equal(proof.GetKey(), []byte(storeKey)) { | ||
return false, fmt.Errorf("got storeKey: %s, expected: %s", string(proof.GetKey()), storeKey) | ||
} | ||
appHash, err := proof.Run([][]byte{stateWitness.RootHash}) | ||
if err != nil { | ||
return false, err | ||
} | ||
if !bytes.Equal(appHash[0], fraudProof.appHash) { | ||
return false, fmt.Errorf("got appHash: %s, expected: %s", string(fraudProof.appHash), string(fraudProof.appHash)) | ||
} | ||
// Fraudproof verification on a substore level | ||
for _, witness := range stateWitness.WitnessData { | ||
proofOp, key, value := witness.Proof, witness.Key, witness.Value | ||
if err != nil { | ||
return false, err | ||
} | ||
if !bytes.Equal(key, proofOp.GetKey()) { | ||
return false, fmt.Errorf("got key: %s, expected: %s for storeKey: %s", string(key), string(proof.GetKey()), storeKey) | ||
} | ||
proof, err := types.CommitmentOpDecoder(proofOp) | ||
if err != nil { | ||
return false, err | ||
} | ||
rootHash, err := proof.Run([][]byte{value}) | ||
if err != nil { | ||
return false, err | ||
} | ||
if !bytes.Equal(rootHash[0], stateWitness.RootHash) { | ||
return false, fmt.Errorf("got rootHash: %s, expected: %s for storeKey: %s", string(rootHash[0]), string(stateWitness.RootHash), storeKey) | ||
} | ||
} | ||
} |
Check warning
Code scanning / CodeQL
Iteration over map
for storeKey, stateWitness := range fraudProof.stateWitness { | ||
abciWitnessData := make([]*abci.WitnessData, 0, len(stateWitness.WitnessData)) | ||
for _, witnessData := range stateWitness.WitnessData { | ||
abciWitness := abci.WitnessData{ | ||
Key: witnessData.Key, | ||
Value: witnessData.Value, | ||
Proof: &witnessData.Proof, | ||
} | ||
abciWitnessData = append(abciWitnessData, &abciWitness) | ||
} | ||
proof := stateWitness.Proof | ||
abciStateWitness[storeKey] = &abci.StateWitness{ | ||
Proof: &proof, | ||
RootHash: stateWitness.RootHash, | ||
WitnessData: abciWitnessData, | ||
} | ||
} |
Check warning
Code scanning / CodeQL
Iteration over map
for storeKey, abciStateWitness := range abciFraudProof.StateWitness { | ||
witnessData := make([]WitnessData, 0, len(abciStateWitness.WitnessData)) | ||
for _, abciWitnessData := range abciStateWitness.WitnessData { | ||
witness := WitnessData{ | ||
Key: abciWitnessData.Key, | ||
Value: abciWitnessData.Value, | ||
Proof: *abciWitnessData.Proof, | ||
} | ||
witnessData = append(witnessData, witness) | ||
} | ||
stateWitness[storeKey] = StateWitness{ | ||
Proof: *abciStateWitness.Proof, | ||
RootHash: abciStateWitness.RootHash, | ||
WitnessData: witnessData, | ||
} | ||
} |
Check warning
Code scanning / CodeQL
Iteration over map
for _, sk := range s.keysByName { | ||
storeKeys = append(storeKeys, sk) | ||
} |
Check warning
Code scanning / CodeQL
Iteration over map
for _, storeParams := range rs.storesParams { | ||
if storeParams.traceWriter != nil { | ||
buf, ok := storeParams.traceWriter.(*bytes.Buffer) | ||
if ok { | ||
buf.Reset() | ||
} | ||
} | ||
} |
Check warning
Code scanning / CodeQL
Iteration over map
for key := range stores { | ||
name := key.Name() | ||
iavlStore, err := rs.GetIAVLStore(name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
m[name], err = iavlStore.Root() | ||
if err != nil { | ||
return nil, err | ||
} | ||
} |
Check warning
Code scanning / CodeQL
Iteration over map
for storeKey, stateWitness := range fraudProof.stateWitness { | ||
rootHash := stateWitness.RootHash | ||
// TODO(manav): Replace with IAVL Deep Subtrees once implementation is done | ||
substoreDeepSMT := smtlib.NewDeepSparseMerkleSubTree(smtlib.NewSimpleMap(), smtlib.NewSimpleMap(), sha256.New(), rootHash) | ||
for _, witnessData := range stateWitness.WitnessData { | ||
proofOp, key, val := witnessData.Proof, witnessData.Key, witnessData.Value | ||
proof, err := types.CommitmentOpDecoder(proofOp) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// TODO(manav): Replace with an IAVL proof instead of SMT here | ||
smtProof := proof.(*smt.ProofOp).GetProof() | ||
substoreDeepSMT.AddBranch(smtProof, key, val) | ||
} | ||
// TODO(manav): Replace with actual iavl stores | ||
storeKeyToIAVLTree[storeKey] = &iavltree.MutableTree{} | ||
} |
Check warning
Code scanning / CodeQL
Iteration over map
…EndBlock is fraudulent
2d8866b
to
da75457
Compare
Description
Consolidates code across PRs from celestiaorg#245 along with replacing the usage of the SMT store with the IAVL store.
Covers Fraud Proof Generation and the first two levels of verification.
The third level of verification needs the functionality to set up a BaseApp from a Fraud Proof. This requires the ability to create IAVL Deep Subtree. This PR includes placeholders for these IAVL Deep Subtrees which can be added once rollkit/iavl#1 is wrapped up.
Author Checklist
All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.
I have...
!
to the type prefix if API or client breaking changeCHANGELOG.md
Reviewers Checklist
All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.
I have...
!
in the type prefix if API or client breaking change