From 2d2a65f59eabf1993804168414b86d758f30c383 Mon Sep 17 00:00:00 2001 From: CHAMI Rachid Date: Thu, 12 Jan 2023 20:48:02 +0100 Subject: [PATCH] feat: Add Inclusion proofs for QGB verification (#878) * feat: add data root inclusion proofs * feat: add tx shares and shares inclusion proof partial support * feat: add rows proofs support * feat: add rows proofs support and other cosmetics * doc: update comments and docs * chore: remove unnecessary test * chore: remove residual comment * chore: refactor RowsFromProto * chore: remove residuel comment * fix: nolint * chore: gofumpt * chore: revert proto new line * chore: rename TxShares to SharesRange * feat: add support for querying the message shares that a transaction contain * chore: regenerate proto * chore: remove unnecessary custom queries in preparation for a single one to have all the proofs * feat: use one query to get shares inclusion proofs * docs: update ProveShares docs * docs: update ShareInclusionProofQueryPath docs * docs: update SharesProof docs and regenerate proto * docs: update Validate docs * chore: regenerate proto * fix: fix data root inclusion proof env * fix: fix data root inclusion proof environment creation * chore: rename SharesFromProto to SharesProofFromProto as suggested by @evan-forbes * docs: update docs for validate proof * fix: execute the proof validation only once instead of many times * Update types/tx.go * Update proto/tendermint/types/types.proto Co-authored-by: Rootul P * Update proto/tendermint/types/types.proto Co-authored-by: Rootul P * chore: regenerate proto * fix: require the user to provide a root to test the shares proof to it * docs: shares Proof validate docs * chore: regenrate proto * chore: rename begin/end block to first/last block * chore: rename begin/end Query to first/last Query in blocks_test.go * Update types/tx.go Co-authored-by: Callum Waters * chore: regenerate proto * chore: format * Update types/tx.go * chore: generate proto * fix: initialize the state store correctly in test data root inclusion proofs * fix: make the prove data root inclusion proof use the new encoded commitment Co-authored-by: Rootul P Co-authored-by: Callum Waters --- light/proxy/routes.go | 59 +- light/rpc/client.go | 25 + pkg/consts/consts.go | 4 + proto/tendermint/types/types.pb.go | 923 +++++++++++++++++++++++++---- proto/tendermint/types/types.proto | 22 + rpc/client/http/http.go | 40 ++ rpc/client/interface.go | 8 + rpc/client/local/local.go | 18 + rpc/client/mock/client.go | 9 + rpc/core/blocks.go | 53 ++ rpc/core/blocks_test.go | 68 +++ rpc/core/routes.go | 44 +- rpc/core/tx.go | 39 ++ rpc/core/types/responses.go | 6 + types/tx.go | 194 +++++- 15 files changed, 1357 insertions(+), 155 deletions(-) diff --git a/light/proxy/routes.go b/light/proxy/routes.go index 169d026f26..ae5a657ddc 100644 --- a/light/proxy/routes.go +++ b/light/proxy/routes.go @@ -18,26 +18,27 @@ func RPCRoutes(c *lrpc.Client) map[string]*rpcserver.RPCFunc { "unsubscribe_all": rpcserver.NewWSRPCFunc(c.UnsubscribeAllWS, ""), // info API - "health": rpcserver.NewRPCFunc(makeHealthFunc(c), ""), - "status": rpcserver.NewRPCFunc(makeStatusFunc(c), ""), - "net_info": rpcserver.NewRPCFunc(makeNetInfoFunc(c), ""), - "blockchain": rpcserver.NewRPCFunc(makeBlockchainInfoFunc(c), "minHeight,maxHeight", rpcserver.Cacheable()), - "genesis": rpcserver.NewRPCFunc(makeGenesisFunc(c), "", rpcserver.Cacheable()), - "genesis_chunked": rpcserver.NewRPCFunc(makeGenesisChunkedFunc(c), "", rpcserver.Cacheable()), - "block": rpcserver.NewRPCFunc(makeBlockFunc(c), "height", rpcserver.Cacheable("height")), - "block_by_hash": rpcserver.NewRPCFunc(makeBlockByHashFunc(c), "hash", rpcserver.Cacheable()), - "block_results": rpcserver.NewRPCFunc(makeBlockResultsFunc(c), "height", rpcserver.Cacheable("height")), - "commit": rpcserver.NewRPCFunc(makeCommitFunc(c), "height", rpcserver.Cacheable("height")), - "data_commitment": rpcserver.NewRPCFunc(makeDataCommitmentFunc(c), "beginBlock,endBlock"), - "tx": rpcserver.NewRPCFunc(makeTxFunc(c), "hash,prove", rpcserver.Cacheable()), - "tx_search": rpcserver.NewRPCFunc(makeTxSearchFunc(c), "query,prove,page,per_page,order_by"), - "block_search": rpcserver.NewRPCFunc(makeBlockSearchFunc(c), "query,page,per_page,order_by"), - "validators": rpcserver.NewRPCFunc(makeValidatorsFunc(c), "height,page,per_page", rpcserver.Cacheable("height")), - "dump_consensus_state": rpcserver.NewRPCFunc(makeDumpConsensusStateFunc(c), ""), - "consensus_state": rpcserver.NewRPCFunc(makeConsensusStateFunc(c), ""), - "consensus_params": rpcserver.NewRPCFunc(makeConsensusParamsFunc(c), "height", rpcserver.Cacheable("height")), - "unconfirmed_txs": rpcserver.NewRPCFunc(makeUnconfirmedTxsFunc(c), "limit"), - "num_unconfirmed_txs": rpcserver.NewRPCFunc(makeNumUnconfirmedTxsFunc(c), ""), + "health": rpcserver.NewRPCFunc(makeHealthFunc(c), ""), + "status": rpcserver.NewRPCFunc(makeStatusFunc(c), ""), + "net_info": rpcserver.NewRPCFunc(makeNetInfoFunc(c), ""), + "blockchain": rpcserver.NewRPCFunc(makeBlockchainInfoFunc(c), "minHeight,maxHeight", rpcserver.Cacheable()), + "genesis": rpcserver.NewRPCFunc(makeGenesisFunc(c), "", rpcserver.Cacheable()), + "genesis_chunked": rpcserver.NewRPCFunc(makeGenesisChunkedFunc(c), "", rpcserver.Cacheable()), + "block": rpcserver.NewRPCFunc(makeBlockFunc(c), "height", rpcserver.Cacheable("height")), + "block_by_hash": rpcserver.NewRPCFunc(makeBlockByHashFunc(c), "hash", rpcserver.Cacheable()), + "block_results": rpcserver.NewRPCFunc(makeBlockResultsFunc(c), "height", rpcserver.Cacheable("height")), + "commit": rpcserver.NewRPCFunc(makeCommitFunc(c), "height", rpcserver.Cacheable("height")), + "data_commitment": rpcserver.NewRPCFunc(makeDataCommitmentFunc(c), "beginBlock,endBlock"), + "data_root_inclusion_proof": rpcserver.NewRPCFunc(makeDataRootInclusionProofFunc(c), "height,firstBlock,lastBlock"), + "tx": rpcserver.NewRPCFunc(makeTxFunc(c), "hash,prove", rpcserver.Cacheable()), + "tx_search": rpcserver.NewRPCFunc(makeTxSearchFunc(c), "query,prove,page,per_page,order_by"), + "block_search": rpcserver.NewRPCFunc(makeBlockSearchFunc(c), "query,page,per_page,order_by"), + "validators": rpcserver.NewRPCFunc(makeValidatorsFunc(c), "height,page,per_page", rpcserver.Cacheable("height")), + "dump_consensus_state": rpcserver.NewRPCFunc(makeDumpConsensusStateFunc(c), ""), + "consensus_state": rpcserver.NewRPCFunc(makeConsensusStateFunc(c), ""), + "consensus_params": rpcserver.NewRPCFunc(makeConsensusParamsFunc(c), "height", rpcserver.Cacheable("height")), + "unconfirmed_txs": rpcserver.NewRPCFunc(makeUnconfirmedTxsFunc(c), "limit"), + "num_unconfirmed_txs": rpcserver.NewRPCFunc(makeNumUnconfirmedTxsFunc(c), ""), // tx broadcast API "broadcast_tx_commit": rpcserver.NewRPCFunc(makeBroadcastTxCommitFunc(c), "tx"), @@ -140,6 +141,13 @@ type rpcDataCommitmentFunc func( endBlock uint64, ) (*ctypes.ResultDataCommitment, error) +type rpcDataRootInclusionProofFunc func( + ctx *rpctypes.Context, + height uint64, + firstBlock uint64, + lastBlock uint64, +) (*ctypes.ResultDataRootInclusionProof, error) + func makeDataCommitmentFunc(c *lrpc.Client) rpcDataCommitmentFunc { return func( ctx *rpctypes.Context, @@ -150,6 +158,17 @@ func makeDataCommitmentFunc(c *lrpc.Client) rpcDataCommitmentFunc { } } +func makeDataRootInclusionProofFunc(c *lrpc.Client) rpcDataRootInclusionProofFunc { + return func( + ctx *rpctypes.Context, + height uint64, + firstBlock uint64, + lastBlock uint64, + ) (*ctypes.ResultDataRootInclusionProof, error) { + return c.DataRootInclusionProof(ctx.Context(), height, firstBlock, lastBlock) + } +} + type rpcTxFunc func(ctx *rpctypes.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) func makeTxFunc(c *lrpc.Client) rpcTxFunc { diff --git a/light/rpc/client.go b/light/rpc/client.go index 2ebcff8c5e..48bcdfc207 100644 --- a/light/rpc/client.go +++ b/light/rpc/client.go @@ -463,6 +463,18 @@ func (c *Client) DataCommitment( return c.next.DataCommitment(ctx, beginBlock, endBlock) } +// DataRootInclusionProof calls rpcclient#DataRootInclusionProof method and returns +// a merkle proof for the data root of block height `height` to the set of blocks +// defined by `firstBlock` and `lastBlock`. +func (c *Client) DataRootInclusionProof( + ctx context.Context, + height uint64, + firstBlock uint64, + lastBlock uint64, +) (*ctypes.ResultDataRootInclusionProof, error) { + return c.next.DataRootInclusionProof(ctx, height, firstBlock, lastBlock) +} + // Tx calls rpcclient#Tx method and then verifies the proof if such was // requested. func (c *Client) Tx(ctx context.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) { @@ -491,6 +503,19 @@ func (c *Client) Tx(ctx context.Context, hash []byte, prove bool) (*ctypes.Resul return res, err } +// ProveShares calls rpcclient#ProveShares method and returns an NMT proof for a set +// of shares, defined by `startShare` and `endShare`, to the corresponding rows. +// Then, a binary merkle inclusion proof from the latter rows to the data root. +func (c *Client) ProveShares( + ctx context.Context, + height uint64, + startShare uint64, + endShare uint64, +) (types.SharesProof, error) { + res, err := c.next.ProveShares(ctx, height, startShare, endShare) + return res, err +} + func (c *Client) TxSearch( ctx context.Context, query string, diff --git a/pkg/consts/consts.go b/pkg/consts/consts.go index ae832e55eb..672bc72cd7 100644 --- a/pkg/consts/consts.go +++ b/pkg/consts/consts.go @@ -12,6 +12,10 @@ const ( // index must be formatted into the path. TxInclusionProofQueryPath = "custom/txInclusionProof/%d" + // ShareInclusionProofQueryPath is the path used to query the application for the + // shares to data root inclusion proofs via the ABCI query method. + ShareInclusionProofQueryPath = "custom/shareInclusionProof/%d/%d" + // ProtoBlobTxTypeID is included in each encoded BlobTx to help prevent // decoding binaries that are not actually BlobTxs. ProtoBlobTxTypeID = "BLOB" diff --git a/proto/tendermint/types/types.pb.go b/proto/tendermint/types/types.pb.go index 2b95f02c67..5c1df726b5 100644 --- a/proto/tendermint/types/types.pb.go +++ b/proto/tendermint/types/types.pb.go @@ -1307,6 +1307,157 @@ func (m *BlobTx) GetTypeId() string { return "" } +// SharesProof represents an NMT proof for a set of shares to the data root. +type SharesProof struct { + // data are the raw shares that are proven. + Data [][]byte `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + // shares_proof NMT proofs for the raw shares. Could be more than one + // if the shares span more than one row. + SharesProof []*NMTProof `protobuf:"bytes,2,rep,name=shares_proof,json=sharesProof,proto3" json:"shares_proof,omitempty"` + // namespace_id namespaceID of the shares. + NamespaceId []byte `protobuf:"bytes,3,opt,name=namespace_id,json=namespaceId,proto3" json:"namespace_id,omitempty"` + // rows_proof are binary Merkle proofs of the rows containing the raw shares to the data root. + RowsProof *RowsProof `protobuf:"bytes,4,opt,name=rows_proof,json=rowsProof,proto3" json:"rows_proof,omitempty"` +} + +func (m *SharesProof) Reset() { *m = SharesProof{} } +func (m *SharesProof) String() string { return proto.CompactTextString(m) } +func (*SharesProof) ProtoMessage() {} +func (*SharesProof) Descriptor() ([]byte, []int) { + return fileDescriptor_d3a6e55e2345de56, []int{17} +} +func (m *SharesProof) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SharesProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SharesProof.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SharesProof) XXX_Merge(src proto.Message) { + xxx_messageInfo_SharesProof.Merge(m, src) +} +func (m *SharesProof) XXX_Size() int { + return m.Size() +} +func (m *SharesProof) XXX_DiscardUnknown() { + xxx_messageInfo_SharesProof.DiscardUnknown(m) +} + +var xxx_messageInfo_SharesProof proto.InternalMessageInfo + +func (m *SharesProof) GetData() [][]byte { + if m != nil { + return m.Data + } + return nil +} + +func (m *SharesProof) GetSharesProof() []*NMTProof { + if m != nil { + return m.SharesProof + } + return nil +} + +func (m *SharesProof) GetNamespaceId() []byte { + if m != nil { + return m.NamespaceId + } + return nil +} + +func (m *SharesProof) GetRowsProof() *RowsProof { + if m != nil { + return m.RowsProof + } + return nil +} + +// RowsProof represents a Merkle proof for a set of rows to the data root. +type RowsProof struct { + RowsRoots [][]byte `protobuf:"bytes,1,rep,name=rows_roots,json=rowsRoots,proto3" json:"rows_roots,omitempty"` + Proofs []*crypto.Proof `protobuf:"bytes,2,rep,name=proofs,proto3" json:"proofs,omitempty"` + Root []byte `protobuf:"bytes,3,opt,name=root,proto3" json:"root,omitempty"` + StartRow uint32 `protobuf:"varint,4,opt,name=start_row,json=startRow,proto3" json:"start_row,omitempty"` + EndRow uint32 `protobuf:"varint,5,opt,name=end_row,json=endRow,proto3" json:"end_row,omitempty"` +} + +func (m *RowsProof) Reset() { *m = RowsProof{} } +func (m *RowsProof) String() string { return proto.CompactTextString(m) } +func (*RowsProof) ProtoMessage() {} +func (*RowsProof) Descriptor() ([]byte, []int) { + return fileDescriptor_d3a6e55e2345de56, []int{18} +} +func (m *RowsProof) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RowsProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RowsProof.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RowsProof) XXX_Merge(src proto.Message) { + xxx_messageInfo_RowsProof.Merge(m, src) +} +func (m *RowsProof) XXX_Size() int { + return m.Size() +} +func (m *RowsProof) XXX_DiscardUnknown() { + xxx_messageInfo_RowsProof.DiscardUnknown(m) +} + +var xxx_messageInfo_RowsProof proto.InternalMessageInfo + +func (m *RowsProof) GetRowsRoots() [][]byte { + if m != nil { + return m.RowsRoots + } + return nil +} + +func (m *RowsProof) GetProofs() []*crypto.Proof { + if m != nil { + return m.Proofs + } + return nil +} + +func (m *RowsProof) GetRoot() []byte { + if m != nil { + return m.Root + } + return nil +} + +func (m *RowsProof) GetStartRow() uint32 { + if m != nil { + return m.StartRow + } + return 0 +} + +func (m *RowsProof) GetEndRow() uint32 { + if m != nil { + return m.EndRow + } + return 0 +} + // Proof represents proof of a namespace.ID in an NMT. // In case this proof proves the absence of a namespace.ID // in a tree it also contains the leaf hashes of the range @@ -1333,7 +1484,7 @@ func (m *NMTProof) Reset() { *m = NMTProof{} } func (m *NMTProof) String() string { return proto.CompactTextString(m) } func (*NMTProof) ProtoMessage() {} func (*NMTProof) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{17} + return fileDescriptor_d3a6e55e2345de56, []int{19} } func (m *NMTProof) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1410,111 +1561,121 @@ func init() { proto.RegisterType((*TxProof)(nil), "tendermint.types.TxProof") proto.RegisterType((*IndexWrapper)(nil), "tendermint.types.IndexWrapper") proto.RegisterType((*BlobTx)(nil), "tendermint.types.BlobTx") + proto.RegisterType((*SharesProof)(nil), "tendermint.types.SharesProof") + proto.RegisterType((*RowsProof)(nil), "tendermint.types.RowsProof") proto.RegisterType((*NMTProof)(nil), "tendermint.types.NMTProof") } func init() { proto.RegisterFile("tendermint/types/types.proto", fileDescriptor_d3a6e55e2345de56) } var fileDescriptor_d3a6e55e2345de56 = []byte{ - // 1566 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcd, 0x6f, 0xdb, 0xc8, - 0x15, 0x37, 0x25, 0xea, 0xeb, 0x49, 0xb2, 0x65, 0xc2, 0x71, 0x14, 0x39, 0x96, 0x55, 0x15, 0x6d, - 0x9d, 0x34, 0x90, 0x53, 0xa7, 0xe8, 0xc7, 0xa1, 0x07, 0xc9, 0x76, 0x12, 0x21, 0xb6, 0xac, 0x52, - 0x8a, 0xd3, 0x16, 0x05, 0x08, 0x4a, 0x1c, 0x4b, 0x44, 0x28, 0x92, 0x25, 0x47, 0x8e, 0x9c, 0x5b, - 0x6f, 0x85, 0x4f, 0x39, 0xf5, 0xe6, 0xd3, 0xee, 0x61, 0xef, 0xfb, 0x0f, 0x2c, 0xf6, 0x94, 0x63, - 0x6e, 0xbb, 0x97, 0xcd, 0x2e, 0x1c, 0x60, 0xb1, 0x7f, 0xc6, 0x62, 0xde, 0x0c, 0x29, 0xca, 0xb2, - 0xb3, 0x8b, 0x20, 0xd8, 0x8b, 0xc0, 0x79, 0xef, 0xf7, 0xde, 0xbc, 0xef, 0x37, 0x82, 0xdb, 0x94, - 0xd8, 0x06, 0xf1, 0x46, 0xa6, 0x4d, 0xb7, 0xe8, 0xa9, 0x4b, 0x7c, 0xfe, 0x5b, 0x73, 0x3d, 0x87, - 0x3a, 0x4a, 0x61, 0xca, 0xad, 0x21, 0xbd, 0xb4, 0x32, 0x70, 0x06, 0x0e, 0x32, 0xb7, 0xd8, 0x17, - 0xc7, 0x95, 0x36, 0x06, 0x8e, 0x33, 0xb0, 0xc8, 0x16, 0x9e, 0x7a, 0xe3, 0xe3, 0x2d, 0x6a, 0x8e, - 0x88, 0x4f, 0xf5, 0x91, 0x2b, 0x00, 0xeb, 0x91, 0x6b, 0xfa, 0xde, 0xa9, 0x4b, 0x1d, 0x86, 0x75, - 0x8e, 0x05, 0xbb, 0x1c, 0x61, 0x9f, 0x10, 0xcf, 0x37, 0x1d, 0x3b, 0x6a, 0x47, 0xa9, 0x32, 0x67, - 0xe5, 0x89, 0x6e, 0x99, 0x86, 0x4e, 0x1d, 0x8f, 0x23, 0xaa, 0x7f, 0x85, 0x7c, 0x5b, 0xf7, 0x68, - 0x87, 0xd0, 0xc7, 0x44, 0x37, 0x88, 0xa7, 0xac, 0x40, 0x82, 0x3a, 0x54, 0xb7, 0x8a, 0x52, 0x45, - 0xda, 0xcc, 0xab, 0xfc, 0xa0, 0x28, 0x20, 0x0f, 0x75, 0x7f, 0x58, 0x8c, 0x55, 0xa4, 0xcd, 0x9c, - 0x8a, 0xdf, 0xd5, 0x21, 0xc8, 0x4c, 0x94, 0x49, 0x98, 0xb6, 0x41, 0x26, 0x81, 0x04, 0x1e, 0x18, - 0xb5, 0x77, 0x4a, 0x89, 0x2f, 0x44, 0xf8, 0x41, 0xf9, 0x23, 0x24, 0xd0, 0xfe, 0x62, 0xbc, 0x22, - 0x6d, 0x66, 0xb7, 0x8b, 0xb5, 0x48, 0xa0, 0xb8, 0x7f, 0xb5, 0x36, 0xe3, 0x37, 0xe4, 0xd7, 0x6f, - 0x37, 0x16, 0x54, 0x0e, 0xae, 0x5a, 0x90, 0x6a, 0x58, 0x4e, 0xff, 0x79, 0x73, 0x37, 0x34, 0x44, - 0x9a, 0x1a, 0xa2, 0x1c, 0xc0, 0x92, 0xab, 0x7b, 0x54, 0xf3, 0x09, 0xd5, 0x86, 0xe8, 0x05, 0x5e, - 0x9a, 0xdd, 0xde, 0xa8, 0x5d, 0xce, 0x43, 0x6d, 0xc6, 0x59, 0x71, 0x4b, 0xde, 0x8d, 0x12, 0xab, - 0xdf, 0xcb, 0x90, 0x14, 0xc1, 0xf8, 0x1b, 0xa4, 0x44, 0x58, 0xf1, 0xc2, 0xec, 0xf6, 0x7a, 0x54, - 0xa3, 0x60, 0xd5, 0x76, 0x1c, 0xdb, 0x27, 0xb6, 0x3f, 0xf6, 0x85, 0xbe, 0x40, 0x46, 0xf9, 0x2d, - 0xa4, 0xfb, 0x43, 0xdd, 0xb4, 0x35, 0xd3, 0x40, 0x8b, 0x32, 0x8d, 0xec, 0xc5, 0xdb, 0x8d, 0xd4, - 0x0e, 0xa3, 0x35, 0x77, 0xd5, 0x14, 0x32, 0x9b, 0x86, 0xb2, 0x0a, 0xc9, 0x21, 0x31, 0x07, 0x43, - 0x8a, 0x61, 0x89, 0xab, 0xe2, 0xa4, 0xfc, 0x05, 0x64, 0x56, 0x10, 0x45, 0x19, 0xef, 0x2e, 0xd5, - 0x78, 0xb5, 0xd4, 0x82, 0x6a, 0xa9, 0x75, 0x83, 0x6a, 0x69, 0xa4, 0xd9, 0xc5, 0xaf, 0xbe, 0xdd, - 0x90, 0x54, 0x94, 0x50, 0x76, 0x20, 0x6f, 0xe9, 0x3e, 0xd5, 0x7a, 0x2c, 0x6c, 0xec, 0xfa, 0x04, - 0xaa, 0xb8, 0x35, 0x1f, 0x10, 0x11, 0x58, 0x61, 0x7a, 0x96, 0x49, 0x71, 0x92, 0xa1, 0x6c, 0x42, - 0x01, 0x95, 0xf4, 0x9d, 0xd1, 0xc8, 0xa4, 0x1a, 0xc6, 0x3d, 0x89, 0x71, 0x5f, 0x64, 0xf4, 0x1d, - 0x24, 0x3f, 0x66, 0x19, 0x58, 0x83, 0x8c, 0xa1, 0x53, 0x9d, 0x43, 0x52, 0x08, 0x49, 0x33, 0x02, - 0x32, 0x7f, 0x07, 0x4b, 0x61, 0xd5, 0xf9, 0x1c, 0x92, 0xe6, 0x5a, 0xa6, 0x64, 0x04, 0xde, 0x87, - 0x15, 0x9b, 0x4c, 0xa8, 0x76, 0x19, 0x9d, 0x41, 0xb4, 0xc2, 0x78, 0x47, 0xb3, 0x12, 0xbf, 0x81, - 0xc5, 0x7e, 0x10, 0x7c, 0x8e, 0x05, 0xc4, 0xe6, 0x43, 0x2a, 0xc2, 0x6e, 0x41, 0x5a, 0x77, 0x5d, - 0x0e, 0xc8, 0x22, 0x20, 0xa5, 0xbb, 0x2e, 0xb2, 0xee, 0xc2, 0x32, 0xfa, 0xe8, 0x11, 0x7f, 0x6c, - 0x51, 0xa1, 0x24, 0x87, 0x98, 0x25, 0xc6, 0x50, 0x39, 0x1d, 0xb1, 0xbf, 0x86, 0x3c, 0x39, 0x31, - 0x0d, 0x62, 0xf7, 0x09, 0xc7, 0xe5, 0x11, 0x97, 0x0b, 0x88, 0x08, 0xba, 0x03, 0x05, 0xd7, 0x73, - 0x5c, 0xc7, 0x27, 0x9e, 0xa6, 0x1b, 0x86, 0x47, 0x7c, 0xbf, 0xb8, 0xc8, 0xf5, 0x05, 0xf4, 0x3a, - 0x27, 0x57, 0xff, 0x2b, 0x81, 0xbc, 0xab, 0x53, 0x5d, 0x29, 0x40, 0x9c, 0x4e, 0xfc, 0xa2, 0x54, - 0x89, 0x6f, 0xe6, 0x54, 0xf6, 0xa9, 0x6c, 0x43, 0xa2, 0x67, 0x39, 0x3d, 0xbf, 0x28, 0x57, 0xe2, - 0x9b, 0xd9, 0xed, 0xd5, 0x2b, 0xf3, 0xd6, 0x0b, 0xba, 0x04, 0xa1, 0xca, 0x06, 0x64, 0xfd, 0xff, - 0x8c, 0x75, 0x8f, 0x68, 0xbe, 0xf9, 0x92, 0x60, 0xc6, 0x65, 0x15, 0x38, 0xa9, 0x63, 0xbe, 0x24, - 0x61, 0xef, 0x24, 0x23, 0x4d, 0xdc, 0x03, 0x99, 0x69, 0x52, 0x7e, 0x05, 0x39, 0x5b, 0x1f, 0x11, - 0xdf, 0xd5, 0xfb, 0x84, 0xd5, 0x0b, 0xef, 0xaf, 0x6c, 0x48, 0x6b, 0x1a, 0x4c, 0x9c, 0xe5, 0x34, - 0x98, 0x01, 0xec, 0x9b, 0x85, 0xc4, 0x1f, 0xb2, 0x2b, 0x83, 0x36, 0x89, 0xe3, 0x0c, 0xc8, 0x21, - 0xf1, 0x88, 0xd3, 0xaa, 0xff, 0x80, 0x55, 0xe6, 0x66, 0xfd, 0x44, 0x37, 0x2d, 0xbd, 0x67, 0x5a, - 0x26, 0x3d, 0x15, 0xfd, 0xb5, 0x06, 0x19, 0xcf, 0x79, 0xa1, 0x79, 0x8e, 0x43, 0x03, 0xf7, 0xd3, - 0x9e, 0xf3, 0x42, 0x65, 0x67, 0x66, 0x52, 0xdf, 0xb1, 0xc6, 0x23, 0x5b, 0xf0, 0x63, 0xc8, 0xcf, - 0x72, 0x1a, 0x42, 0xaa, 0x3f, 0xc4, 0x40, 0x3e, 0x72, 0x28, 0x51, 0x1e, 0x80, 0xcc, 0xc2, 0x82, - 0x66, 0x2f, 0x5e, 0xd5, 0xf7, 0x1d, 0x73, 0x60, 0x13, 0xe3, 0xc0, 0x1f, 0x74, 0x4f, 0x5d, 0xa2, - 0x22, 0x38, 0xd2, 0x76, 0xb1, 0x99, 0xb6, 0x5b, 0x81, 0x84, 0xe7, 0x8c, 0x6d, 0x03, 0x9d, 0x49, - 0xa8, 0xfc, 0xa0, 0xec, 0x41, 0x3a, 0xec, 0x26, 0xf9, 0xa7, 0xba, 0x69, 0x89, 0x25, 0x86, 0xf5, - 0xba, 0x20, 0xa8, 0xa9, 0x9e, 0x68, 0xaa, 0x06, 0x64, 0xc2, 0x21, 0x2f, 0xba, 0xf2, 0xe7, 0x35, - 0xf6, 0x54, 0x4c, 0xf9, 0x3d, 0x2c, 0x87, 0x3d, 0x12, 0x16, 0x19, 0xcf, 0x6a, 0x21, 0x64, 0x88, - 0x2a, 0x9b, 0x69, 0x3f, 0x8d, 0x0f, 0xea, 0x14, 0xfa, 0x35, 0x6d, 0xbf, 0x26, 0x4e, 0xec, 0xdb, - 0x90, 0xf1, 0xcd, 0x81, 0xad, 0xd3, 0xb1, 0x47, 0x44, 0x87, 0x4e, 0x09, 0xd5, 0x2f, 0x24, 0x48, - 0xf2, 0x8e, 0x8f, 0xc4, 0x4d, 0xba, 0x3a, 0x6e, 0xb1, 0xeb, 0xe2, 0x16, 0xff, 0xf0, 0xb8, 0xd5, - 0x01, 0x42, 0x63, 0x82, 0xb6, 0x58, 0x9b, 0x57, 0xc4, 0x4d, 0xec, 0x98, 0x03, 0xd1, 0x1b, 0x11, - 0xa1, 0xea, 0x37, 0x12, 0x64, 0x42, 0xbe, 0x52, 0x87, 0x7c, 0x60, 0x97, 0x76, 0x6c, 0xe9, 0x03, - 0x51, 0x3b, 0xeb, 0xd7, 0x1a, 0xf7, 0xd0, 0xd2, 0x07, 0x6a, 0x56, 0xd8, 0xc3, 0x0e, 0x57, 0xe7, - 0x21, 0x76, 0x4d, 0x1e, 0x66, 0x12, 0x1f, 0xff, 0xb0, 0xc4, 0xcf, 0xa4, 0x48, 0xbe, 0x9c, 0xa2, - 0xcf, 0x63, 0x90, 0x6e, 0xe3, 0x8c, 0xd1, 0xad, 0x5f, 0xa2, 0x23, 0xd6, 0x20, 0xe3, 0x3a, 0x96, - 0xc6, 0x39, 0x32, 0x72, 0xd2, 0xae, 0x63, 0xa9, 0x73, 0x69, 0x4f, 0x7c, 0xa4, 0x76, 0x49, 0x7e, - 0x84, 0xa8, 0xa5, 0x2e, 0x47, 0xcd, 0x83, 0x1c, 0x0f, 0x85, 0x98, 0x49, 0xf7, 0x59, 0x0c, 0xf0, - 0x11, 0x21, 0xcd, 0xbf, 0x51, 0xb8, 0xd9, 0x1c, 0xa9, 0x0a, 0x1c, 0x93, 0xe0, 0x2b, 0x52, 0x3c, - 0x3b, 0x8a, 0xd7, 0x95, 0xa5, 0x2a, 0x70, 0xd5, 0xff, 0x4b, 0x00, 0xfb, 0x2c, 0xb2, 0xe8, 0x2f, - 0xdb, 0xd6, 0x3e, 0x9a, 0xa0, 0xcd, 0xdc, 0x5c, 0xbe, 0x2e, 0x69, 0xe2, 0xfe, 0x9c, 0x1f, 0xb5, - 0x7b, 0x07, 0xf2, 0xd3, 0x62, 0xf4, 0x49, 0x60, 0xcc, 0x15, 0x4a, 0xc2, 0x25, 0xda, 0x21, 0x54, - 0xcd, 0x9d, 0x44, 0x4e, 0xd5, 0x2f, 0x25, 0xc8, 0xa0, 0x4d, 0x07, 0x84, 0xea, 0x33, 0x39, 0x94, - 0x3e, 0x3c, 0x87, 0xeb, 0x00, 0x5c, 0x0d, 0xee, 0x25, 0x5e, 0x59, 0x19, 0xa4, 0xe0, 0x5a, 0xfa, - 0x53, 0x18, 0xf0, 0xf8, 0xfb, 0x03, 0x2e, 0x5a, 0x3a, 0x08, 0xfb, 0x4d, 0x48, 0xd9, 0xe3, 0x91, - 0xc6, 0x36, 0xa7, 0xcc, 0xab, 0xd5, 0x1e, 0x8f, 0xba, 0x13, 0xbf, 0x6a, 0x43, 0xaa, 0x3b, 0xc1, - 0x67, 0xe4, 0xfb, 0x17, 0xcc, 0x74, 0xa1, 0xc5, 0xc3, 0x85, 0xb6, 0x0d, 0x49, 0x7c, 0x73, 0xfa, - 0xc5, 0x38, 0x8e, 0x98, 0xd2, 0xbc, 0x31, 0xad, 0x83, 0x2e, 0x2a, 0x57, 0x05, 0xb2, 0xfa, 0x6f, - 0xc8, 0xe1, 0x04, 0x7d, 0xe6, 0xe9, 0xae, 0x4b, 0x3c, 0x65, 0x11, 0x62, 0x74, 0x22, 0x36, 0x68, - 0x8c, 0x4e, 0xa6, 0x4b, 0x12, 0xa7, 0x2f, 0xe1, 0x9b, 0x2c, 0x58, 0x92, 0x4d, 0x4e, 0x63, 0xde, - 0x30, 0xf5, 0xc1, 0x94, 0xcc, 0xa8, 0x49, 0x76, 0x6c, 0x1a, 0x55, 0x0d, 0x92, 0x6c, 0x43, 0x77, - 0x27, 0x73, 0x7a, 0xef, 0x05, 0x8f, 0x84, 0xd8, 0xfb, 0x1e, 0x09, 0xc1, 0xf3, 0xe0, 0xda, 0x0b, - 0x08, 0xa4, 0x03, 0x97, 0x58, 0xa3, 0xfb, 0x54, 0xf7, 0xf8, 0x64, 0x4f, 0xa8, 0xfc, 0xc0, 0xde, - 0x27, 0x24, 0x1c, 0xeb, 0xec, 0x93, 0xe1, 0x6c, 0xc7, 0x20, 0x3c, 0x4a, 0x39, 0x95, 0x1f, 0x58, - 0xb4, 0x2d, 0xa2, 0x1f, 0xf3, 0xc7, 0x11, 0x1f, 0x4f, 0x69, 0x46, 0x60, 0x0f, 0xa3, 0xbb, 0x5f, - 0x49, 0x90, 0x8d, 0x4c, 0x52, 0xe5, 0x0f, 0x70, 0xa3, 0xb1, 0x7f, 0xb8, 0xf3, 0x44, 0x6b, 0xee, - 0x6a, 0x0f, 0xf7, 0xeb, 0x8f, 0xb4, 0xa7, 0xad, 0x27, 0xad, 0xc3, 0x67, 0xad, 0xc2, 0x42, 0x69, - 0xf5, 0xec, 0xbc, 0xa2, 0x44, 0xb0, 0x4f, 0xed, 0xe7, 0xb6, 0xf3, 0xc2, 0x56, 0xb6, 0x60, 0x65, - 0x56, 0xa4, 0xde, 0xe8, 0xec, 0xb5, 0xba, 0x05, 0xa9, 0x74, 0xe3, 0xec, 0xbc, 0xb2, 0x1c, 0x91, - 0xa8, 0xf7, 0x7c, 0x62, 0xd3, 0x79, 0x81, 0x9d, 0xc3, 0x83, 0x83, 0x66, 0xb7, 0x10, 0x9b, 0x13, - 0x10, 0xab, 0xed, 0x0e, 0x2c, 0xcf, 0x0a, 0xb4, 0x9a, 0xfb, 0x85, 0x78, 0x49, 0x39, 0x3b, 0xaf, - 0x2c, 0x46, 0xd0, 0x2d, 0xd3, 0x2a, 0xa5, 0xff, 0xf7, 0x49, 0x79, 0xe1, 0xb3, 0x4f, 0xcb, 0x12, - 0xf3, 0x2c, 0x3f, 0x33, 0x4d, 0x95, 0x7b, 0x70, 0xb3, 0xd3, 0x7c, 0xd4, 0xda, 0xdb, 0xd5, 0x0e, - 0x3a, 0x8f, 0xb4, 0xee, 0x3f, 0xdb, 0x7b, 0x11, 0xef, 0x96, 0xce, 0xce, 0x2b, 0x59, 0xe1, 0xd2, - 0x75, 0xe8, 0xb6, 0xba, 0x77, 0x74, 0xd8, 0xdd, 0x2b, 0x48, 0x1c, 0xdd, 0xf6, 0xc8, 0x89, 0x43, - 0x09, 0xa2, 0xef, 0xc3, 0xad, 0x2b, 0xd0, 0xa1, 0x63, 0xcb, 0x67, 0xe7, 0x95, 0x7c, 0xdb, 0x23, - 0x7c, 0xd2, 0xa0, 0x44, 0x0d, 0x8a, 0xf3, 0x12, 0x87, 0xed, 0xc3, 0x4e, 0x7d, 0xbf, 0x50, 0x29, - 0x15, 0xce, 0xce, 0x2b, 0xb9, 0x60, 0x6d, 0x30, 0xfc, 0xd4, 0xb3, 0xc6, 0xdf, 0x5f, 0x5f, 0x94, - 0xa5, 0x37, 0x17, 0x65, 0xe9, 0xbb, 0x8b, 0xb2, 0xf4, 0xea, 0x5d, 0x79, 0xe1, 0xcd, 0xbb, 0xf2, - 0xc2, 0xd7, 0xef, 0xca, 0x0b, 0xff, 0xfa, 0xf3, 0xc0, 0xa4, 0xc3, 0x71, 0xaf, 0xd6, 0x77, 0x46, - 0x5b, 0xd1, 0x3f, 0x99, 0xd3, 0x4f, 0xfe, 0x67, 0xf7, 0xf2, 0x1f, 0xd0, 0x5e, 0x12, 0xe9, 0x0f, - 0x7e, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x57, 0x52, 0x88, 0x93, 0x41, 0x0f, 0x00, 0x00, + // 1688 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4b, 0x6f, 0x23, 0xc7, + 0x11, 0xd6, 0x90, 0xc3, 0x57, 0x91, 0x94, 0xa8, 0x81, 0xbc, 0xe6, 0x72, 0xbd, 0x14, 0x33, 0x41, + 0x12, 0xd9, 0x31, 0xa8, 0x8d, 0x1c, 0xe4, 0x05, 0xf8, 0xa0, 0x97, 0xd7, 0x84, 0xf5, 0xca, 0x90, + 0x5e, 0x27, 0x41, 0x80, 0xc1, 0x90, 0xd3, 0x4b, 0x0e, 0x3c, 0x9c, 0x9e, 0x4c, 0x37, 0x45, 0xca, + 0xb7, 0xdc, 0x02, 0x9d, 0x7c, 0xca, 0x4d, 0xa7, 0x04, 0x41, 0xee, 0xf9, 0x01, 0x09, 0x72, 0xf2, + 0xd1, 0xb7, 0xe4, 0x12, 0x27, 0xd0, 0x02, 0x41, 0x7e, 0x46, 0xd0, 0xd5, 0x3d, 0xc3, 0xa1, 0x28, + 0xae, 0x83, 0xc5, 0x22, 0x17, 0x61, 0xba, 0xea, 0xab, 0xea, 0xea, 0xaf, 0xaa, 0xba, 0x9a, 0x82, + 0xb7, 0x38, 0x09, 0x5c, 0x12, 0x8d, 0xbd, 0x80, 0xef, 0xf2, 0xab, 0x90, 0x30, 0xf9, 0xb7, 0x1d, + 0x46, 0x94, 0x53, 0xa3, 0x36, 0xd7, 0xb6, 0x51, 0xde, 0xd8, 0x1a, 0xd2, 0x21, 0x45, 0xe5, 0xae, + 0xf8, 0x92, 0xb8, 0xc6, 0xf6, 0x90, 0xd2, 0xa1, 0x4f, 0x76, 0x71, 0xd5, 0x9f, 0x3c, 0xdf, 0xe5, + 0xde, 0x98, 0x30, 0xee, 0x8c, 0x43, 0x05, 0x78, 0x9c, 0xda, 0x66, 0x10, 0x5d, 0x85, 0x9c, 0x0a, + 0x2c, 0x7d, 0xae, 0xd4, 0xcd, 0x94, 0xfa, 0x92, 0x44, 0xcc, 0xa3, 0x41, 0x3a, 0x8e, 0x46, 0x6b, + 0x29, 0xca, 0x4b, 0xc7, 0xf7, 0x5c, 0x87, 0xd3, 0x48, 0x22, 0xcc, 0x1f, 0x43, 0xf5, 0xc2, 0x89, + 0x78, 0x97, 0xf0, 0x0f, 0x89, 0xe3, 0x92, 0xc8, 0xd8, 0x82, 0x1c, 0xa7, 0xdc, 0xf1, 0xeb, 0x5a, + 0x4b, 0xdb, 0xa9, 0x5a, 0x72, 0x61, 0x18, 0xa0, 0x8f, 0x1c, 0x36, 0xaa, 0x67, 0x5a, 0xda, 0x4e, + 0xc5, 0xc2, 0x6f, 0x73, 0x04, 0xba, 0x30, 0x15, 0x16, 0x5e, 0xe0, 0x92, 0x59, 0x6c, 0x81, 0x0b, + 0x21, 0xed, 0x5f, 0x71, 0xc2, 0x94, 0x89, 0x5c, 0x18, 0xdf, 0x87, 0x1c, 0xc6, 0x5f, 0xcf, 0xb6, + 0xb4, 0x9d, 0xf2, 0x5e, 0xbd, 0x9d, 0x22, 0x4a, 0x9e, 0xaf, 0x7d, 0x21, 0xf4, 0x07, 0xfa, 0x17, + 0x5f, 0x6d, 0xaf, 0x59, 0x12, 0x6c, 0xfa, 0x50, 0x38, 0xf0, 0xe9, 0xe0, 0xd3, 0xce, 0x51, 0x12, + 0x88, 0x36, 0x0f, 0xc4, 0x38, 0x85, 0x8d, 0xd0, 0x89, 0xb8, 0xcd, 0x08, 0xb7, 0x47, 0x78, 0x0a, + 0xdc, 0xb4, 0xbc, 0xb7, 0xdd, 0xbe, 0x9b, 0x87, 0xf6, 0xc2, 0x61, 0xd5, 0x2e, 0xd5, 0x30, 0x2d, + 0x34, 0xff, 0xad, 0x43, 0x5e, 0x91, 0xf1, 0x3e, 0x14, 0x14, 0xad, 0xb8, 0x61, 0x79, 0xef, 0x71, + 0xda, 0xa3, 0x52, 0xb5, 0x0f, 0x69, 0xc0, 0x48, 0xc0, 0x26, 0x4c, 0xf9, 0x8b, 0x6d, 0x8c, 0x6f, + 0x43, 0x71, 0x30, 0x72, 0xbc, 0xc0, 0xf6, 0x5c, 0x8c, 0xa8, 0x74, 0x50, 0xbe, 0xfd, 0x6a, 0xbb, + 0x70, 0x28, 0x64, 0x9d, 0x23, 0xab, 0x80, 0xca, 0x8e, 0x6b, 0x3c, 0x80, 0xfc, 0x88, 0x78, 0xc3, + 0x11, 0x47, 0x5a, 0xb2, 0x96, 0x5a, 0x19, 0x3f, 0x02, 0x5d, 0x14, 0x44, 0x5d, 0xc7, 0xbd, 0x1b, + 0x6d, 0x59, 0x2d, 0xed, 0xb8, 0x5a, 0xda, 0xbd, 0xb8, 0x5a, 0x0e, 0x8a, 0x62, 0xe3, 0xcf, 0xff, + 0xb9, 0xad, 0x59, 0x68, 0x61, 0x1c, 0x42, 0xd5, 0x77, 0x18, 0xb7, 0xfb, 0x82, 0x36, 0xb1, 0x7d, + 0x0e, 0x5d, 0x3c, 0x5c, 0x26, 0x44, 0x11, 0xab, 0x42, 0x2f, 0x0b, 0x2b, 0x29, 0x72, 0x8d, 0x1d, + 0xa8, 0xa1, 0x93, 0x01, 0x1d, 0x8f, 0x3d, 0x6e, 0x23, 0xef, 0x79, 0xe4, 0x7d, 0x5d, 0xc8, 0x0f, + 0x51, 0xfc, 0xa1, 0xc8, 0xc0, 0x23, 0x28, 0xb9, 0x0e, 0x77, 0x24, 0xa4, 0x80, 0x90, 0xa2, 0x10, + 0xa0, 0xf2, 0x3b, 0xb0, 0x91, 0x54, 0x1d, 0x93, 0x90, 0xa2, 0xf4, 0x32, 0x17, 0x23, 0xf0, 0x09, + 0x6c, 0x05, 0x64, 0xc6, 0xed, 0xbb, 0xe8, 0x12, 0xa2, 0x0d, 0xa1, 0x7b, 0xb6, 0x68, 0xf1, 0x2d, + 0x58, 0x1f, 0xc4, 0xe4, 0x4b, 0x2c, 0x20, 0xb6, 0x9a, 0x48, 0x11, 0xf6, 0x10, 0x8a, 0x4e, 0x18, + 0x4a, 0x40, 0x19, 0x01, 0x05, 0x27, 0x0c, 0x51, 0xf5, 0x0e, 0x6c, 0xe2, 0x19, 0x23, 0xc2, 0x26, + 0x3e, 0x57, 0x4e, 0x2a, 0x88, 0xd9, 0x10, 0x0a, 0x4b, 0xca, 0x11, 0xfb, 0x4d, 0xa8, 0x92, 0x4b, + 0xcf, 0x25, 0xc1, 0x80, 0x48, 0x5c, 0x15, 0x71, 0x95, 0x58, 0x88, 0xa0, 0xb7, 0xa1, 0x16, 0x46, + 0x34, 0xa4, 0x8c, 0x44, 0xb6, 0xe3, 0xba, 0x11, 0x61, 0xac, 0xbe, 0x2e, 0xfd, 0xc5, 0xf2, 0x7d, + 0x29, 0x36, 0x7f, 0xad, 0x81, 0x7e, 0xe4, 0x70, 0xc7, 0xa8, 0x41, 0x96, 0xcf, 0x58, 0x5d, 0x6b, + 0x65, 0x77, 0x2a, 0x96, 0xf8, 0x34, 0xf6, 0x20, 0xd7, 0xf7, 0x69, 0x9f, 0xd5, 0xf5, 0x56, 0x76, + 0xa7, 0xbc, 0xf7, 0xe0, 0xde, 0xbc, 0xf5, 0xe3, 0x2e, 0x41, 0xa8, 0xb1, 0x0d, 0x65, 0xf6, 0xab, + 0x89, 0x13, 0x11, 0x9b, 0x79, 0x9f, 0x11, 0xcc, 0xb8, 0x6e, 0x81, 0x14, 0x75, 0xbd, 0xcf, 0x48, + 0xd2, 0x3b, 0xf9, 0x54, 0x13, 0xf7, 0x41, 0x17, 0x9e, 0x8c, 0x6f, 0x40, 0x25, 0x70, 0xc6, 0x84, + 0x85, 0xce, 0x80, 0x88, 0x7a, 0x91, 0xfd, 0x55, 0x4e, 0x64, 0x1d, 0x57, 0x98, 0x8b, 0x9c, 0xc6, + 0x77, 0x80, 0xf8, 0x16, 0x94, 0xb0, 0x91, 0xd8, 0x32, 0x6e, 0x93, 0x2c, 0xde, 0x01, 0x15, 0x14, + 0x3e, 0x93, 0x32, 0xf3, 0x67, 0xf0, 0x40, 0x1c, 0x73, 0xff, 0xd2, 0xf1, 0x7c, 0xa7, 0xef, 0xf9, + 0x1e, 0xbf, 0x52, 0xfd, 0xf5, 0x08, 0x4a, 0x11, 0x9d, 0xda, 0x11, 0xa5, 0x3c, 0x3e, 0x7e, 0x31, + 0xa2, 0x53, 0x4b, 0xac, 0x45, 0x48, 0x03, 0xea, 0x4f, 0xc6, 0x81, 0xd2, 0x67, 0x50, 0x5f, 0x96, + 0x32, 0x84, 0x98, 0xff, 0xc9, 0x80, 0xfe, 0x8c, 0x72, 0x62, 0xbc, 0x07, 0xba, 0xa0, 0x05, 0xc3, + 0x5e, 0xbf, 0xaf, 0xef, 0xbb, 0xde, 0x30, 0x20, 0xee, 0x29, 0x1b, 0xf6, 0xae, 0x42, 0x62, 0x21, + 0x38, 0xd5, 0x76, 0x99, 0x85, 0xb6, 0xdb, 0x82, 0x5c, 0x44, 0x27, 0x81, 0x8b, 0x87, 0xc9, 0x59, + 0x72, 0x61, 0x1c, 0x43, 0x31, 0xe9, 0x26, 0xfd, 0xeb, 0xba, 0x69, 0x43, 0x24, 0x46, 0xf4, 0xba, + 0x12, 0x58, 0x85, 0xbe, 0x6a, 0xaa, 0x03, 0x28, 0x25, 0x97, 0xbc, 0xea, 0xca, 0xff, 0xad, 0xb1, + 0xe7, 0x66, 0xc6, 0x77, 0x61, 0x33, 0xe9, 0x91, 0xa4, 0xc8, 0x64, 0x56, 0x6b, 0x89, 0x42, 0x55, + 0xd9, 0x42, 0xfb, 0xd9, 0xf2, 0xa2, 0x2e, 0xe0, 0xb9, 0xe6, 0xed, 0xd7, 0xc1, 0x1b, 0xfb, 0x2d, + 0x28, 0x31, 0x6f, 0x18, 0x38, 0x7c, 0x12, 0x11, 0xd5, 0xa1, 0x73, 0x81, 0xf9, 0x17, 0x0d, 0xf2, + 0xb2, 0xe3, 0x53, 0xbc, 0x69, 0xf7, 0xf3, 0x96, 0x59, 0xc5, 0x5b, 0xf6, 0xd5, 0x79, 0xdb, 0x07, + 0x48, 0x82, 0x89, 0xdb, 0xe2, 0xd1, 0xb2, 0x23, 0x19, 0x62, 0xd7, 0x1b, 0xaa, 0xde, 0x48, 0x19, + 0x99, 0xff, 0xd0, 0xa0, 0x94, 0xe8, 0x8d, 0x7d, 0xa8, 0xc6, 0x71, 0xd9, 0xcf, 0x7d, 0x67, 0xa8, + 0x6a, 0xe7, 0xf1, 0xca, 0xe0, 0x3e, 0xf0, 0x9d, 0xa1, 0x55, 0x56, 0xf1, 0x88, 0xc5, 0xfd, 0x79, + 0xc8, 0xac, 0xc8, 0xc3, 0x42, 0xe2, 0xb3, 0xaf, 0x96, 0xf8, 0x85, 0x14, 0xe9, 0x77, 0x53, 0xf4, + 0xa7, 0x0c, 0x14, 0x2f, 0xf0, 0x8e, 0x71, 0xfc, 0xff, 0x47, 0x47, 0x3c, 0x82, 0x52, 0x48, 0x7d, + 0x5b, 0x6a, 0x74, 0xd4, 0x14, 0x43, 0xea, 0x5b, 0x4b, 0x69, 0xcf, 0xbd, 0xa6, 0x76, 0xc9, 0xbf, + 0x06, 0xd6, 0x0a, 0x77, 0x59, 0x8b, 0xa0, 0x22, 0xa9, 0x50, 0x77, 0xd2, 0x13, 0xc1, 0x01, 0x3e, + 0x22, 0xb4, 0xe5, 0x37, 0x8a, 0x0c, 0x5b, 0x22, 0x2d, 0x85, 0x13, 0x16, 0x72, 0x44, 0xaa, 0x67, + 0x47, 0x7d, 0x55, 0x59, 0x5a, 0x0a, 0x67, 0xfe, 0x56, 0x03, 0x38, 0x11, 0xcc, 0xe2, 0x79, 0xc5, + 0xb4, 0x66, 0x18, 0x82, 0xbd, 0xb0, 0x73, 0x73, 0x55, 0xd2, 0xd4, 0xfe, 0x15, 0x96, 0x8e, 0xfb, + 0x10, 0xaa, 0xf3, 0x62, 0x64, 0x24, 0x0e, 0xe6, 0x1e, 0x27, 0xc9, 0x10, 0xed, 0x12, 0x6e, 0x55, + 0x2e, 0x53, 0x2b, 0xf3, 0xaf, 0x1a, 0x94, 0x30, 0xa6, 0x53, 0xc2, 0x9d, 0x85, 0x1c, 0x6a, 0xaf, + 0x9e, 0xc3, 0xc7, 0x00, 0xd2, 0x0d, 0xce, 0x25, 0x59, 0x59, 0x25, 0x94, 0xe0, 0x58, 0xfa, 0x41, + 0x42, 0x78, 0xf6, 0xe5, 0x84, 0xab, 0x96, 0x8e, 0x69, 0x7f, 0x13, 0x0a, 0xc1, 0x64, 0x6c, 0x8b, + 0xc9, 0xa9, 0xcb, 0x6a, 0x0d, 0x26, 0xe3, 0xde, 0x8c, 0x99, 0x01, 0x14, 0x7a, 0x33, 0x7c, 0x46, + 0xbe, 0x7c, 0xc0, 0xcc, 0x07, 0x5a, 0x36, 0x19, 0x68, 0x7b, 0x90, 0xc7, 0x37, 0x27, 0xab, 0x67, + 0xf1, 0x8a, 0x69, 0x2c, 0x07, 0x73, 0x76, 0xda, 0x43, 0xe7, 0x96, 0x42, 0x9a, 0xbf, 0x84, 0x0a, + 0xde, 0xa0, 0x9f, 0x44, 0x4e, 0x18, 0x92, 0xc8, 0x58, 0x87, 0x0c, 0x9f, 0xa9, 0x09, 0x9a, 0xe1, + 0xb3, 0xf9, 0x90, 0xc4, 0xdb, 0x97, 0xc8, 0x49, 0x16, 0x0f, 0xc9, 0x8e, 0x94, 0x89, 0xd3, 0x08, + 0xf7, 0xf1, 0x2d, 0x59, 0xb2, 0xf2, 0x62, 0xd9, 0x71, 0x4d, 0x1b, 0xf2, 0x62, 0x42, 0xf7, 0x66, + 0x4b, 0x7e, 0xdf, 0x8d, 0x1f, 0x09, 0x99, 0x97, 0x3d, 0x12, 0xe2, 0xe7, 0xc1, 0xca, 0x0d, 0xfe, + 0xac, 0x41, 0xb9, 0x2b, 0x42, 0x61, 0x92, 0xb3, 0x98, 0x16, 0x2d, 0x45, 0xcb, 0xfb, 0x20, 0xa3, + 0x65, 0xb6, 0x7c, 0xbe, 0x67, 0xbe, 0x96, 0x9c, 0x32, 0x4b, 0xb9, 0xbc, 0xfb, 0xba, 0xc8, 0x2e, + 0xbf, 0x2e, 0x7e, 0x02, 0x10, 0xd1, 0x69, 0xec, 0x5f, 0x0e, 0xd8, 0x7b, 0xee, 0x77, 0x8b, 0x4e, + 0xa5, 0x4f, 0x4b, 0x24, 0x56, 0x7e, 0x9a, 0x7f, 0xd0, 0xa0, 0x94, 0x28, 0x44, 0xb9, 0xa1, 0xa7, + 0x74, 0xd2, 0x11, 0x2c, 0xb3, 0xfe, 0x24, 0xc9, 0xb0, 0x3c, 0xc4, 0xca, 0xdf, 0x20, 0x71, 0x7e, + 0x05, 0x21, 0xc2, 0x97, 0x8a, 0x1a, 0xbf, 0x45, 0x61, 0x31, 0x2e, 0x7e, 0x74, 0x44, 0x74, 0x8a, + 0xd1, 0x56, 0xad, 0x22, 0x0a, 0x2c, 0x3a, 0x15, 0x54, 0x93, 0xc0, 0x45, 0x55, 0x0e, 0x55, 0x79, + 0x12, 0xb8, 0x16, 0x9d, 0x9a, 0x04, 0x8a, 0x31, 0x41, 0xe2, 0x4e, 0x45, 0x03, 0x4c, 0x68, 0xce, + 0x92, 0x0b, 0xf1, 0x14, 0x24, 0xc9, 0x04, 0x15, 0x9f, 0x02, 0x17, 0x50, 0x97, 0xc8, 0x82, 0xac, + 0x58, 0x72, 0x21, 0xf6, 0xf7, 0x89, 0xf3, 0x5c, 0xbe, 0x43, 0xe5, 0x24, 0x28, 0x0a, 0x81, 0x78, + 0x83, 0xbe, 0xf3, 0x37, 0x0d, 0xca, 0xa9, 0xa1, 0x65, 0x7c, 0x0f, 0xde, 0x38, 0x38, 0x39, 0x3f, + 0xfc, 0xc8, 0xee, 0x1c, 0xd9, 0x1f, 0x9c, 0xec, 0x3f, 0xb5, 0x3f, 0x3e, 0xfb, 0xe8, 0xec, 0xfc, + 0x93, 0xb3, 0xda, 0x5a, 0xe3, 0xc1, 0xf5, 0x4d, 0xcb, 0x48, 0x61, 0x3f, 0x0e, 0x3e, 0x0d, 0xe8, + 0x34, 0x30, 0x76, 0x61, 0x6b, 0xd1, 0x64, 0xff, 0xa0, 0x7b, 0x7c, 0xd6, 0xab, 0x69, 0x8d, 0x37, + 0xae, 0x6f, 0x5a, 0x9b, 0x29, 0x8b, 0xfd, 0x3e, 0x23, 0x01, 0x5f, 0x36, 0x38, 0x3c, 0x3f, 0x3d, + 0xed, 0xf4, 0x6a, 0x99, 0x25, 0x03, 0xf5, 0x8a, 0x78, 0x1b, 0x36, 0x17, 0x0d, 0xce, 0x3a, 0x27, + 0xb5, 0x6c, 0xc3, 0xb8, 0xbe, 0x69, 0xad, 0xa7, 0xd0, 0x67, 0x9e, 0xdf, 0x28, 0xfe, 0xe6, 0x77, + 0xcd, 0xb5, 0x3f, 0xfe, 0xbe, 0xa9, 0x89, 0x93, 0x55, 0x17, 0x06, 0x97, 0xf1, 0x2e, 0xbc, 0xd9, + 0xed, 0x3c, 0x3d, 0x3b, 0x3e, 0xb2, 0x4f, 0xbb, 0x4f, 0xed, 0xde, 0xcf, 0x2f, 0x8e, 0x53, 0xa7, + 0xdb, 0xb8, 0xbe, 0x69, 0x95, 0xd5, 0x91, 0x56, 0xa1, 0x2f, 0xac, 0xe3, 0x67, 0xe7, 0xbd, 0xe3, + 0x9a, 0x26, 0xd1, 0x17, 0x11, 0xb9, 0xa4, 0x9c, 0x20, 0xfa, 0x09, 0x3c, 0xbc, 0x07, 0x9d, 0x1c, + 0x6c, 0xf3, 0xfa, 0xa6, 0x55, 0xbd, 0x88, 0x88, 0xbc, 0xd4, 0xd1, 0xa2, 0x0d, 0xf5, 0x65, 0x8b, + 0xf3, 0x8b, 0xf3, 0xee, 0xfe, 0x49, 0xad, 0xd5, 0xa8, 0x5d, 0xdf, 0xb4, 0x2a, 0xf1, 0x84, 0x16, + 0xf8, 0xf9, 0xc9, 0x0e, 0x7e, 0xfa, 0xc5, 0x6d, 0x53, 0xfb, 0xf2, 0xb6, 0xa9, 0xfd, 0xeb, 0xb6, + 0xa9, 0x7d, 0xfe, 0xa2, 0xb9, 0xf6, 0xe5, 0x8b, 0xe6, 0xda, 0xdf, 0x5f, 0x34, 0xd7, 0x7e, 0xf1, + 0xc3, 0xa1, 0xc7, 0x47, 0x93, 0x7e, 0x7b, 0x40, 0xc7, 0xbb, 0xe9, 0xdf, 0xf3, 0xf3, 0x4f, 0xf9, + 0x7f, 0x85, 0xbb, 0xbf, 0xf5, 0xfb, 0x79, 0x94, 0xbf, 0xf7, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xd4, 0xff, 0x45, 0x5a, 0xac, 0x10, 0x00, 0x00, } func (m *PartSetHeader) Marshal() (dAtA []byte, err error) { @@ -2462,6 +2623,134 @@ func (m *BlobTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *SharesProof) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SharesProof) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SharesProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.RowsProof != nil { + { + size, err := m.RowsProof.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if len(m.NamespaceId) > 0 { + i -= len(m.NamespaceId) + copy(dAtA[i:], m.NamespaceId) + i = encodeVarintTypes(dAtA, i, uint64(len(m.NamespaceId))) + i-- + dAtA[i] = 0x1a + } + if len(m.SharesProof) > 0 { + for iNdEx := len(m.SharesProof) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SharesProof[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Data) > 0 { + for iNdEx := len(m.Data) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Data[iNdEx]) + copy(dAtA[i:], m.Data[iNdEx]) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Data[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *RowsProof) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RowsProof) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RowsProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.EndRow != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.EndRow)) + i-- + dAtA[i] = 0x28 + } + if m.StartRow != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.StartRow)) + i-- + dAtA[i] = 0x20 + } + if len(m.Root) > 0 { + i -= len(m.Root) + copy(dAtA[i:], m.Root) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Root))) + i-- + dAtA[i] = 0x1a + } + if len(m.Proofs) > 0 { + for iNdEx := len(m.Proofs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Proofs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.RowsRoots) > 0 { + for iNdEx := len(m.RowsRoots) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.RowsRoots[iNdEx]) + copy(dAtA[i:], m.RowsRoots[iNdEx]) + i = encodeVarintTypes(dAtA, i, uint64(len(m.RowsRoots[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *NMTProof) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2932,6 +3221,66 @@ func (m *BlobTx) Size() (n int) { return n } +func (m *SharesProof) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Data) > 0 { + for _, b := range m.Data { + l = len(b) + n += 1 + l + sovTypes(uint64(l)) + } + } + if len(m.SharesProof) > 0 { + for _, e := range m.SharesProof { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + l = len(m.NamespaceId) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.RowsProof != nil { + l = m.RowsProof.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *RowsProof) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.RowsRoots) > 0 { + for _, b := range m.RowsRoots { + l = len(b) + n += 1 + l + sovTypes(uint64(l)) + } + } + if len(m.Proofs) > 0 { + for _, e := range m.Proofs { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + l = len(m.Root) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.StartRow != 0 { + n += 1 + sovTypes(uint64(m.StartRow)) + } + if m.EndRow != 0 { + n += 1 + sovTypes(uint64(m.EndRow)) + } + return n +} + func (m *NMTProof) Size() (n int) { if m == nil { return 0 @@ -5944,6 +6293,380 @@ func (m *BlobTx) Unmarshal(dAtA []byte) error { } return nil } +func (m *SharesProof) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SharesProof: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SharesProof: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data, make([]byte, postIndex-iNdEx)) + copy(m.Data[len(m.Data)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SharesProof", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SharesProof = append(m.SharesProof, &NMTProof{}) + if err := m.SharesProof[len(m.SharesProof)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NamespaceId", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NamespaceId = append(m.NamespaceId[:0], dAtA[iNdEx:postIndex]...) + if m.NamespaceId == nil { + m.NamespaceId = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RowsProof", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RowsProof == nil { + m.RowsProof = &RowsProof{} + } + if err := m.RowsProof.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RowsProof) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RowsProof: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RowsProof: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RowsRoots", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RowsRoots = append(m.RowsRoots, make([]byte, postIndex-iNdEx)) + copy(m.RowsRoots[len(m.RowsRoots)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proofs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Proofs = append(m.Proofs, &crypto.Proof{}) + if err := m.Proofs[len(m.Proofs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Root", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Root = append(m.Root[:0], dAtA[iNdEx:postIndex]...) + if m.Root == nil { + m.Root = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartRow", wireType) + } + m.StartRow = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartRow |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EndRow", wireType) + } + m.EndRow = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EndRow |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *NMTProof) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/proto/tendermint/types/types.proto b/proto/tendermint/types/types.proto index 98b40920c5..68c87db6dd 100644 --- a/proto/tendermint/types/types.proto +++ b/proto/tendermint/types/types.proto @@ -206,6 +206,28 @@ message BlobTx { string type_id = 3; } +// SharesProof represents an NMT proof for a set of shares to the data root. +message SharesProof { + // data are the raw shares that are proven. + repeated bytes data = 1; + // shares_proof NMT proofs for the raw shares. Could be more than one + // if the shares span more than one row. + repeated NMTProof shares_proof = 2; + // namespace_id namespaceID of the shares. + bytes namespace_id = 3; + // rows_proof are binary Merkle proofs of the rows containing the raw shares to the data root. + RowsProof rows_proof = 4; +} + +// RowsProof represents a Merkle proof for a set of rows to the data root. +message RowsProof { + repeated bytes rows_roots = 1; + repeated tendermint.crypto.Proof proofs = 2; + bytes root = 3; + uint32 start_row = 4; + uint32 end_row = 5; +} + // Proof represents proof of a namespace.ID in an NMT. // In case this proof proves the absence of a namespace.ID // in a tree it also contains the leaf hashes of the range diff --git a/rpc/client/http/http.go b/rpc/client/http/http.go index a317d65e14..a8741fb68a 100644 --- a/rpc/client/http/http.go +++ b/rpc/client/http/http.go @@ -476,6 +476,27 @@ func (c *baseRPCClient) DataCommitment( return result, nil } +func (c *baseRPCClient) DataRootInclusionProof( + ctx context.Context, + height uint64, + firstBlock uint64, + lastBlock uint64, +) (*ctypes.ResultDataRootInclusionProof, error) { + result := new(ctypes.ResultDataRootInclusionProof) + params := map[string]interface{}{ + "height": height, + "firstBlock": firstBlock, + "lastBlock": lastBlock, + } + + _, err := c.caller.Call(ctx, "data_root_inclusion_proof", params, result) + if err != nil { + return nil, err + } + + return result, nil +} + func (c *baseRPCClient) Tx(ctx context.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) { result := new(ctypes.ResultTx) params := map[string]interface{}{ @@ -489,6 +510,25 @@ func (c *baseRPCClient) Tx(ctx context.Context, hash []byte, prove bool) (*ctype return result, nil } +func (c *baseRPCClient) ProveShares( + ctx context.Context, + height uint64, + startShare uint64, + endShare uint64, +) (types.SharesProof, error) { + result := new(types.SharesProof) + params := map[string]interface{}{ + "height": height, + "startShare": startShare, + "endShare": endShare, + } + _, err := c.caller.Call(ctx, "prove_shares", params, result) + if err != nil { + return types.SharesProof{}, err + } + return *result, nil +} + func (c *baseRPCClient) TxSearch( ctx context.Context, query string, diff --git a/rpc/client/interface.go b/rpc/client/interface.go index e458b2ff8f..1ab4fd9554 100644 --- a/rpc/client/interface.go +++ b/rpc/client/interface.go @@ -70,10 +70,18 @@ type SignClient interface { Commit(ctx context.Context, height *int64) (*ctypes.ResultCommit, error) DataCommitment(ctx context.Context, beginBlock uint64, endBlock uint64) (*ctypes.ResultDataCommitment, error) + DataRootInclusionProof( + ctx context.Context, + height uint64, + firstBlock uint64, + lastBlock uint64, + ) (*ctypes.ResultDataRootInclusionProof, error) Validators(ctx context.Context, height *int64, page, perPage *int) (*ctypes.ResultValidators, error) Tx(ctx context.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) + ProveShares(_ context.Context, height uint64, startShare uint64, endShare uint64) (types.SharesProof, error) + // TxSearch defines a method to search for a paginated set of transactions by // DeliverTx event search criteria. TxSearch( diff --git a/rpc/client/local/local.go b/rpc/client/local/local.go index 8975d4394e..7dea32390b 100644 --- a/rpc/client/local/local.go +++ b/rpc/client/local/local.go @@ -181,6 +181,15 @@ func (c *Local) DataCommitment( return core.DataCommitment(c.ctx, beginBlock, endBlock) } +func (c *Local) DataRootInclusionProof( + _ context.Context, + height uint64, + firstBlock uint64, + lastBlock uint64, +) (*ctypes.ResultDataRootInclusionProof, error) { + return core.DataRootInclusionProof(c.ctx, int64(height), firstBlock, lastBlock) +} + func (c *Local) Validators(ctx context.Context, height *int64, page, perPage *int) (*ctypes.ResultValidators, error) { return core.Validators(c.ctx, height, page, perPage) } @@ -189,6 +198,15 @@ func (c *Local) Tx(ctx context.Context, hash []byte, prove bool) (*ctypes.Result return core.Tx(c.ctx, hash, prove) } +func (c *Local) ProveShares( + ctx context.Context, + height uint64, + startShare uint64, + endShare uint64, +) (types.SharesProof, error) { + return core.ProveShares(c.ctx, int64(height), startShare, endShare) +} + func (c *Local) TxSearch( _ context.Context, query string, diff --git a/rpc/client/mock/client.go b/rpc/client/mock/client.go index d8ea906b96..1c5e7b9d87 100644 --- a/rpc/client/mock/client.go +++ b/rpc/client/mock/client.go @@ -177,6 +177,15 @@ func (c Client) DataCommitment( return core.DataCommitment(&rpctypes.Context{}, beginBlock, endBlock) } +func (c Client) DataRootInclusionProof( + ctx context.Context, + height uint64, + firstBlock uint64, + lastBlock uint64, +) (*ctypes.ResultDataRootInclusionProof, error) { + return core.DataRootInclusionProof(&rpctypes.Context{}, int64(height), firstBlock, lastBlock) +} + func (c Client) Validators(ctx context.Context, height *int64, page, perPage *int) (*ctypes.ResultValidators, error) { return core.Validators(&rpctypes.Context{}, height, page, perPage) } diff --git a/rpc/core/blocks.go b/rpc/core/blocks.go index f1a0993a5c..ba529110df 100644 --- a/rpc/core/blocks.go +++ b/rpc/core/blocks.go @@ -156,6 +156,27 @@ func DataCommitment(ctx *rpctypes.Context, beginBlock uint64, endBlock uint64) ( return &ctypes.ResultDataCommitment{DataCommitment: root}, nil } +// DataRootInclusionProof creates an inclusion proof of the data root of block +// height `height` in the set of blocks defined by `begin_block` and `end_block`. +func DataRootInclusionProof( + ctx *rpctypes.Context, + height int64, + beginBlock uint64, + endBlock uint64, +) (*ctypes.ResultDataRootInclusionProof, error) { + err := validateDataRootInclusionProofRequest(uint64(height), beginBlock, endBlock) + if err != nil { + return nil, err + } + heights := generateHeightsList(beginBlock, endBlock) + blockResults := fetchBlocks(heights, len(heights), 0) + proof, err := proveDataRootTuples(blockResults, height) + if err != nil { + return nil, err + } + return &ctypes.ResultDataRootInclusionProof{Proof: *proof}, nil +} + // EncodeDataRootTuple takes a height and a data root and returns the equivalent of // `abi.encode(...)` in Ethereum. // The encoded type is a DataRootTuple, which has the following ABI: @@ -269,6 +290,38 @@ func hashDataRootTuples(blocks []*ctypes.ResultBlock) ([]byte, error) { return root, nil } +// validateDataRootInclusionProofRequest validates the request to generate a data root +// inclusion proof. +func validateDataRootInclusionProofRequest(height uint64, firstBlock uint64, lastBlock uint64) error { + err := validateDataCommitmentRange(firstBlock, lastBlock) + if err != nil { + return err + } + if height < firstBlock || height > lastBlock { + return fmt.Errorf( + "height %d should be in the interval first_block %d last_block %d", + height, + firstBlock, + lastBlock, + ) + } + return nil +} + +// proveDataRootTuples returns the merkle inclusion proof for a height. +func proveDataRootTuples(blocks []*ctypes.ResultBlock, height int64) (*merkle.Proof, error) { + dataRootEncodedTuples := make([][]byte, 0, len(blocks)) + for _, block := range blocks { + encodedTuple, err := EncodeDataRootTuple(uint64(block.Block.Height), *(*[32]byte)(block.Block.DataHash)) + if err != nil { + return nil, err + } + dataRootEncodedTuples = append(dataRootEncodedTuples, encodedTuple) + } + _, proofs := merkle.ProofsFromByteSlices(dataRootEncodedTuples) + return proofs[height-blocks[0].Block.Height], nil +} + // BlockResults gets ABCIResults at a given height. // If no height is provided, it will fetch results for the latest block. // When DiscardABCIResponses is enabled, an error will be returned. diff --git a/rpc/core/blocks_test.go b/rpc/core/blocks_test.go index bcfc6d48ff..f6acf16a25 100644 --- a/rpc/core/blocks_test.go +++ b/rpc/core/blocks_test.go @@ -199,6 +199,74 @@ func TestDataCommitmentResults(t *testing.T) { } } +func TestDataRootInclusionProofResults(t *testing.T) { + env := &Environment{} + env.StateStore = sm.NewStore( + dbm.NewMemDB(), sm.StoreOptions{ + DiscardABCIResponses: false, + }, + ) + + height := int64(2826) + env.BlockStore = mockBlockStore{height: height} + SetEnvironment(env) + + blocks := randomBlocks(height) + blockStore := mockBlockStore{ + height: height, + blocks: blocks, + } + env.BlockStore = blockStore + + testCases := []struct { + height int + firstQuery int + lastQuery int + expectPass bool + }{ + {8, 10, 15, false}, + {10, 10, 15, true}, + {13, 10, 15, true}, + {15, 10, 15, true}, + {17, 10, 15, false}, + } + + for _, tc := range testCases { + env.BlockIndexer = mockBlockIndexer{ + height: height, + beginQueryBlock: tc.firstQuery, + endQueryBlock: tc.lastQuery, + } + + proof, err := DataRootInclusionProof( + &rpctypes.Context{}, + int64(tc.height), + uint64(tc.firstQuery), + uint64(tc.lastQuery), + ) + if tc.expectPass { + require.Nil(t, err, "should generate block height data root inclusion proof.") + + size := tc.lastQuery - tc.firstQuery + 1 + dataRootEncodedTuples := make([][]byte, size) + for i := 0; i < size; i++ { + encodedTuple, err := EncodeDataRootTuple( + uint64(blocks[tc.firstQuery+i].Height), + *(*[32]byte)(blocks[tc.firstQuery+i].DataHash), + ) + require.NoError(t, err) + dataRootEncodedTuples[i] = encodedTuple + } + commitment := merkle.HashFromByteSlices(dataRootEncodedTuples) + + err = proof.Proof.Verify(commitment, dataRootEncodedTuples[tc.height-tc.firstQuery]) + require.NoError(t, err) + } else { + require.NotNil(t, err, "shouldn't be able to generate proof.") + } + } +} + type mockBlockStore struct { height int64 blocks []*types.Block diff --git a/rpc/core/routes.go b/rpc/core/routes.go index 9907310f16..3089b8a63c 100644 --- a/rpc/core/routes.go +++ b/rpc/core/routes.go @@ -14,27 +14,29 @@ var Routes = map[string]*rpc.RPCFunc{ "unsubscribe_all": rpc.NewWSRPCFunc(UnsubscribeAll, ""), // info API - "health": rpc.NewRPCFunc(Health, ""), - "status": rpc.NewRPCFunc(Status, ""), - "net_info": rpc.NewRPCFunc(NetInfo, ""), - "blockchain": rpc.NewRPCFunc(BlockchainInfo, "minHeight,maxHeight", rpc.Cacheable()), - "genesis": rpc.NewRPCFunc(Genesis, "", rpc.Cacheable()), - "genesis_chunked": rpc.NewRPCFunc(GenesisChunked, "chunk", rpc.Cacheable()), - "block": rpc.NewRPCFunc(Block, "height", rpc.Cacheable("height")), - "block_by_hash": rpc.NewRPCFunc(BlockByHash, "hash", rpc.Cacheable()), - "block_results": rpc.NewRPCFunc(BlockResults, "height", rpc.Cacheable("height")), - "commit": rpc.NewRPCFunc(Commit, "height", rpc.Cacheable("height")), - "data_commitment": rpc.NewRPCFunc(DataCommitment, "beginBlock,endBlock"), - "check_tx": rpc.NewRPCFunc(CheckTx, "tx", rpc.Cacheable()), - "tx": rpc.NewRPCFunc(Tx, "hash,prove", rpc.Cacheable()), - "tx_search": rpc.NewRPCFunc(TxSearch, "query,prove,page,per_page,order_by"), - "block_search": rpc.NewRPCFunc(BlockSearch, "query,page,per_page,order_by"), - "validators": rpc.NewRPCFunc(Validators, "height,page,per_page", rpc.Cacheable("height")), - "dump_consensus_state": rpc.NewRPCFunc(DumpConsensusState, ""), - "consensus_state": rpc.NewRPCFunc(ConsensusState, ""), - "consensus_params": rpc.NewRPCFunc(ConsensusParams, "height", rpc.Cacheable("height")), - "unconfirmed_txs": rpc.NewRPCFunc(UnconfirmedTxs, "limit"), - "num_unconfirmed_txs": rpc.NewRPCFunc(NumUnconfirmedTxs, ""), + "health": rpc.NewRPCFunc(Health, ""), + "status": rpc.NewRPCFunc(Status, ""), + "net_info": rpc.NewRPCFunc(NetInfo, ""), + "blockchain": rpc.NewRPCFunc(BlockchainInfo, "minHeight,maxHeight", rpc.Cacheable()), + "genesis": rpc.NewRPCFunc(Genesis, "", rpc.Cacheable()), + "genesis_chunked": rpc.NewRPCFunc(GenesisChunked, "chunk", rpc.Cacheable()), + "block": rpc.NewRPCFunc(Block, "height", rpc.Cacheable("height")), + "block_by_hash": rpc.NewRPCFunc(BlockByHash, "hash", rpc.Cacheable()), + "block_results": rpc.NewRPCFunc(BlockResults, "height", rpc.Cacheable("height")), + "commit": rpc.NewRPCFunc(Commit, "height", rpc.Cacheable("height")), + "data_commitment": rpc.NewRPCFunc(DataCommitment, "beginBlock,endBlock"), + "check_tx": rpc.NewRPCFunc(CheckTx, "tx", rpc.Cacheable()), + "tx": rpc.NewRPCFunc(Tx, "hash,prove", rpc.Cacheable()), + "prove_shares": rpc.NewRPCFunc(ProveShares, "height,startShare,endShare"), + "data_root_inclusion_proof": rpc.NewRPCFunc(DataRootInclusionProof, "height,firstBlock,lastBlock"), + "tx_search": rpc.NewRPCFunc(TxSearch, "query,prove,page,per_page,order_by"), + "block_search": rpc.NewRPCFunc(BlockSearch, "query,page,per_page,order_by"), + "validators": rpc.NewRPCFunc(Validators, "height,page,per_page", rpc.Cacheable("height")), + "dump_consensus_state": rpc.NewRPCFunc(DumpConsensusState, ""), + "consensus_state": rpc.NewRPCFunc(ConsensusState, ""), + "consensus_params": rpc.NewRPCFunc(ConsensusParams, "height", rpc.Cacheable("height")), + "unconfirmed_txs": rpc.NewRPCFunc(UnconfirmedTxs, "limit"), + "num_unconfirmed_txs": rpc.NewRPCFunc(NumUnconfirmedTxs, ""), // tx broadcast API "broadcast_tx_commit": rpc.NewRPCFunc(BroadcastTxCommit, "tx"), diff --git a/rpc/core/tx.go b/rpc/core/tx.go index 9ff22b2c2d..0a898c144c 100644 --- a/rpc/core/tx.go +++ b/rpc/core/tx.go @@ -175,6 +175,45 @@ func proveTx(height int64, index uint32) (types.TxProof, error) { return txProof, nil } +// ProveShares creates an NMT proof for a set of shares to a set of rows. +func ProveShares( + _ *rpctypes.Context, + height int64, + startShare uint64, + endShare uint64, +) (types.SharesProof, error) { + var ( + pSharesProof tmproto.SharesProof + sharesProof types.SharesProof + ) + env := GetEnvironment() + rawBlock, err := loadRawBlock(env.BlockStore, height) + if err != nil { + return sharesProof, err + } + res, err := env.ProxyAppQuery.QuerySync(abcitypes.RequestQuery{ + Data: rawBlock, + Path: fmt.Sprintf(consts.ShareInclusionProofQueryPath, startShare, endShare), + }) + if err != nil { + return sharesProof, err + } + if res.Value == nil && res.Log != "" { + // we can make the assumption that for custom queries, if the value is nil + // and some logs have been emitted, then an error happened. + return types.SharesProof{}, errors.New(res.Log) + } + err = pSharesProof.Unmarshal(res.Value) + if err != nil { + return sharesProof, err + } + sharesProof, err = types.SharesProofFromProto(pSharesProof) + if err != nil { + return sharesProof, err + } + return sharesProof, nil +} + func loadRawBlock(bs state.BlockStore, height int64) ([]byte, error) { var blockMeta = bs.LoadBlockMeta(height) if blockMeta == nil { diff --git a/rpc/core/types/responses.go b/rpc/core/types/responses.go index bace7d0dae..69b5011a7d 100644 --- a/rpc/core/types/responses.go +++ b/rpc/core/types/responses.go @@ -4,6 +4,8 @@ import ( "encoding/json" "time" + "github.com/tendermint/tendermint/crypto/merkle" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/libs/bytes" @@ -59,6 +61,10 @@ type ResultDataCommitment struct { DataCommitment bytes.HexBytes `json:"data_commitment"` } +type ResultDataRootInclusionProof struct { + Proof merkle.Proof `json:"proof"` +} + // NewResultCommit is a helper to initialize the ResultCommit with // the embedded struct func NewResultCommit(header *types.Header, commit *types.Commit, diff --git a/types/tx.go b/types/tx.go index 43bc7af47b..7767df7051 100644 --- a/types/tx.go +++ b/types/tx.go @@ -12,6 +12,7 @@ import ( "github.com/tendermint/tendermint/crypto/tmhash" tmbytes "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/pkg/consts" + "github.com/tendermint/tendermint/proto/tendermint/crypto" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) @@ -120,6 +121,28 @@ type TxProof struct { Proofs []*tmproto.NMTProof `json:"proof"` } +// RowsProof represents a Merkle proof for a set of rows to the data root. +type RowsProof struct { + RowsRoots []tmbytes.HexBytes `json:"row_root"` + Proofs []*merkle.Proof `json:"proof"` + StartRow uint32 `json:"starting_row"` + EndRow uint32 `json:"ending_row"` +} + +// SharesProof represents an NMT proof for a set of shares to the data root. +type SharesProof struct { + // Data are the raw shares that are being proven. + Data [][]byte `json:"data"` + // SharesProofs proofs to the shares. Can contain multiple proofs if the shares + // span on multiple rows. + SharesProofs []*tmproto.NMTProof `json:"proof"` + // NamespaceID needs to be specified as it will be used when verifying proofs. + // A wrong NamespaceID will result in an invalid proof. + NamespaceID []byte `json:"namespace_id"` + // RowsProof binary merkle proofs of the rows to the data root. + RowsProof RowsProof `json:"rows_proof"` +} + // Validate verifies the proof. It returns nil if the RootHash matches the dataHash argument, // and if the proof is internally consistent. Otherwise, it returns a sensible error. func (tp TxProof) Validate() error { @@ -144,7 +167,7 @@ func (tp TxProof) Validate() error { return nil } -func (tp *TxProof) VerifyProof() bool { +func (tp TxProof) VerifyProof() bool { cursor := int32(0) for i, proof := range tp.Proofs { nmtProof := nmt.NewInclusionProof( @@ -168,19 +191,23 @@ func (tp *TxProof) VerifyProof() bool { return true } -func (tp *TxProof) IncludesTx(tx Tx) bool { - return bytes.Contains(bytes.Join(tp.Data, []byte{}), tx) -} - -func (tp TxProof) ToProto() tmproto.TxProof { - rowRoots := make([][]byte, len(tp.RowRoots)) - for i, root := range tp.RowRoots { - rowRoots[i] = root.Bytes() +func (sp SharesProof) ToProto() tmproto.SharesProof { + rowsRoots := make([][]byte, len(sp.RowsProof.RowsRoots)) + rowsProofs := make([]*crypto.Proof, len(sp.RowsProof.Proofs)) + for i := range sp.RowsProof.RowsRoots { + rowsRoots[i] = sp.RowsProof.RowsRoots[i].Bytes() + rowsProofs[i] = sp.RowsProof.Proofs[i].ToProto() } - pbtp := tmproto.TxProof{ - RowRoots: rowRoots, - Data: tp.Data, - Proofs: tp.Proofs, + pbtp := tmproto.SharesProof{ + Data: sp.Data, + SharesProof: sp.SharesProofs, + NamespaceId: sp.NamespaceID, + RowsProof: &tmproto.RowsProof{ + RowsRoots: rowsRoots, + Proofs: rowsProofs, + StartRow: sp.RowsProof.StartRow, + EndRow: sp.RowsProof.EndRow, + }, } return pbtp @@ -189,7 +216,7 @@ func (tp TxProof) ToProto() tmproto.TxProof { func TxProofFromProto(pb tmproto.TxProof) (TxProof, error) { rowRoots := make([]tmbytes.HexBytes, len(pb.RowRoots)) for i, root := range pb.RowRoots { - rowRoots[i] = tmbytes.HexBytes(root) + rowRoots[i] = root } pbtp := TxProof{ RowRoots: rowRoots, @@ -200,6 +227,34 @@ func TxProofFromProto(pb tmproto.TxProof) (TxProof, error) { return pbtp, nil } +// SharesProofFromProto creates the SharesProof from a proto message. +// Expects the proof to be pre-validated. +func SharesProofFromProto(pb tmproto.SharesProof) (SharesProof, error) { + rowsRoots := make([]tmbytes.HexBytes, len(pb.RowsProof.RowsRoots)) + rowsProofs := make([]*merkle.Proof, len(pb.RowsProof.Proofs)) + for i := range pb.RowsProof.Proofs { + rowsRoots[i] = pb.RowsProof.RowsRoots[i] + rowsProofs[i] = &merkle.Proof{ + Total: pb.RowsProof.Proofs[i].Total, + Index: pb.RowsProof.Proofs[i].Index, + LeafHash: pb.RowsProof.Proofs[i].LeafHash, + Aunts: pb.RowsProof.Proofs[i].Aunts, + } + } + + return SharesProof{ + RowsProof: RowsProof{ + RowsRoots: rowsRoots, + Proofs: rowsProofs, + StartRow: pb.RowsProof.StartRow, + EndRow: pb.RowsProof.EndRow, + }, + Data: pb.Data, + SharesProofs: pb.SharesProof, + NamespaceID: pb.NamespaceId, + }, nil +} + // ComputeProtoSizeForTxs wraps the transactions in tmproto.Data{} and calculates the size. // https://developers.google.com/protocol-buffers/docs/encoding func ComputeProtoSizeForTxs(txs []Tx) int64 { @@ -277,3 +332,114 @@ func MarshalBlobTx(tx []byte, blobs ...*tmproto.Blob) (Tx, error) { } return bTx.Marshal() } + +// Validate runs basic validations on the proof then verifies if it is consistent. +// It returns nil if the proof is valid. Otherwise, it returns a sensible error. +// The `root` is the block data root that the shares to be proven belong to. +// Note: these proofs are tested on the app side. +func (sp SharesProof) Validate(root []byte) error { + numberOfSharesInProofs := int32(0) + for _, proof := range sp.SharesProofs { + // the range is not inclusive from the left. + numberOfSharesInProofs += proof.End - proof.Start + } + + if len(sp.RowsProof.RowsRoots) != len(sp.SharesProofs) || + int32(len(sp.Data)) != numberOfSharesInProofs { + return errors.New( + "invalid number of proofs, row roots, or data. they all must be the same to verify the proof", + ) + } + + for _, proof := range sp.SharesProofs { + if proof.Start < 0 { + return errors.New("proof index cannot be negative") + } + if (proof.End - proof.Start) <= 0 { + return errors.New("proof total must be positive") + } + } + + valid := sp.VerifyProof() + if !valid { + return errors.New("proof is not internally consistent") + } + + if err := sp.RowsProof.Validate(root); err != nil { + return err + } + + return nil +} + +func (sp SharesProof) VerifyProof() bool { + cursor := int32(0) + for i, proof := range sp.SharesProofs { + nmtProof := nmt.NewInclusionProof( + int(proof.Start), + int(proof.End), + proof.Nodes, + true, + ) + sharesUsed := proof.End - proof.Start + valid := nmtProof.VerifyInclusion( + consts.NewBaseHashFunc(), + sp.NamespaceID, + sp.Data[cursor:sharesUsed+cursor], + sp.RowsProof.RowsRoots[i], + ) + if !valid { + return false + } + cursor += sharesUsed + } + return true +} + +func (tp TxProof) IncludesTx(tx Tx) bool { + return bytes.Contains(bytes.Join(tp.Data, []byte{}), tx) +} + +func (tp TxProof) ToProto() tmproto.TxProof { + rowRoots := make([][]byte, len(tp.RowRoots)) + for i, root := range tp.RowRoots { + rowRoots[i] = root.Bytes() + } + pbtp := tmproto.TxProof{ + RowRoots: rowRoots, + Data: tp.Data, + Proofs: tp.Proofs, + } + + return pbtp +} + +// Validate verifies the proof. It returns nil if the proof is valid. +// Otherwise, it returns a sensible error. +func (rp RowsProof) Validate(root []byte) error { + if int(rp.EndRow-rp.StartRow+1) != len(rp.RowsRoots) { + return errors.New( + "invalid number of row roots, or rows range. they all must be the same to verify the proof", + ) + } + if len(rp.Proofs) != len(rp.RowsRoots) { + return errors.New( + "invalid number of row roots, or proofs. they all must be the same to verify the proof", + ) + } + if !rp.VerifyProof(root) { + return errors.New("proofs verification failed") + } + + return nil +} + +func (rp RowsProof) VerifyProof(root []byte) bool { + for i, proof := range rp.Proofs { + err := proof.Verify(root, rp.RowsRoots[i]) + if err != nil { + return false + } + } + return true +}