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

[WIP] General Merkle Proof #2298

Merged
merged 12 commits into from Sep 29, 2018

Conversation

mossid
Copy link
Contributor

@mossid mossid commented Aug 30, 2018

Closes: #2502

  • Updated all relevant documentation in docs
  • Updated all code comments where relevant
  • Wrote tests
  • Updated CHANGELOG_PENDING.md

@ValarDragon
Copy link
Contributor

Should we close #2296 then?

@mossid
Copy link
Contributor Author

mossid commented Sep 4, 2018

@ValarDragon That PR is for making reference squashed branch, so I think it is good to close that.

@codecov-io
Copy link

codecov-io commented Sep 4, 2018

Codecov Report

❗ No coverage uploaded for pull request base (develop@4c4a95c). Click here to learn what that means.
The diff coverage is 24.21%.

@@            Coverage Diff             @@
##             develop    #2298   +/-   ##
==========================================
  Coverage           ?   61.16%           
==========================================
  Files              ?      202           
  Lines              ?    16658           
  Branches           ?        0           
==========================================
  Hits               ?    10189           
  Misses             ?     5600           
  Partials           ?      869
Impacted Files Coverage Δ
rpc/core/abci.go 0% <0%> (ø)
lite/proxy/wrapper.go 0% <0%> (ø)
lite/proxy/query.go 9.8% <0%> (ø)
crypto/merkle/proof_simple_value.go 0% <0%> (ø)
lite/proxy/proof.go 0% <0%> (ø)
crypto/merkle/proof.go 0% <0%> (ø)
abci/example/kvstore/kvstore.go 80.95% <100%> (ø)
crypto/merkle/wire.go 100% <100%> (ø)
crypto/merkle/proof_key_path.go 74.19% <74.19%> (ø)
crypto/merkle/simple_proof.go 67.3% <81.81%> (ø)

@mossid
Copy link
Contributor Author

mossid commented Sep 4, 2018

Ready for review.

Copy link
Contributor

@liamsi liamsi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a few comments. Mostly about documentation and few. But I also still think, we might split this up into two PRs: the general merkle stuff and the examples? It will make this slightly easier to review, too.

There are a bunch of TODOs and XXXs in the PR. If they won't be addressed in this PR, can we open an issue that summarizes what is letft to be done?

A brief description in an issue what the overall goal is, would be beneficial too.

@@ -39,7 +39,7 @@ const (

// genesis, chain_id, priv_val
var config *cfg.Config // NOTE: must be reset for each _test.go file
var ensureTimeout = time.Second * 1 // must be in seconds because CreateEmptyBlocksInterval is
var ensureTimeout = time.Second * 5 // must be in seconds because CreateEmptyBlocksInterval is
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do need to increase the timeout here?

crypto/merkle/merkle.proto Show resolved Hide resolved
crypto/merkle/merkle.proto Show resolved Hide resolved
crypto/merkle/proof.go Show resolved Hide resolved
crypto/merkle/proof.go Show resolved Hide resolved
crypto/merkle/proof_simple_value.go Outdated Show resolved Hide resolved
"fmt"

cmn "github.com/tendermint/tmlibs/common"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use common package in tendermint

if ok {
t.Errorf("Expected verification to fail for wrong trail length.")
err = proof.Verify(rootHash, itemHash)
if err == nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency: can we use require.Error here? And everywhere else?

require.NoError(err, "%#v", err)
// require.NotNil(proof)
// TODO: Ensure that *some* keys will be there, ensuring that proof is nil,
// (currently there's a race condition)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there still a race condition?

resQuery, err := proxyAppQuery.QuerySync(abci.RequestQuery{
Path: path,
Data: data,
Height: height,
Prove: !trusted,
Prove: prove,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everywhere else prove is just a renaming of trusted. Why is it different here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that is because this was the place where the trusted finally converted into prove which abci.RequestQuery wants.

@ebuchman
Copy link
Contributor

ebuchman commented Sep 13, 2018

Would be really great if we could get an ADR here that explains what we're trying to do, why, and how. Would also help orient folks looking at cosmos/iavl#105

@mossid mossid changed the title General Merkle Proof [WIP] General Merkle Proof Sep 14, 2018
@ebuchman
Copy link
Contributor

@mossid thanks for updating - is this still a WIP or want to remove that?

Copy link
Contributor

@ebuchman ebuchman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good, other than some deficiencies in documentation, both in code and the docs/spec/abci/ dir (since we're updating ABCI). We also need an ADR. There's also a few TODO/XXX that we should probably track in new issues.

We also need to update CHANGELOG. This is a breaking change to:

  • [abci] ResponseQuery
  • [rpc] /abci_query takes prove instead of trusted and switches the default behaviour to prove=false

cmn "github.com/tendermint/tendermint/libs/common"
)

const ProofOpSimpleValue = "simple:v"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should include the encoding scheme in here? eg. amino ? or maybe use IPFS multicodec: https://github.com/multiformats/multicodec

crypto/merkle/proof.go Show resolved Hide resolved

for i, op := range poz {
key := op.GetKey()
if len(key) != 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the meaning of an op with an empty key, and should it still be represented in the keypath? Should we have len(poz) == len(keys)?

crypto/merkle/proof.go Show resolved Hide resolved
crypto/merkle/proof_key_path.go Show resolved Hide resolved
// GetWithProofOptions is useful if you want full access to the ABCIQueryOptions
func GetWithProofOptions(path string, key []byte, opts rpcclient.ABCIQueryOptions,
// GetWithProofOptions is useful if you want full access to the ABCIQueryOptions.
// XXX Usage of path? It's not used, and sometimes it's /, sometimes /key, sometimes /store.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was noted in #2090. Added a small comment to docs (d8d268f#diff-69fe72a9f14b8f1a14776025eb902ed3R239) to address this but maybe issue should be re-opened?

lite/proxy/query.go Show resolved Hide resolved
@@ -61,7 +61,7 @@ func (c *Local) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQue
}

func (Local) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
return core.ABCIQuery(path, data, opts.Height, opts.Trusted)
return core.ABCIQuery(path, data, opts.Height, opts.Prove)
Copy link
Contributor

@ebuchman ebuchman Sep 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, was this wrong before? Trusted should mean don't Prove.

func (a ABCIApp) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
res := ctypes.ResultBroadcastTxCommit{}
res.CheckTx = a.App.CheckTx(tx)
if res.CheckTx.IsErr() {
return &res, nil
}
res.DeliverTx = a.App.DeliverTx(tx)
res.Height = -1 // TODO
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

@@ -98,7 +98,7 @@ func TestABCIRecorder(t *testing.T) {
_, err := r.ABCIInfo()
assert.Nil(err, "expected no err on info")

_, err = r.ABCIQueryWithOptions("path", cmn.HexBytes("data"), client.ABCIQueryOptions{Trusted: false})
_, err = r.ABCIQueryWithOptions("path", cmn.HexBytes("data"), client.ABCIQueryOptions{Prove: false})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true?

@ebuchman
Copy link
Contributor

I'll address some of my comments and open an issue for the rest. Thanks.

@ebuchman ebuchman merged commit 71a34ad into tendermint:develop Sep 29, 2018
@ebuchman ebuchman mentioned this pull request Sep 29, 2018
8 tasks
ebuchman added a commit that referenced this pull request Sep 29, 2018
ebuchman added a commit that referenced this pull request Sep 29, 2018
ebuchman added a commit that referenced this pull request Sep 29, 2018
* tmlibs -> libs

* update changelog

* address some comments from review of #2298
}

// | height | int64 | 0 | false | Height (0 means latest) |
// | prove | bool | false | false | Includes proof if true |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want proofs by default?

@@ -173,9 +173,17 @@ func TestABCIApp(t *testing.T) {
require.NotNil(res.DeliverTx)
assert.True(res.DeliverTx.IsOK())

// commit
// TODO: This may not be necessary in the future
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in what future? under what conditions?

cert := lite.NewBaseVerifier(chainID, seed.Height(), seed.Validators)

// Wait for tx confirmation.
done := make(chan int64)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

txConfirmedCh


func init() {
cdc = amino.NewCodec()
cdc.Seal()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what Seal() does? prevents future modifications?

// Check sp.Index/sp.Total manually if needed
func (sp *SimpleProof) Verify(rootHash []byte, leafHash []byte) error {
if sp.Total < 0 {
return errors.New("Proof total must be positive")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cannot be negative


for i := range keys {
enc := keyEncoding(rand.Intn(int(KeyEncodingMax)))
keys[i] = make([]byte, rand.Uint32()%20)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

20 magic const

cmn "github.com/tendermint/tendermint/libs/common"
)

/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

func (prt *ProofRuntime) Decode(pop ProofOp) (ProofOperator, error) {
decoder := prt.decoders[pop.Type]
if decoder == nil {
return nil, cmn.NewError("unrecognized proof type %v", pop.Type)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no decoder for proof type %v


type OpDecoder func(ProofOp) (ProofOperator, error)

type ProofRuntime struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

godoc is missing

key := op.GetKey()
if len(key) != 0 {
if !bytes.Equal(keys[0], key) {
return cmn.NewError("Key mismatch on operation #%d: expected %+v but %+v", i, []byte(keys[0]), []byte(key))
Copy link
Contributor

@melekes melekes Oct 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

, but got

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants