From 12e1fa1a9901083536771b8d1ef37644d464d961 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 27 Apr 2022 12:22:56 -0500 Subject: [PATCH 01/31] add basic consts --- pkg/consts/consts.go | 81 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 pkg/consts/consts.go diff --git a/pkg/consts/consts.go b/pkg/consts/consts.go new file mode 100644 index 0000000000..165664f31a --- /dev/null +++ b/pkg/consts/consts.go @@ -0,0 +1,81 @@ +package consts + +import ( + "crypto/sha256" + + "github.com/celestiaorg/nmt/namespace" + "github.com/celestiaorg/rsmt2d" +) + +// This contains all constants of: +// https://github.com/celestiaorg/celestia-specs/blob/master/specs/consensus.md#constants +const ( + // ShareSize is the size of a share (in bytes). + // see: https://github.com/celestiaorg/celestia-specs/blob/master/specs/consensus.md#constants + ShareSize = 256 + + // NamespaceSize is the namespace size in bytes. + NamespaceSize = 8 + + // ShareReservedBytes is the reserved bytes for contiguous appends. + ShareReservedBytes = 1 + + // TxShareSize is the number of bytes usable for tx/evidence/ISR shares. + TxShareSize = ShareSize - NamespaceSize - ShareReservedBytes + // MsgShareSize is the number of bytes usable for message shares. + MsgShareSize = ShareSize - NamespaceSize + + // MaxSquareSize is the maximum number of + // rows/columns of the original data shares in square layout. + // Corresponds to AVAILABLE_DATA_ORIGINAL_SQUARE_MAX in the spec. + // 128*128*256 = 4 Megabytes + // TODO(ismail): settle on a proper max square + // if the square size is larger than this, the block producer will panic + MaxSquareSize = 128 + // MaxShareCount is the maximum number of shares allowed in the original data square. + // if there are more shares than this, the block producer will panic. + MaxShareCount = MaxSquareSize * MaxSquareSize + + // MinSquareSize depicts the smallest original square width. A square size smaller than this will + // cause block producer to panic + MinSquareSize = 1 + // MinshareCount is the minimum shares required in an original data square. + MinSharecount = MinSquareSize * MinSquareSize +) + +var ( + // See spec for further details on the types of available data + // https://github.com/celestiaorg/celestia-specs/blob/master/specs/consensus.md#reserved-namespace-ids + // https://github.com/celestiaorg/celestia-specs/blob/de5f4f74f56922e9fa735ef79d9e6e6492a2bad1/specs/data_structures.md#availabledata + + // TxNamespaceID is the namespace reserved for transaction data + TxNamespaceID = namespace.ID{0, 0, 0, 0, 0, 0, 0, 1} + // IntermediateStateRootsNamespaceID is the namespace reserved for + // intermediate state root data + // TODO(liamsi): code commented out but kept intentionally. + // IntermediateStateRootsNamespaceID = namespace.ID{0, 0, 0, 0, 0, 0, 0, 2} + + // EvidenceNamespaceID is the namespace reserved for evidence + EvidenceNamespaceID = namespace.ID{0, 0, 0, 0, 0, 0, 0, 3} + + // MaxReservedNamespace is the lexicographically largest namespace that is + // reserved for protocol use. It is derived from NAMESPACE_ID_MAX_RESERVED + // https://github.com/celestiaorg/celestia-specs/blob/master/specs/consensus.md#constants + MaxReservedNamespace = namespace.ID{0, 0, 0, 0, 0, 0, 0, 255} + // TailPaddingNamespaceID is the namespace ID for tail padding. All data + // with this namespace will be ignored + TailPaddingNamespaceID = namespace.ID{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE} + // ParitySharesNamespaceID indicates that share contains erasure data + ParitySharesNamespaceID = namespace.ID{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} + + // NewBaseHashFunc change accordingly if another hash.Hash should be used as a base hasher in the NMT: + NewBaseHashFunc = sha256.New + + // DefaultCodec is the default codec creator used for data erasure + // TODO(ismail): for better efficiency and a larger number shares + // we should switch to the rsmt2d.LeopardFF16 codec: + DefaultCodec = rsmt2d.NewRSGF8Codec + + // DataCommitmentBlocksLimit is the limit to the number of blocks we can generate a data commitment for. + DataCommitmentBlocksLimit = 1000 +) From 116b7af4000920030a373363487ef9a9f084e066 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 27 Apr 2022 11:45:04 -0500 Subject: [PATCH 02/31] add the data availability header and corresponding logic Co-authored-by: Ismail Khoffi Co-authored-by: Hlib Kanunnikov --- pkg/da/data_availability_header.go | 206 +++++++++ pkg/da/data_availability_header_test.go | 230 +++++++++++ .../da/data_availability_header.pb.go | 390 ++++++++++++++++++ .../da/data_availability_header.proto | 21 + 4 files changed, 847 insertions(+) create mode 100644 pkg/da/data_availability_header.go create mode 100644 pkg/da/data_availability_header_test.go create mode 100644 proto/tendermint/da/data_availability_header.pb.go create mode 100644 proto/tendermint/da/data_availability_header.proto diff --git a/pkg/da/data_availability_header.go b/pkg/da/data_availability_header.go new file mode 100644 index 0000000000..61e1f3c0c3 --- /dev/null +++ b/pkg/da/data_availability_header.go @@ -0,0 +1,206 @@ +package da + +import ( + "bytes" + "errors" + "fmt" + + "github.com/celestiaorg/rsmt2d" + "github.com/tendermint/tendermint/crypto/merkle" + "github.com/tendermint/tendermint/crypto/tmhash" + "github.com/tendermint/tendermint/pkg/consts" + "github.com/tendermint/tendermint/pkg/wrapper" + daproto "github.com/tendermint/tendermint/proto/tendermint/da" +) + +const ( + maxExtendedSquareWidth = consts.MaxSquareSize * 2 + minExtendedSquareWidth = consts.MinSquareSize * 2 +) + +// DataAvailabilityHeader (DAHeader) contains the row and column roots of the erasure +// coded version of the data in Block.Data. +// Therefor the original Block.Data is arranged in a +// k × k matrix, which is then "extended" to a +// 2k × 2k matrix applying multiple times Reed-Solomon encoding. +// For details see Section 5.2: https://arxiv.org/abs/1809.09044 +// or the Celestia specification: +// https://github.com/celestiaorg/celestia-specs/blob/master/specs/data_structures.md#availabledataheader +// Note that currently we list row and column roots in separate fields +// (different from the spec). +type DataAvailabilityHeader struct { + // RowRoot_j = root((M_{j,1} || M_{j,2} || ... || M_{j,2k} )) + RowsRoots [][]byte `json:"row_roots"` + // ColumnRoot_j = root((M_{1,j} || M_{2,j} || ... || M_{2k,j} )) + ColumnRoots [][]byte `json:"column_roots"` + // cached result of Hash() not to be recomputed + hash []byte +} + +// NewDataAvailabilityHeader generates a DataAvailability header using the provided square size and shares +func NewDataAvailabilityHeader(eds *rsmt2d.ExtendedDataSquare) DataAvailabilityHeader { + // generate the row and col roots using the EDS + dah := DataAvailabilityHeader{ + RowsRoots: eds.RowRoots(), + ColumnRoots: eds.ColRoots(), + } + + // generate the hash of the data using the new roots + dah.Hash() + + return dah +} + +func ExtendShares(squareSize uint64, shares [][]byte) (*rsmt2d.ExtendedDataSquare, error) { + // Check that square size is with range + if squareSize < consts.MinSquareSize || squareSize > consts.MaxSquareSize { + return nil, fmt.Errorf( + "invalid square size: min %d max %d provided %d", + consts.MinSquareSize, + consts.MaxSquareSize, + squareSize, + ) + } + // check that valid number of shares have been provided + if squareSize*squareSize != uint64(len(shares)) { + return nil, fmt.Errorf( + "must provide valid number of shares for square size: got %d wanted %d", + len(shares), + squareSize*squareSize, + ) + } + tree := wrapper.NewErasuredNamespacedMerkleTree(squareSize) + return rsmt2d.ComputeExtendedDataSquare(shares, consts.DefaultCodec(), tree.Constructor) +} + +// String returns hex representation of merkle hash of the DAHeader. +func (dah *DataAvailabilityHeader) String() string { + if dah == nil { + return "" + } + return fmt.Sprintf("%X", dah.Hash()) +} + +// Equals checks equality of two DAHeaders. +func (dah *DataAvailabilityHeader) Equals(to *DataAvailabilityHeader) bool { + return bytes.Equal(dah.Hash(), to.Hash()) +} + +// Hash computes and caches the merkle root of the row and column roots. +func (dah *DataAvailabilityHeader) Hash() []byte { + if dah == nil { + return merkle.HashFromByteSlices(nil) + } + if len(dah.hash) != 0 { + return dah.hash + } + + colsCount := len(dah.ColumnRoots) + rowsCount := len(dah.RowsRoots) + slices := make([][]byte, colsCount+rowsCount) + for i, rowRoot := range dah.RowsRoots { + slices[i] = rowRoot + } + for i, colRoot := range dah.ColumnRoots { + slices[i+colsCount] = colRoot + } + // The single data root is computed using a simple binary merkle tree. + // Effectively being root(rowRoots || columnRoots): + dah.hash = merkle.HashFromByteSlices(slices) + return dah.hash +} + +func (dah *DataAvailabilityHeader) ToProto() (*daproto.DataAvailabilityHeader, error) { + if dah == nil { + return nil, errors.New("nil DataAvailabilityHeader") + } + + dahp := new(daproto.DataAvailabilityHeader) + dahp.RowRoots = dah.RowsRoots + dahp.ColumnRoots = dah.ColumnRoots + return dahp, nil +} + +func DataAvailabilityHeaderFromProto(dahp *daproto.DataAvailabilityHeader) (dah *DataAvailabilityHeader, err error) { + if dahp == nil { + return nil, errors.New("nil DataAvailabilityHeader") + } + + dah = new(DataAvailabilityHeader) + dah.RowsRoots = dahp.RowRoots + dah.ColumnRoots = dahp.ColumnRoots + + return dah, dah.ValidateBasic() +} + +// ValidateBasic runs stateless checks on the DataAvailabilityHeader. +func (dah *DataAvailabilityHeader) ValidateBasic() error { + if dah == nil { + return errors.New("nil data availability header is not valid") + } + if len(dah.ColumnRoots) < minExtendedSquareWidth || len(dah.RowsRoots) < minExtendedSquareWidth { + return fmt.Errorf( + "minimum valid DataAvailabilityHeader has at least %d row and column roots", + minExtendedSquareWidth, + ) + } + if len(dah.ColumnRoots) > maxExtendedSquareWidth || len(dah.RowsRoots) > maxExtendedSquareWidth { + return fmt.Errorf( + "maximum valid DataAvailabilityHeader has at most %d row and column roots", + maxExtendedSquareWidth, + ) + } + if len(dah.ColumnRoots) != len(dah.RowsRoots) { + return fmt.Errorf( + "unequal number of row and column roots: row %d col %d", + len(dah.RowsRoots), + len(dah.ColumnRoots), + ) + } + if err := validateHash(dah.hash); err != nil { + return fmt.Errorf("wrong hash: %v", err) + } + + return nil +} + +func (dah *DataAvailabilityHeader) IsZero() bool { + if dah == nil { + return true + } + return len(dah.ColumnRoots) == 0 || len(dah.RowsRoots) == 0 +} + +// tail is filler for all tail padded shares +// it is allocated once and used everywhere +var tailPaddingShare = append( + append(make([]byte, 0, consts.ShareSize), consts.TailPaddingNamespaceID...), + bytes.Repeat([]byte{0}, consts.ShareSize-consts.NamespaceSize)..., +) + +// MinDataAvailabilityHeader returns the minimum valid data availability header. +// It is equal to the data availability header for an empty block +func MinDataAvailabilityHeader() DataAvailabilityHeader { + shares := make([][]byte, consts.MinSharecount) + for i := 0; i < consts.MinSharecount; i++ { + shares[i] = tailPaddingShare + } + eds, err := ExtendShares(consts.MinSquareSize, shares) + if err != nil { + panic(err) + } + dah := NewDataAvailabilityHeader(eds) + return dah +} + +// validateHash returns an error if the hash is not empty, but its +// size != tmhash.Size. copy pasted from `types` package as to not import +func validateHash(h []byte) error { + if len(h) > 0 && len(h) != tmhash.Size { + return fmt.Errorf("expected size to be %d bytes, got %d bytes", + tmhash.Size, + len(h), + ) + } + return nil +} diff --git a/pkg/da/data_availability_header_test.go b/pkg/da/data_availability_header_test.go new file mode 100644 index 0000000000..3e16f1019c --- /dev/null +++ b/pkg/da/data_availability_header_test.go @@ -0,0 +1,230 @@ +package da + +import ( + "bytes" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/pkg/consts" +) + +func TestNilDataAvailabilityHeaderHashDoesntCrash(t *testing.T) { + // This follows RFC-6962, i.e. `echo -n '' | sha256sum` + var emptyBytes = []byte{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, + 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, + 0x78, 0x52, 0xb8, 0x55} + + assert.Equal(t, emptyBytes, (*DataAvailabilityHeader)(nil).Hash()) + assert.Equal(t, emptyBytes, new(DataAvailabilityHeader).Hash()) +} + +func TestMinDataAvailabilityHeader(t *testing.T) { + dah := MinDataAvailabilityHeader() + expectedHash := []byte{ + 0x7b, 0x57, 0x8b, 0x35, 0x1b, 0x1b, 0xb, 0xbd, 0x70, 0xbb, 0x35, 0x0, 0x19, 0xeb, 0xc9, 0x64, + 0xc4, 0x4a, 0x14, 0xa, 0x37, 0xef, 0x71, 0x5b, 0x55, 0x2a, 0x7f, 0x8f, 0x31, 0x5a, 0xcd, 0x19, + } + require.Equal(t, expectedHash, dah.hash) + require.NoError(t, dah.ValidateBasic()) + // important note: also see the types.TestEmptyBlockDataAvailabilityHeader test + // which ensures that empty block data results in the minimum data availability + // header +} + +func TestNewDataAvailabilityHeader(t *testing.T) { + type test struct { + name string + expectedHash []byte + squareSize uint64 + shares [][]byte + } + + tests := []test{ + { + name: "typical", + expectedHash: []byte{ + 0xfe, 0x9c, 0x6b, 0xd8, 0xe5, 0x7c, 0xd1, 0x5d, 0x1f, 0xd6, 0x55, 0x7e, 0x87, 0x7d, 0xd9, 0x7d, + 0xdb, 0xf2, 0x66, 0xfa, 0x60, 0x24, 0x2d, 0xb3, 0xa0, 0x9c, 0x4f, 0x4e, 0x5b, 0x2a, 0x2c, 0x2a, + }, + squareSize: 2, + shares: generateShares(4, 1), + }, + { + name: "max square size", + expectedHash: []byte{ + 0xe2, 0x87, 0x23, 0xd0, 0x2d, 0x54, 0x25, 0x5f, 0x79, 0x43, 0x8e, 0xfb, 0xb7, 0xe8, 0xfa, 0xf5, + 0xbf, 0x93, 0x50, 0xb3, 0x64, 0xd0, 0x4f, 0xa7, 0x7b, 0xb1, 0x83, 0x3b, 0x8, 0xba, 0xd3, 0xa4, + }, + squareSize: consts.MaxSquareSize, + shares: generateShares(consts.MaxSquareSize*consts.MaxSquareSize, 99), + }, + } + + for _, tt := range tests { + tt := tt + eds, err := ExtendShares(tt.squareSize, tt.shares) + require.NoError(t, err) + resdah := NewDataAvailabilityHeader(eds) + require.Equal(t, tt.squareSize*2, uint64(len(resdah.ColumnRoots)), tt.name) + require.Equal(t, tt.squareSize*2, uint64(len(resdah.RowsRoots)), tt.name) + require.Equal(t, tt.expectedHash, resdah.hash, tt.name) + } +} + +func TestExtendShares(t *testing.T) { + type test struct { + name string + expectedErr bool + squareSize uint64 + shares [][]byte + } + + tests := []test{ + { + name: "too large square size", + expectedErr: true, + squareSize: consts.MaxSquareSize + 1, + shares: generateShares((consts.MaxSquareSize+1)*(consts.MaxSquareSize+1), 1), + }, + { + name: "invalid number of shares", + expectedErr: true, + squareSize: 2, + shares: generateShares(5, 1), + }, + } + + for _, tt := range tests { + tt := tt + eds, err := ExtendShares(tt.squareSize, tt.shares) + if tt.expectedErr { + require.NotNil(t, err) + continue + } + require.NoError(t, err) + require.Equal(t, tt.squareSize*2, eds.Width(), tt.name) + } +} + +func TestDataAvailabilityHeaderProtoConversion(t *testing.T) { + type test struct { + name string + dah DataAvailabilityHeader + } + + shares := generateShares(consts.MaxSquareSize*consts.MaxSquareSize, 1) + eds, err := ExtendShares(consts.MaxSquareSize, shares) + require.NoError(t, err) + bigdah := NewDataAvailabilityHeader(eds) + + tests := []test{ + { + name: "min", + dah: MinDataAvailabilityHeader(), + }, + { + name: "max", + dah: bigdah, + }, + } + + for _, tt := range tests { + tt := tt + pdah, err := tt.dah.ToProto() + require.NoError(t, err) + resDah, err := DataAvailabilityHeaderFromProto(pdah) + require.NoError(t, err) + resDah.Hash() // calc the hash to make the comparisons fair + require.Equal(t, tt.dah, *resDah, tt.name) + } + +} + +func Test_DAHValidateBasic(t *testing.T) { + type test struct { + name string + dah DataAvailabilityHeader + expectErr bool + errStr string + } + + shares := generateShares(consts.MaxSquareSize*consts.MaxSquareSize, 1) + eds, err := ExtendShares(consts.MaxSquareSize, shares) + require.NoError(t, err) + bigdah := NewDataAvailabilityHeader(eds) + + // make a mutant dah that has too many roots + var tooBigDah DataAvailabilityHeader + tooBigDah.ColumnRoots = make([][]byte, consts.MaxSquareSize*consts.MaxSquareSize) + tooBigDah.RowsRoots = make([][]byte, consts.MaxSquareSize*consts.MaxSquareSize) + copy(tooBigDah.ColumnRoots, bigdah.ColumnRoots) + copy(tooBigDah.RowsRoots, bigdah.RowsRoots) + tooBigDah.ColumnRoots = append(tooBigDah.ColumnRoots, bytes.Repeat([]byte{1}, 32)) + tooBigDah.RowsRoots = append(tooBigDah.RowsRoots, bytes.Repeat([]byte{1}, 32)) + // make a mutant dah that has too few roots + var tooSmallDah DataAvailabilityHeader + tooSmallDah.ColumnRoots = [][]byte{bytes.Repeat([]byte{2}, 32)} + tooSmallDah.RowsRoots = [][]byte{bytes.Repeat([]byte{2}, 32)} + // use a bad hash + badHashDah := MinDataAvailabilityHeader() + badHashDah.hash = []byte{1, 2, 3, 4} + // dah with not equal number of roots + mismatchDah := MinDataAvailabilityHeader() + mismatchDah.ColumnRoots = append(mismatchDah.ColumnRoots, bytes.Repeat([]byte{2}, 32)) + + tests := []test{ + { + name: "min", + dah: MinDataAvailabilityHeader(), + }, + { + name: "max", + dah: bigdah, + }, + { + name: "too big dah", + dah: tooBigDah, + expectErr: true, + errStr: "maximum valid DataAvailabilityHeader has at most", + }, + { + name: "too small dah", + dah: tooSmallDah, + expectErr: true, + errStr: "minimum valid DataAvailabilityHeader has at least", + }, + { + name: "bash hash", + dah: badHashDah, + expectErr: true, + errStr: "wrong hash", + }, + { + name: "mismatched roots", + dah: mismatchDah, + expectErr: true, + errStr: "unequal number of row and column roots", + }, + } + + for _, tt := range tests { + tt := tt + err := tt.dah.ValidateBasic() + if tt.expectErr { + require.True(t, strings.Contains(err.Error(), tt.errStr), tt.name) + require.Error(t, err) + continue + } + require.NoError(t, err) + } +} + +func generateShares(count int, repeatByte byte) [][]byte { + shares := make([][]byte, count) + for i := 0; i < count; i++ { + shares[i] = bytes.Repeat([]byte{repeatByte}, consts.ShareSize) + } + return shares +} diff --git a/proto/tendermint/da/data_availability_header.pb.go b/proto/tendermint/da/data_availability_header.pb.go new file mode 100644 index 0000000000..875dbbc734 --- /dev/null +++ b/proto/tendermint/da/data_availability_header.pb.go @@ -0,0 +1,390 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: tendermint/da/data_availability_header.proto + +package da + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// DataAvailabilityHeader contains the row and column roots of the erasure +// coded version of the data in Block.Data. +// Therefor the original Block.Data is arranged in a +// k × k matrix, which is then "extended" to a +// 2k × 2k matrix applying multiple times Reed-Solomon encoding. +// For details see Section 5.2: https://arxiv.org/abs/1809.09044 +// or the Celestia specification: +// https://github.com/celestiaorg/celestia-specs/blob/master/specs/data_structures.md#availabledataheader +// Note that currently we list row and column roots in separate fields +// (different from the spec). +type DataAvailabilityHeader struct { + // RowRoot_j = root((M_{j,1} || M_{j,2} || ... || M_{j,2k} )) + RowRoots [][]byte `protobuf:"bytes,1,rep,name=row_roots,json=rowRoots,proto3" json:"row_roots,omitempty"` + // ColumnRoot_j = root((M_{1,j} || M_{2,j} || ... || M_{2k,j} )) + ColumnRoots [][]byte `protobuf:"bytes,2,rep,name=column_roots,json=columnRoots,proto3" json:"column_roots,omitempty"` +} + +func (m *DataAvailabilityHeader) Reset() { *m = DataAvailabilityHeader{} } +func (m *DataAvailabilityHeader) String() string { return proto.CompactTextString(m) } +func (*DataAvailabilityHeader) ProtoMessage() {} +func (*DataAvailabilityHeader) Descriptor() ([]byte, []int) { + return fileDescriptor_dfe248ce3a86eed9, []int{0} +} +func (m *DataAvailabilityHeader) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DataAvailabilityHeader) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DataAvailabilityHeader.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 *DataAvailabilityHeader) XXX_Merge(src proto.Message) { + xxx_messageInfo_DataAvailabilityHeader.Merge(m, src) +} +func (m *DataAvailabilityHeader) XXX_Size() int { + return m.Size() +} +func (m *DataAvailabilityHeader) XXX_DiscardUnknown() { + xxx_messageInfo_DataAvailabilityHeader.DiscardUnknown(m) +} + +var xxx_messageInfo_DataAvailabilityHeader proto.InternalMessageInfo + +func (m *DataAvailabilityHeader) GetRowRoots() [][]byte { + if m != nil { + return m.RowRoots + } + return nil +} + +func (m *DataAvailabilityHeader) GetColumnRoots() [][]byte { + if m != nil { + return m.ColumnRoots + } + return nil +} + +func init() { + proto.RegisterType((*DataAvailabilityHeader)(nil), "tendermint.da.DataAvailabilityHeader") +} + +func init() { + proto.RegisterFile("tendermint/da/data_availability_header.proto", fileDescriptor_dfe248ce3a86eed9) +} + +var fileDescriptor_dfe248ce3a86eed9 = []byte{ + // 193 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x29, 0x49, 0xcd, 0x4b, + 0x49, 0x2d, 0xca, 0xcd, 0xcc, 0x2b, 0xd1, 0x4f, 0x49, 0xd4, 0x4f, 0x49, 0x2c, 0x49, 0x8c, 0x4f, + 0x2c, 0x4b, 0xcc, 0xcc, 0x49, 0x4c, 0xca, 0xcc, 0xc9, 0x2c, 0xa9, 0x8c, 0xcf, 0x48, 0x4d, 0x4c, + 0x49, 0x2d, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x45, 0xa8, 0xd6, 0x4b, 0x49, 0x54, + 0x8a, 0xe0, 0x12, 0x73, 0x49, 0x2c, 0x49, 0x74, 0x44, 0x52, 0xef, 0x01, 0x56, 0x2e, 0x24, 0xcd, + 0xc5, 0x59, 0x94, 0x5f, 0x1e, 0x5f, 0x94, 0x9f, 0x5f, 0x52, 0x2c, 0xc1, 0xa8, 0xc0, 0xac, 0xc1, + 0x13, 0xc4, 0x51, 0x94, 0x5f, 0x1e, 0x04, 0xe2, 0x0b, 0x29, 0x72, 0xf1, 0x24, 0xe7, 0xe7, 0x94, + 0xe6, 0xe6, 0x41, 0xe5, 0x99, 0xc0, 0xf2, 0xdc, 0x10, 0x31, 0xb0, 0x12, 0x27, 0xbf, 0x13, 0x8f, + 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, + 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0x32, 0x49, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, + 0x4b, 0xce, 0xcf, 0xd5, 0x47, 0x72, 0x3b, 0x12, 0x13, 0xec, 0x54, 0x7d, 0x14, 0x7f, 0x25, 0xb1, + 0x81, 0x05, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x2c, 0x16, 0x1b, 0x0d, 0xef, 0x00, 0x00, + 0x00, +} + +func (m *DataAvailabilityHeader) 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 *DataAvailabilityHeader) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DataAvailabilityHeader) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ColumnRoots) > 0 { + for iNdEx := len(m.ColumnRoots) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ColumnRoots[iNdEx]) + copy(dAtA[i:], m.ColumnRoots[iNdEx]) + i = encodeVarintDataAvailabilityHeader(dAtA, i, uint64(len(m.ColumnRoots[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.RowRoots) > 0 { + for iNdEx := len(m.RowRoots) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.RowRoots[iNdEx]) + copy(dAtA[i:], m.RowRoots[iNdEx]) + i = encodeVarintDataAvailabilityHeader(dAtA, i, uint64(len(m.RowRoots[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintDataAvailabilityHeader(dAtA []byte, offset int, v uint64) int { + offset -= sovDataAvailabilityHeader(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *DataAvailabilityHeader) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.RowRoots) > 0 { + for _, b := range m.RowRoots { + l = len(b) + n += 1 + l + sovDataAvailabilityHeader(uint64(l)) + } + } + if len(m.ColumnRoots) > 0 { + for _, b := range m.ColumnRoots { + l = len(b) + n += 1 + l + sovDataAvailabilityHeader(uint64(l)) + } + } + return n +} + +func sovDataAvailabilityHeader(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozDataAvailabilityHeader(x uint64) (n int) { + return sovDataAvailabilityHeader(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *DataAvailabilityHeader) 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 ErrIntOverflowDataAvailabilityHeader + } + 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: DataAvailabilityHeader: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DataAvailabilityHeader: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RowRoots", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDataAvailabilityHeader + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthDataAvailabilityHeader + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthDataAvailabilityHeader + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RowRoots = append(m.RowRoots, make([]byte, postIndex-iNdEx)) + copy(m.RowRoots[len(m.RowRoots)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ColumnRoots", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDataAvailabilityHeader + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthDataAvailabilityHeader + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthDataAvailabilityHeader + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ColumnRoots = append(m.ColumnRoots, make([]byte, postIndex-iNdEx)) + copy(m.ColumnRoots[len(m.ColumnRoots)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipDataAvailabilityHeader(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthDataAvailabilityHeader + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipDataAvailabilityHeader(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowDataAvailabilityHeader + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowDataAvailabilityHeader + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowDataAvailabilityHeader + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthDataAvailabilityHeader + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupDataAvailabilityHeader + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthDataAvailabilityHeader + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthDataAvailabilityHeader = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowDataAvailabilityHeader = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupDataAvailabilityHeader = fmt.Errorf("proto: unexpected end of group") +) diff --git a/proto/tendermint/da/data_availability_header.proto b/proto/tendermint/da/data_availability_header.proto new file mode 100644 index 0000000000..3e82c6084b --- /dev/null +++ b/proto/tendermint/da/data_availability_header.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; +package tendermint.da; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/da"; + +// DataAvailabilityHeader contains the row and column roots of the erasure +// coded version of the data in Block.Data. +// Therefor the original Block.Data is arranged in a +// k × k matrix, which is then "extended" to a +// 2k × 2k matrix applying multiple times Reed-Solomon encoding. +// For details see Section 5.2: https://arxiv.org/abs/1809.09044 +// or the Celestia specification: +// https://github.com/celestiaorg/celestia-specs/blob/master/specs/data_structures.md#availabledataheader +// Note that currently we list row and column roots in separate fields +// (different from the spec). +message DataAvailabilityHeader { + // RowRoot_j = root((M_{j,1} || M_{j,2} || ... || M_{j,2k} )) + repeated bytes row_roots = 1; + // ColumnRoot_j = root((M_{1,j} || M_{2,j} || ... || M_{2k,j} )) + repeated bytes column_roots = 2; +} \ No newline at end of file From eee8f352cb6a1687a9f6b470abe28bbd4eb66413 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 27 Apr 2022 12:23:22 -0500 Subject: [PATCH 03/31] add nmt wrapper nmt_wrapper: add extend nmt wrapper with tree method patch filter test Co-authored-by: Hlib Kanunnikov Co-authored-by: Viacheslav Gonkivskyi --- go.mod | 3 +- go.sum | 24 ++++- internal/state/tx_filter_test.go | 4 +- pkg/wrapper/nmt_wrapper.go | 83 +++++++++++++++ pkg/wrapper/nmt_wrapper_test.go | 168 +++++++++++++++++++++++++++++++ 5 files changed, 276 insertions(+), 6 deletions(-) create mode 100644 pkg/wrapper/nmt_wrapper.go create mode 100644 pkg/wrapper/nmt_wrapper_test.go diff --git a/go.mod b/go.mod index 19badc3eeb..d6b49080d3 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,8 @@ require ( github.com/adlio/schema v1.3.0 github.com/btcsuite/btcd v0.22.0-beta github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce + github.com/celestiaorg/nmt v0.8.0 + github.com/celestiaorg/rsmt2d v0.5.0 github.com/creachadair/atomicfile v0.2.5 github.com/creachadair/taskgroup v0.3.2 github.com/creachadair/tomledit v0.0.18 @@ -46,6 +48,5 @@ require ( golang.org/x/net v0.0.0-20220412020605-290c469a71a5 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c google.golang.org/grpc v1.46.0 - gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect pgregory.net/rapid v0.4.7 ) diff --git a/go.sum b/go.sum index 79be52c717..3943d738aa 100644 --- a/go.sum +++ b/go.sum @@ -175,6 +175,14 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY= github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= +github.com/celestiaorg/go-leopard v0.1.0 h1:28z2EkvKJIez5J9CEaiiUEC+OxalRLtTGJJ1oScfE1g= +github.com/celestiaorg/go-leopard v0.1.0/go.mod h1:NtO/rjlB8dw2aq7jr06vZFKGvryQcTDXaNHelmPNOAM= +github.com/celestiaorg/merkletree v0.0.0-20210714075610-a84dc3ddbbe4 h1:CJdIpo8n5MFP2MwK0gSRcOVlDlFdQJO1p+FqdxYzmvc= +github.com/celestiaorg/merkletree v0.0.0-20210714075610-a84dc3ddbbe4/go.mod h1:fzuHnhzj1pUygGz+1ZkB3uQbEUL4htqCGJ4Qs2LwMZA= +github.com/celestiaorg/nmt v0.8.0 h1:wtX7GRouLbmBe+ffnc8+cOg2UbWteM+Y1imZuZ/EeqU= +github.com/celestiaorg/nmt v0.8.0/go.mod h1:3bqzTj8xKj0DgQUpOgZzoxvtNkC3MS/hTbQ6dn8SIa0= +github.com/celestiaorg/rsmt2d v0.5.0 h1:Wa0uNZUXl8lIMJnSunjoD65ktqBedXZD0z2ZU3xKYYw= +github.com/celestiaorg/rsmt2d v0.5.0/go.mod h1:EZ+O2KdCq8xI7WFwjATLdhtMdrdClmAs2w7zENDr010= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= @@ -454,6 +462,8 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -772,7 +782,6 @@ github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nishanths/exhaustive v0.7.11 h1:xV/WU3Vdwh5BUH4N06JNUznb6d5zhRPOnlgCrpNYNKA= github.com/nishanths/exhaustive v0.7.11/go.mod h1:gX+MP7DWMKJmNa1HfMozK+u04hQd3na9i0hyqf3/dOI= @@ -1073,6 +1082,8 @@ github.com/vektra/mockery/v2 v2.12.0/go.mod h1:8vf4KDDUptfkyypzdHLuE7OE2xA7Gdt60 github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3 h1:zMsHhfK9+Wdl1F7sIKLyx3wrOFofpb3rWFbA4HgcK5k= +github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3/go.mod h1:R0Gbuw7ElaGSLOZUSwBm/GgVwMd30jWxBDdAyMOeTuc= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= @@ -1091,6 +1102,11 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +gitlab.com/NebulousLabs/errors v0.0.0-20171229012116-7ead97ef90b8/go.mod h1:ZkMZ0dpQyWwlENaeZVBiQRjhMEZvk6VTXquzl3FOFP8= +gitlab.com/NebulousLabs/errors v0.0.0-20200929122200-06c536cf6975 h1:L/ENs/Ar1bFzUeKx6m3XjlmBgIUlykX9dzvp5k9NGxc= +gitlab.com/NebulousLabs/errors v0.0.0-20200929122200-06c536cf6975/go.mod h1:ZkMZ0dpQyWwlENaeZVBiQRjhMEZvk6VTXquzl3FOFP8= +gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40 h1:dizWJqTWjwyD8KGcMOwgrkqu1JIkofYgKkmDeNE7oAs= +gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40/go.mod h1:rOnSnoRyxMI3fe/7KIbVcsHRGxe30OONv8dEgo+vCfA= gitlab.com/bosi/decorder v0.2.1 h1:ehqZe8hI4w7O4b1vgsDZw1YU1PE7iJXrQWFMsocbQ1w= gitlab.com/bosi/decorder v0.2.1/go.mod h1:6C/nhLSbF6qZbYD8bRmISBwc6vcWdNsiIBkRvjJFrH0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -1145,6 +1161,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200109152110-61a87790db17/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1152,6 +1169,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -1736,8 +1754,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= diff --git a/internal/state/tx_filter_test.go b/internal/state/tx_filter_test.go index 27af28a40c..df13eda5e6 100644 --- a/internal/state/tx_filter_test.go +++ b/internal/state/tx_filter_test.go @@ -22,8 +22,8 @@ func TestTxFilter(t *testing.T) { tx types.Tx isErr bool }{ - {types.Tx(tmrand.Bytes(2155)), false}, - {types.Tx(tmrand.Bytes(2156)), true}, + {types.Tx(tmrand.Bytes(2106)), false}, + {types.Tx(tmrand.Bytes(2152)), true}, {types.Tx(tmrand.Bytes(3000)), true}, } diff --git a/pkg/wrapper/nmt_wrapper.go b/pkg/wrapper/nmt_wrapper.go new file mode 100644 index 0000000000..e9b3747d5b --- /dev/null +++ b/pkg/wrapper/nmt_wrapper.go @@ -0,0 +1,83 @@ +package wrapper + +import ( + "fmt" + + "github.com/celestiaorg/nmt" + "github.com/celestiaorg/rsmt2d" + + "github.com/tendermint/tendermint/pkg/consts" +) + +// Fulfills the rsmt2d.Tree interface and rsmt2d.TreeConstructorFn function +var _ rsmt2d.TreeConstructorFn = ErasuredNamespacedMerkleTree{}.Constructor +var _ rsmt2d.Tree = &ErasuredNamespacedMerkleTree{} + +// ErasuredNamespacedMerkleTree wraps NamespaceMerkleTree to conform to the +// rsmt2d.Tree interface while also providing the correct namespaces to the +// underlying NamespaceMerkleTree. It does this by adding the already included +// namespace to the first half of the tree, and then uses the parity namespace +// ID for each share pushed to the second half of the tree. This allows for the +// namespaces to be included in the erasure data, while also keeping the nmt +// library sufficiently general +type ErasuredNamespacedMerkleTree struct { + squareSize uint64 // note: this refers to the width of the original square before erasure-coded + options []nmt.Option + tree *nmt.NamespacedMerkleTree +} + +// NewErasuredNamespacedMerkleTree issues a new ErasuredNamespacedMerkleTree. squareSize must be greater than zero +func NewErasuredNamespacedMerkleTree(origSquareSize uint64, setters ...nmt.Option) ErasuredNamespacedMerkleTree { + if origSquareSize == 0 { + panic("cannot create a ErasuredNamespacedMerkleTree of squareSize == 0") + } + tree := nmt.New(consts.NewBaseHashFunc(), setters...) + return ErasuredNamespacedMerkleTree{squareSize: origSquareSize, options: setters, tree: tree} +} + +// Constructor acts as the rsmt2d.TreeConstructorFn for +// ErasuredNamespacedMerkleTree +func (w ErasuredNamespacedMerkleTree) Constructor() rsmt2d.Tree { + newTree := NewErasuredNamespacedMerkleTree(w.squareSize, w.options...) + return &newTree +} + +// Push adds the provided data to the underlying NamespaceMerkleTree, and +// automatically uses the first DefaultNamespaceIDLen number of bytes as the +// namespace unless the data pushed to the second half of the tree. Fulfills the +// rsmt.Tree interface. NOTE: panics if an error is encountered while pushing or +// if the tree size is exceeded. +func (w *ErasuredNamespacedMerkleTree) Push(data []byte, idx rsmt2d.SquareIndex) { + if idx.Axis+1 > 2*uint(w.squareSize) || idx.Cell+1 > 2*uint(w.squareSize) { + panic(fmt.Sprintf("pushed past predetermined square size: boundary at %d index at %+v", 2*w.squareSize, idx)) + } + nidAndData := make([]byte, consts.NamespaceSize+len(data)) + copy(nidAndData[consts.NamespaceSize:], data) + // use the parity namespace if the cell is not in Q0 of the extended data square + if idx.Axis+1 > uint(w.squareSize) || idx.Cell+1 > uint(w.squareSize) { + copy(nidAndData[:consts.NamespaceSize], consts.ParitySharesNamespaceID) + } else { + copy(nidAndData[:consts.NamespaceSize], data[:consts.NamespaceSize]) + } + // push to the underlying tree + err := w.tree.Push(nidAndData) + // panic on error + if err != nil { + panic(err) + } +} + +// Root fulfills the rsmt.Tree interface by generating and returning the +// underlying NamespaceMerkleTree Root. +func (w *ErasuredNamespacedMerkleTree) Root() []byte { + return w.tree.Root() +} + +func (w *ErasuredNamespacedMerkleTree) Prove(ind int) (nmt.Proof, error) { + return w.tree.Prove(ind) +} + +// Tree returns the underlying NamespacedMerkleTree +func (w *ErasuredNamespacedMerkleTree) Tree() *nmt.NamespacedMerkleTree { + return w.tree +} diff --git a/pkg/wrapper/nmt_wrapper_test.go b/pkg/wrapper/nmt_wrapper_test.go new file mode 100644 index 0000000000..b43aeda402 --- /dev/null +++ b/pkg/wrapper/nmt_wrapper_test.go @@ -0,0 +1,168 @@ +package wrapper + +import ( + "bytes" + "crypto/rand" + "crypto/sha256" + "sort" + "testing" + + "github.com/celestiaorg/nmt" + "github.com/celestiaorg/rsmt2d" + "github.com/stretchr/testify/assert" + "github.com/tendermint/tendermint/pkg/consts" +) + +func TestPushErasuredNamespacedMerkleTree(t *testing.T) { + testCases := []struct { + name string + squareSize int + }{ + {"extendedSquareSize = 16", 8}, + {"extendedSquareSize = 256", 128}, + } + for _, tc := range testCases { + tc := tc + n := NewErasuredNamespacedMerkleTree(uint64(tc.squareSize)) + tree := n.Constructor() + + // push test data to the tree + for i, d := range generateErasuredData(t, tc.squareSize, consts.DefaultCodec()) { + // push will panic if there's an error + tree.Push(d, rsmt2d.SquareIndex{Axis: uint(0), Cell: uint(i)}) + } + } +} + +func TestRootErasuredNamespacedMerkleTree(t *testing.T) { + // check that the root is different from a standard nmt tree this should be + // the case, because the ErasuredNamespacedMerkleTree should add namespaces + // to the second half of the tree + size := 8 + data := generateRandNamespacedRawData(size, consts.NamespaceSize, consts.MsgShareSize) + n := NewErasuredNamespacedMerkleTree(uint64(size)) + tree := n.Constructor() + nmtTree := nmt.New(sha256.New()) + + for i, d := range data { + tree.Push(d, rsmt2d.SquareIndex{Axis: uint(0), Cell: uint(i)}) + err := nmtTree.Push(d) + if err != nil { + t.Error(err) + } + } + + assert.NotEqual(t, nmtTree.Root(), tree.Root()) +} + +func TestErasureNamespacedMerkleTreePanics(t *testing.T) { + testCases := []struct { + name string + pFunc assert.PanicTestFunc + }{ + { + "push over square size", + assert.PanicTestFunc( + func() { + data := generateErasuredData(t, 16, consts.DefaultCodec()) + n := NewErasuredNamespacedMerkleTree(uint64(15)) + tree := n.Constructor() + for i, d := range data { + tree.Push(d, rsmt2d.SquareIndex{Axis: uint(0), Cell: uint(i)}) + } + }), + }, + { + "push in incorrect lexigraphic order", + assert.PanicTestFunc( + func() { + data := generateErasuredData(t, 16, consts.DefaultCodec()) + n := NewErasuredNamespacedMerkleTree(uint64(16)) + tree := n.Constructor() + for i := len(data) - 1; i > 0; i-- { + tree.Push(data[i], rsmt2d.SquareIndex{Axis: uint(0), Cell: uint(i)}) + } + }, + ), + }, + } + for _, tc := range testCases { + tc := tc + assert.Panics(t, tc.pFunc, tc.name) + + } +} + +func TestExtendedDataSquare(t *testing.T) { + squareSize := 4 + // data for a 4X4 square + raw := generateRandNamespacedRawData( + squareSize*squareSize, + consts.NamespaceSize, + consts.MsgShareSize, + ) + + tree := NewErasuredNamespacedMerkleTree(uint64(squareSize)) + + _, err := rsmt2d.ComputeExtendedDataSquare(raw, consts.DefaultCodec(), tree.Constructor) + assert.NoError(t, err) +} + +func TestErasuredNamespacedMerkleTree(t *testing.T) { + // check that the Tree() returns exact underlying nmt tree + size := 8 + data := generateRandNamespacedRawData(size, consts.NamespaceSize, consts.MsgShareSize) + n := NewErasuredNamespacedMerkleTree(uint64(size)) + tree := n.Constructor() + + for i, d := range data { + tree.Push(d, rsmt2d.SquareIndex{Axis: uint(0), Cell: uint(i)}) + } + + assert.Equal(t, n.Tree(), n.tree) + assert.Equal(t, n.Tree().Root(), n.tree.Root()) +} + +// generateErasuredData produces a slice that is twice as long as it erasures +// the data +func generateErasuredData(t *testing.T, numLeaves int, codec rsmt2d.Codec) [][]byte { + raw := generateRandNamespacedRawData( + numLeaves, + consts.NamespaceSize, + consts.MsgShareSize, + ) + erasuredData, err := codec.Encode(raw) + if err != nil { + t.Error(err) + } + return append(raw, erasuredData...) +} + +// this code is copy pasted from the plugin, and should likely be exported in the plugin instead +func generateRandNamespacedRawData(total int, nidSize int, leafSize int) [][]byte { + data := make([][]byte, total) + for i := 0; i < total; i++ { + nid := make([]byte, nidSize) + _, err := rand.Read(nid) + if err != nil { + panic(err) + } + data[i] = nid + } + + sortByteArrays(data) + for i := 0; i < total; i++ { + d := make([]byte, leafSize) + _, err := rand.Read(d) + if err != nil { + panic(err) + } + data[i] = append(data[i], d...) + } + + return data +} + +func sortByteArrays(src [][]byte) { + sort.Slice(src, func(i, j int) bool { return bytes.Compare(src[i], src[j]) < 0 }) +} From 86df6529a7c0cc1112c34b6bf1b5364aa0518dec Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Tue, 3 May 2022 12:18:07 -0500 Subject: [PATCH 04/31] Modify the block data to hold evidence and messages Co-authored-by: Ismail Khoffi Co-authored-by: Hlib Kanunnikov Co-authored-by: John Adler --- internal/mempool/v0/clist_mempool_test.go | 12 +- internal/mempool/v1/mempool_test.go | 4 +- internal/state/tx_filter_test.go | 2 +- node/node_test.go | 2 +- proto/tendermint/blocksync/message_test.go | 2 +- proto/tendermint/types/block.pb.go | 85 +- proto/tendermint/types/block.proto | 2 - proto/tendermint/types/evidence.pb.go | 1394 -------- proto/tendermint/types/evidence.proto | 38 - proto/tendermint/types/types.pb.go | 3449 +++++++++++++++----- proto/tendermint/types/types.proto | 45 + test/Makefile | 2 + types/block.go | 77 +- 13 files changed, 2783 insertions(+), 2331 deletions(-) delete mode 100644 proto/tendermint/types/evidence.pb.go delete mode 100644 proto/tendermint/types/evidence.proto diff --git a/internal/mempool/v0/clist_mempool_test.go b/internal/mempool/v0/clist_mempool_test.go index 61ec543ef7..a68d42f7d2 100644 --- a/internal/mempool/v0/clist_mempool_test.go +++ b/internal/mempool/v0/clist_mempool_test.go @@ -130,11 +130,11 @@ func TestReapMaxBytesMaxGas(t *testing.T) { {20, 0, -1, 0}, {20, 0, 10, 0}, {20, 10, 10, 0}, - {20, 24, 10, 1}, + {20, 28, 10, 1}, {20, 240, 5, 5}, - {20, 240, -1, 10}, - {20, 240, 10, 10}, - {20, 240, 15, 10}, + {20, 280, -1, 10}, + {20, 280, 10, 10}, + {20, 280, 15, 10}, {20, 20000, -1, 20}, {20, 20000, 5, 5}, {20, 20000, 30, 20}, @@ -169,14 +169,14 @@ func TestMempoolFilters(t *testing.T) { }{ {10, nopPreFilter, nopPostFilter, 10}, {10, mempool.PreCheckMaxBytes(10), nopPostFilter, 0}, - {10, mempool.PreCheckMaxBytes(22), nopPostFilter, 10}, + {10, mempool.PreCheckMaxBytes(28), nopPostFilter, 10}, {10, nopPreFilter, mempool.PostCheckMaxGas(-1), 10}, {10, nopPreFilter, mempool.PostCheckMaxGas(0), 0}, {10, nopPreFilter, mempool.PostCheckMaxGas(1), 10}, {10, nopPreFilter, mempool.PostCheckMaxGas(3000), 10}, {10, mempool.PreCheckMaxBytes(10), mempool.PostCheckMaxGas(20), 0}, {10, mempool.PreCheckMaxBytes(30), mempool.PostCheckMaxGas(20), 10}, - {10, mempool.PreCheckMaxBytes(22), mempool.PostCheckMaxGas(1), 10}, + {10, mempool.PreCheckMaxBytes(28), mempool.PostCheckMaxGas(1), 10}, {10, mempool.PreCheckMaxBytes(22), mempool.PostCheckMaxGas(0), 0}, } for tcIndex, tt := range tests { diff --git a/internal/mempool/v1/mempool_test.go b/internal/mempool/v1/mempool_test.go index 72a72861c9..93838eb6c7 100644 --- a/internal/mempool/v1/mempool_test.go +++ b/internal/mempool/v1/mempool_test.go @@ -260,7 +260,7 @@ func TestTxMempool_ReapMaxBytesMaxGas(t *testing.T) { ensurePrioritized(reapedTxs) require.Equal(t, len(tTxs), txmp.Size()) require.Equal(t, int64(5690), txmp.SizeBytes()) - require.GreaterOrEqual(t, len(reapedTxs), 16) + require.GreaterOrEqual(t, len(reapedTxs), 15) // Reap by both transaction bytes and gas, where the size yields 31 reaped // transactions and the gas limit reaps 25 transactions. @@ -268,7 +268,7 @@ func TestTxMempool_ReapMaxBytesMaxGas(t *testing.T) { ensurePrioritized(reapedTxs) require.Equal(t, len(tTxs), txmp.Size()) require.Equal(t, int64(5690), txmp.SizeBytes()) - require.Len(t, reapedTxs, 25) + require.Len(t, reapedTxs, 23) } func TestTxMempool_ReapMaxTxs(t *testing.T) { diff --git a/internal/state/tx_filter_test.go b/internal/state/tx_filter_test.go index df13eda5e6..04a1badd44 100644 --- a/internal/state/tx_filter_test.go +++ b/internal/state/tx_filter_test.go @@ -22,7 +22,7 @@ func TestTxFilter(t *testing.T) { tx types.Tx isErr bool }{ - {types.Tx(tmrand.Bytes(2106)), false}, + {types.Tx(tmrand.Bytes(2149)), false}, {types.Tx(tmrand.Bytes(2152)), true}, {types.Tx(tmrand.Bytes(3000)), true}, } diff --git a/node/node_test.go b/node/node_test.go index 305f9b873c..3e52ce961b 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -406,7 +406,7 @@ func TestMaxProposalBlockSize(t *testing.T) { // fill the mempool with one txs just below the maximum size txLength := int(types.MaxDataBytesNoEvidence(maxBytes, types.MaxVotesCount)) - tx := tmrand.Bytes(txLength - 6) // to account for the varint + tx := tmrand.Bytes(txLength - 6 - 4) // to account for the varint err = mp.CheckTx(context.Background(), tx, nil, mempool.TxInfo{}) assert.NoError(t, err) // now produce more txs than what a normal block can hold with 10 smaller txs diff --git a/proto/tendermint/blocksync/message_test.go b/proto/tendermint/blocksync/message_test.go index 3406c6dff4..5642527b72 100644 --- a/proto/tendermint/blocksync/message_test.go +++ b/proto/tendermint/blocksync/message_test.go @@ -102,7 +102,7 @@ func TestBlockchainMessageVectors(t *testing.T) { BlockRequest: &bcproto.BlockRequest{Height: math.MaxInt64}}}, "0a0a08ffffffffffffffff7f"}, {"BlockResponseMessage", &bcproto.Message{Sum: &bcproto.Message_BlockResponse{ - BlockResponse: &bcproto.BlockResponse{Block: bpb}}}, "1a700a6e0a5b0a02080b1803220b088092b8c398feffffff012a0212003a20c4da88e876062aa1543400d50d0eaa0dac88096057949cfb7bca7f3a48c04bf96a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855120d0a0b48656c6c6f20576f726c641a00"}, + BlockResponse: &bcproto.BlockResponse{Block: bpb}}}, "1a97010a94010a5b0a02080b1803220b088092b8c398feffffff012a0212003a20269ece38583f42aaf53fdd3abe1f570ab9b0d08284d080900966040a29df504c6a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85512350a0b48656c6c6f20576f726c641a00220028013220269ece38583f42aaf53fdd3abe1f570ab9b0d08284d080900966040a29df504c"}, {"NoBlockResponseMessage", &bcproto.Message{Sum: &bcproto.Message_NoBlockResponse{ NoBlockResponse: &bcproto.NoBlockResponse{Height: 1}}}, "12020801"}, {"NoBlockResponseMessage", &bcproto.Message{Sum: &bcproto.Message_NoBlockResponse{ diff --git a/proto/tendermint/types/block.pb.go b/proto/tendermint/types/block.pb.go index f2077aad8b..6dd30be50a 100644 --- a/proto/tendermint/types/block.pb.go +++ b/proto/tendermint/types/block.pb.go @@ -24,10 +24,9 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Block struct { - Header Header `protobuf:"bytes,1,opt,name=header,proto3" json:"header"` - Data Data `protobuf:"bytes,2,opt,name=data,proto3" json:"data"` - Evidence EvidenceList `protobuf:"bytes,3,opt,name=evidence,proto3" json:"evidence"` - LastCommit *Commit `protobuf:"bytes,4,opt,name=last_commit,json=lastCommit,proto3" json:"last_commit,omitempty"` + Header Header `protobuf:"bytes,1,opt,name=header,proto3" json:"header"` + Data Data `protobuf:"bytes,2,opt,name=data,proto3" json:"data"` + LastCommit *Commit `protobuf:"bytes,4,opt,name=last_commit,json=lastCommit,proto3" json:"last_commit,omitempty"` } func (m *Block) Reset() { *m = Block{} } @@ -77,13 +76,6 @@ func (m *Block) GetData() Data { return Data{} } -func (m *Block) GetEvidence() EvidenceList { - if m != nil { - return m.Evidence - } - return EvidenceList{} -} - func (m *Block) GetLastCommit() *Commit { if m != nil { return m.LastCommit @@ -98,24 +90,22 @@ func init() { func init() { proto.RegisterFile("tendermint/types/block.proto", fileDescriptor_70840e82f4357ab1) } var fileDescriptor_70840e82f4357ab1 = []byte{ - // 266 bytes of a gzipped FileDescriptorProto + // 228 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x29, 0x49, 0xcd, 0x4b, 0x49, 0x2d, 0xca, 0xcd, 0xcc, 0x2b, 0xd1, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, 0x4f, 0xca, 0xc9, 0x4f, 0xce, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x40, 0xc8, 0xea, 0x81, 0x65, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x92, 0xfa, 0x20, 0x16, 0x44, 0x9d, 0x14, 0xa6, 0x29, 0x60, - 0x12, 0x2a, 0x2b, 0x8f, 0x21, 0x9b, 0x5a, 0x96, 0x99, 0x92, 0x9a, 0x97, 0x9c, 0x0a, 0x51, 0xa0, - 0xf4, 0x8e, 0x91, 0x8b, 0xd5, 0x09, 0x64, 0xad, 0x90, 0x19, 0x17, 0x5b, 0x46, 0x6a, 0x62, 0x4a, - 0x6a, 0x91, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xb7, 0x91, 0x84, 0x1e, 0xba, 0x0b, 0xf4, 0x3c, 0xc0, - 0xf2, 0x4e, 0x2c, 0x27, 0xee, 0xc9, 0x33, 0x04, 0x41, 0x55, 0x0b, 0x19, 0x70, 0xb1, 0xa4, 0x24, - 0x96, 0x24, 0x4a, 0x30, 0x81, 0x75, 0x89, 0x61, 0xea, 0x72, 0x49, 0x2c, 0x49, 0x84, 0xea, 0x01, - 0xab, 0x14, 0x72, 0xe0, 0xe2, 0x80, 0xb9, 0x42, 0x82, 0x19, 0xac, 0x4b, 0x0e, 0x53, 0x97, 0x2b, - 0x54, 0x85, 0x4f, 0x66, 0x71, 0x09, 0x54, 0x37, 0x5c, 0x97, 0x90, 0x25, 0x17, 0x77, 0x4e, 0x62, - 0x71, 0x49, 0x7c, 0x72, 0x7e, 0x6e, 0x6e, 0x66, 0x89, 0x04, 0x0b, 0x2e, 0x07, 0x3b, 0x83, 0xe5, - 0x83, 0xb8, 0x40, 0x8a, 0x21, 0x6c, 0xa7, 0xc0, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, - 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, - 0x63, 0x88, 0x32, 0x4f, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x47, 0x0e, - 0x36, 0x04, 0x13, 0x12, 0xf8, 0xe8, 0x41, 0x9a, 0xc4, 0x06, 0x16, 0x37, 0x06, 0x04, 0x00, 0x00, - 0xff, 0xff, 0x79, 0x8c, 0xb5, 0x43, 0xd1, 0x01, 0x00, 0x00, + 0x12, 0x22, 0xab, 0xb4, 0x86, 0x91, 0x8b, 0xd5, 0x09, 0x64, 0xaa, 0x90, 0x19, 0x17, 0x5b, 0x46, + 0x6a, 0x62, 0x4a, 0x6a, 0x91, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xb7, 0x91, 0x84, 0x1e, 0xba, 0x05, + 0x7a, 0x1e, 0x60, 0x79, 0x27, 0x96, 0x13, 0xf7, 0xe4, 0x19, 0x82, 0xa0, 0xaa, 0x85, 0x0c, 0xb8, + 0x58, 0x52, 0x12, 0x4b, 0x12, 0x25, 0x98, 0xc0, 0xba, 0xc4, 0x30, 0x75, 0xb9, 0x24, 0x96, 0x24, + 0x42, 0xf5, 0x80, 0x55, 0x0a, 0x59, 0x72, 0x71, 0xe7, 0x24, 0x16, 0x97, 0xc4, 0x27, 0xe7, 0xe7, + 0xe6, 0x66, 0x96, 0x48, 0xb0, 0xe0, 0xb2, 0xce, 0x19, 0x2c, 0x1f, 0xc4, 0x05, 0x52, 0x0c, 0x61, + 0x3b, 0x05, 0x9e, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, + 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x79, 0x7a, 0x66, + 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x3e, 0xb2, 0x8f, 0x11, 0x4c, 0x48, 0xc8, 0xa0, + 0x87, 0x46, 0x12, 0x1b, 0x58, 0xdc, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0xa3, 0xfc, 0x87, 0xdc, + 0x6e, 0x01, 0x00, 0x00, } func (m *Block) Marshal() (dAtA []byte, err error) { @@ -150,16 +140,6 @@ func (m *Block) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x22 } - { - size, err := m.Evidence.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintBlock(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a { size, err := m.Data.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -204,8 +184,6 @@ func (m *Block) Size() (n int) { n += 1 + l + sovBlock(uint64(l)) l = m.Data.Size() n += 1 + l + sovBlock(uint64(l)) - l = m.Evidence.Size() - n += 1 + l + sovBlock(uint64(l)) if m.LastCommit != nil { l = m.LastCommit.Size() n += 1 + l + sovBlock(uint64(l)) @@ -314,39 +292,6 @@ func (m *Block) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBlock - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthBlock - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthBlock - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Evidence.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field LastCommit", wireType) diff --git a/proto/tendermint/types/block.proto b/proto/tendermint/types/block.proto index 84e9bb15d8..bf4b35664f 100644 --- a/proto/tendermint/types/block.proto +++ b/proto/tendermint/types/block.proto @@ -5,11 +5,9 @@ option go_package = "github.com/tendermint/tendermint/proto/tendermint/types"; import "gogoproto/gogo.proto"; import "tendermint/types/types.proto"; -import "tendermint/types/evidence.proto"; message Block { Header header = 1 [(gogoproto.nullable) = false]; Data data = 2 [(gogoproto.nullable) = false]; - tendermint.types.EvidenceList evidence = 3 [(gogoproto.nullable) = false]; Commit last_commit = 4; } diff --git a/proto/tendermint/types/evidence.pb.go b/proto/tendermint/types/evidence.pb.go deleted file mode 100644 index daab3dc34f..0000000000 --- a/proto/tendermint/types/evidence.pb.go +++ /dev/null @@ -1,1394 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: tendermint/types/evidence.proto - -package types - -import ( - fmt "fmt" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - _ "github.com/gogo/protobuf/types" - github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" - io "io" - math "math" - math_bits "math/bits" - time "time" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf -var _ = time.Kitchen - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type Evidence struct { - // Types that are valid to be assigned to Sum: - // *Evidence_DuplicateVoteEvidence - // *Evidence_LightClientAttackEvidence - Sum isEvidence_Sum `protobuf_oneof:"sum"` -} - -func (m *Evidence) Reset() { *m = Evidence{} } -func (m *Evidence) String() string { return proto.CompactTextString(m) } -func (*Evidence) ProtoMessage() {} -func (*Evidence) Descriptor() ([]byte, []int) { - return fileDescriptor_6825fabc78e0a168, []int{0} -} -func (m *Evidence) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Evidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Evidence.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 *Evidence) XXX_Merge(src proto.Message) { - xxx_messageInfo_Evidence.Merge(m, src) -} -func (m *Evidence) XXX_Size() int { - return m.Size() -} -func (m *Evidence) XXX_DiscardUnknown() { - xxx_messageInfo_Evidence.DiscardUnknown(m) -} - -var xxx_messageInfo_Evidence proto.InternalMessageInfo - -type isEvidence_Sum interface { - isEvidence_Sum() - MarshalTo([]byte) (int, error) - Size() int -} - -type Evidence_DuplicateVoteEvidence struct { - DuplicateVoteEvidence *DuplicateVoteEvidence `protobuf:"bytes,1,opt,name=duplicate_vote_evidence,json=duplicateVoteEvidence,proto3,oneof" json:"duplicate_vote_evidence,omitempty"` -} -type Evidence_LightClientAttackEvidence struct { - LightClientAttackEvidence *LightClientAttackEvidence `protobuf:"bytes,2,opt,name=light_client_attack_evidence,json=lightClientAttackEvidence,proto3,oneof" json:"light_client_attack_evidence,omitempty"` -} - -func (*Evidence_DuplicateVoteEvidence) isEvidence_Sum() {} -func (*Evidence_LightClientAttackEvidence) isEvidence_Sum() {} - -func (m *Evidence) GetSum() isEvidence_Sum { - if m != nil { - return m.Sum - } - return nil -} - -func (m *Evidence) GetDuplicateVoteEvidence() *DuplicateVoteEvidence { - if x, ok := m.GetSum().(*Evidence_DuplicateVoteEvidence); ok { - return x.DuplicateVoteEvidence - } - return nil -} - -func (m *Evidence) GetLightClientAttackEvidence() *LightClientAttackEvidence { - if x, ok := m.GetSum().(*Evidence_LightClientAttackEvidence); ok { - return x.LightClientAttackEvidence - } - return nil -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*Evidence) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*Evidence_DuplicateVoteEvidence)(nil), - (*Evidence_LightClientAttackEvidence)(nil), - } -} - -// DuplicateVoteEvidence contains evidence of a validator signed two conflicting votes. -type DuplicateVoteEvidence struct { - VoteA *Vote `protobuf:"bytes,1,opt,name=vote_a,json=voteA,proto3" json:"vote_a,omitempty"` - VoteB *Vote `protobuf:"bytes,2,opt,name=vote_b,json=voteB,proto3" json:"vote_b,omitempty"` - TotalVotingPower int64 `protobuf:"varint,3,opt,name=total_voting_power,json=totalVotingPower,proto3" json:"total_voting_power,omitempty"` - ValidatorPower int64 `protobuf:"varint,4,opt,name=validator_power,json=validatorPower,proto3" json:"validator_power,omitempty"` - Timestamp time.Time `protobuf:"bytes,5,opt,name=timestamp,proto3,stdtime" json:"timestamp"` -} - -func (m *DuplicateVoteEvidence) Reset() { *m = DuplicateVoteEvidence{} } -func (m *DuplicateVoteEvidence) String() string { return proto.CompactTextString(m) } -func (*DuplicateVoteEvidence) ProtoMessage() {} -func (*DuplicateVoteEvidence) Descriptor() ([]byte, []int) { - return fileDescriptor_6825fabc78e0a168, []int{1} -} -func (m *DuplicateVoteEvidence) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *DuplicateVoteEvidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_DuplicateVoteEvidence.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 *DuplicateVoteEvidence) XXX_Merge(src proto.Message) { - xxx_messageInfo_DuplicateVoteEvidence.Merge(m, src) -} -func (m *DuplicateVoteEvidence) XXX_Size() int { - return m.Size() -} -func (m *DuplicateVoteEvidence) XXX_DiscardUnknown() { - xxx_messageInfo_DuplicateVoteEvidence.DiscardUnknown(m) -} - -var xxx_messageInfo_DuplicateVoteEvidence proto.InternalMessageInfo - -func (m *DuplicateVoteEvidence) GetVoteA() *Vote { - if m != nil { - return m.VoteA - } - return nil -} - -func (m *DuplicateVoteEvidence) GetVoteB() *Vote { - if m != nil { - return m.VoteB - } - return nil -} - -func (m *DuplicateVoteEvidence) GetTotalVotingPower() int64 { - if m != nil { - return m.TotalVotingPower - } - return 0 -} - -func (m *DuplicateVoteEvidence) GetValidatorPower() int64 { - if m != nil { - return m.ValidatorPower - } - return 0 -} - -func (m *DuplicateVoteEvidence) GetTimestamp() time.Time { - if m != nil { - return m.Timestamp - } - return time.Time{} -} - -// LightClientAttackEvidence contains evidence of a set of validators attempting to mislead a light client. -type LightClientAttackEvidence struct { - ConflictingBlock *LightBlock `protobuf:"bytes,1,opt,name=conflicting_block,json=conflictingBlock,proto3" json:"conflicting_block,omitempty"` - CommonHeight int64 `protobuf:"varint,2,opt,name=common_height,json=commonHeight,proto3" json:"common_height,omitempty"` - ByzantineValidators []*Validator `protobuf:"bytes,3,rep,name=byzantine_validators,json=byzantineValidators,proto3" json:"byzantine_validators,omitempty"` - TotalVotingPower int64 `protobuf:"varint,4,opt,name=total_voting_power,json=totalVotingPower,proto3" json:"total_voting_power,omitempty"` - Timestamp time.Time `protobuf:"bytes,5,opt,name=timestamp,proto3,stdtime" json:"timestamp"` -} - -func (m *LightClientAttackEvidence) Reset() { *m = LightClientAttackEvidence{} } -func (m *LightClientAttackEvidence) String() string { return proto.CompactTextString(m) } -func (*LightClientAttackEvidence) ProtoMessage() {} -func (*LightClientAttackEvidence) Descriptor() ([]byte, []int) { - return fileDescriptor_6825fabc78e0a168, []int{2} -} -func (m *LightClientAttackEvidence) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *LightClientAttackEvidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_LightClientAttackEvidence.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 *LightClientAttackEvidence) XXX_Merge(src proto.Message) { - xxx_messageInfo_LightClientAttackEvidence.Merge(m, src) -} -func (m *LightClientAttackEvidence) XXX_Size() int { - return m.Size() -} -func (m *LightClientAttackEvidence) XXX_DiscardUnknown() { - xxx_messageInfo_LightClientAttackEvidence.DiscardUnknown(m) -} - -var xxx_messageInfo_LightClientAttackEvidence proto.InternalMessageInfo - -func (m *LightClientAttackEvidence) GetConflictingBlock() *LightBlock { - if m != nil { - return m.ConflictingBlock - } - return nil -} - -func (m *LightClientAttackEvidence) GetCommonHeight() int64 { - if m != nil { - return m.CommonHeight - } - return 0 -} - -func (m *LightClientAttackEvidence) GetByzantineValidators() []*Validator { - if m != nil { - return m.ByzantineValidators - } - return nil -} - -func (m *LightClientAttackEvidence) GetTotalVotingPower() int64 { - if m != nil { - return m.TotalVotingPower - } - return 0 -} - -func (m *LightClientAttackEvidence) GetTimestamp() time.Time { - if m != nil { - return m.Timestamp - } - return time.Time{} -} - -type EvidenceList struct { - Evidence []Evidence `protobuf:"bytes,1,rep,name=evidence,proto3" json:"evidence"` -} - -func (m *EvidenceList) Reset() { *m = EvidenceList{} } -func (m *EvidenceList) String() string { return proto.CompactTextString(m) } -func (*EvidenceList) ProtoMessage() {} -func (*EvidenceList) Descriptor() ([]byte, []int) { - return fileDescriptor_6825fabc78e0a168, []int{3} -} -func (m *EvidenceList) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *EvidenceList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_EvidenceList.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 *EvidenceList) XXX_Merge(src proto.Message) { - xxx_messageInfo_EvidenceList.Merge(m, src) -} -func (m *EvidenceList) XXX_Size() int { - return m.Size() -} -func (m *EvidenceList) XXX_DiscardUnknown() { - xxx_messageInfo_EvidenceList.DiscardUnknown(m) -} - -var xxx_messageInfo_EvidenceList proto.InternalMessageInfo - -func (m *EvidenceList) GetEvidence() []Evidence { - if m != nil { - return m.Evidence - } - return nil -} - -func init() { - proto.RegisterType((*Evidence)(nil), "tendermint.types.Evidence") - proto.RegisterType((*DuplicateVoteEvidence)(nil), "tendermint.types.DuplicateVoteEvidence") - proto.RegisterType((*LightClientAttackEvidence)(nil), "tendermint.types.LightClientAttackEvidence") - proto.RegisterType((*EvidenceList)(nil), "tendermint.types.EvidenceList") -} - -func init() { proto.RegisterFile("tendermint/types/evidence.proto", fileDescriptor_6825fabc78e0a168) } - -var fileDescriptor_6825fabc78e0a168 = []byte{ - // 532 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0xcf, 0x6e, 0xd3, 0x40, - 0x10, 0xc6, 0xed, 0x3a, 0xa9, 0xc2, 0xb6, 0x40, 0x58, 0x5a, 0x48, 0x43, 0xe4, 0x44, 0xe1, 0xd0, - 0x48, 0x80, 0x2d, 0x95, 0x03, 0x17, 0x2e, 0x35, 0x20, 0x15, 0x29, 0x42, 0x60, 0xa1, 0x1e, 0xb8, - 0x58, 0x6b, 0x7b, 0xeb, 0xac, 0x6a, 0xef, 0x5a, 0xf1, 0x24, 0xa8, 0x3c, 0x45, 0x1e, 0xab, 0x17, - 0xa4, 0x1e, 0x39, 0x01, 0x4a, 0x78, 0x10, 0xe4, 0xf5, 0x9f, 0x44, 0x75, 0xcc, 0x89, 0x4b, 0xe4, - 0xcc, 0xfc, 0xbe, 0x9d, 0x99, 0xcf, 0xb3, 0x46, 0x7d, 0xa0, 0xdc, 0xa7, 0xd3, 0x88, 0x71, 0x30, - 0xe1, 0x2a, 0xa6, 0x89, 0x49, 0xe7, 0xcc, 0xa7, 0xdc, 0xa3, 0x46, 0x3c, 0x15, 0x20, 0x70, 0x7b, - 0x0d, 0x18, 0x12, 0xe8, 0x1e, 0x04, 0x22, 0x10, 0x32, 0x69, 0xa6, 0x4f, 0x19, 0xd7, 0xed, 0x07, - 0x42, 0x04, 0x21, 0x35, 0xe5, 0x3f, 0x77, 0x76, 0x61, 0x02, 0x8b, 0x68, 0x02, 0x24, 0x8a, 0x73, - 0xa0, 0x57, 0xa9, 0x24, 0x7f, 0xf3, 0xec, 0xa0, 0x92, 0x9d, 0x93, 0x90, 0xf9, 0x04, 0xc4, 0x34, - 0x23, 0x86, 0x7f, 0x54, 0xd4, 0x7a, 0x97, 0xf7, 0x86, 0x09, 0x7a, 0xec, 0xcf, 0xe2, 0x90, 0x79, - 0x04, 0xa8, 0x33, 0x17, 0x40, 0x9d, 0xa2, 0xed, 0x8e, 0x3a, 0x50, 0x47, 0x7b, 0x27, 0xc7, 0xc6, - 0xed, 0xbe, 0x8d, 0xb7, 0x85, 0xe0, 0x5c, 0x00, 0x2d, 0x4e, 0x3a, 0x53, 0xec, 0x43, 0x7f, 0x5b, - 0x02, 0x73, 0xd4, 0x0b, 0x59, 0x30, 0x01, 0xc7, 0x0b, 0x19, 0xe5, 0xe0, 0x10, 0x00, 0xe2, 0x5d, - 0xae, 0xeb, 0xec, 0xc8, 0x3a, 0xcf, 0xaa, 0x75, 0xc6, 0xa9, 0xea, 0x8d, 0x14, 0x9d, 0x4a, 0xcd, - 0x46, 0xad, 0xa3, 0xb0, 0x2e, 0x69, 0x35, 0x91, 0x96, 0xcc, 0xa2, 0xe1, 0x62, 0x07, 0x1d, 0x6e, - 0xed, 0x14, 0xbf, 0x40, 0xbb, 0x72, 0x52, 0x92, 0x8f, 0xf8, 0xa8, 0x5a, 0x3a, 0xe5, 0xed, 0x66, - 0x4a, 0x9d, 0x96, 0xb8, 0x9b, 0x77, 0xfa, 0x4f, 0xdc, 0xc2, 0xcf, 0x11, 0x06, 0x01, 0x24, 0x4c, - 0xdd, 0x64, 0x3c, 0x70, 0x62, 0xf1, 0x95, 0x4e, 0x3b, 0xda, 0x40, 0x1d, 0x69, 0x76, 0x5b, 0x66, - 0xce, 0x65, 0xe2, 0x63, 0x1a, 0xc7, 0xc7, 0xe8, 0x7e, 0xf9, 0x7e, 0x72, 0xb4, 0x21, 0xd1, 0x7b, - 0x65, 0x38, 0x03, 0x2d, 0x74, 0xa7, 0x5c, 0x84, 0x4e, 0x53, 0x36, 0xd2, 0x35, 0xb2, 0x55, 0x31, - 0x8a, 0x55, 0x31, 0x3e, 0x17, 0x84, 0xd5, 0xba, 0xfe, 0xd9, 0x57, 0x16, 0xbf, 0xfa, 0xaa, 0xbd, - 0x96, 0x0d, 0xbf, 0xef, 0xa0, 0xa3, 0x5a, 0x53, 0xf1, 0x7b, 0xf4, 0xc0, 0x13, 0xfc, 0x22, 0x64, - 0x9e, 0xec, 0xdb, 0x0d, 0x85, 0x77, 0x99, 0x3b, 0xd4, 0xab, 0x79, 0x39, 0x56, 0xca, 0xd8, 0xed, - 0x0d, 0x99, 0x8c, 0xe0, 0xa7, 0xe8, 0xae, 0x27, 0xa2, 0x48, 0x70, 0x67, 0x42, 0x53, 0x4e, 0x3a, - 0xa7, 0xd9, 0xfb, 0x59, 0xf0, 0x4c, 0xc6, 0xf0, 0x07, 0x74, 0xe0, 0x5e, 0x7d, 0x23, 0x1c, 0x18, - 0xa7, 0x4e, 0x39, 0x6d, 0xd2, 0xd1, 0x06, 0xda, 0x68, 0xef, 0xe4, 0xc9, 0x16, 0x97, 0x0b, 0xc6, - 0x7e, 0x58, 0x0a, 0xcb, 0x58, 0x52, 0x63, 0x7c, 0xa3, 0xc6, 0xf8, 0xff, 0xe1, 0xe7, 0x18, 0xed, - 0x17, 0xee, 0x8d, 0x59, 0x02, 0xf8, 0x35, 0x6a, 0x6d, 0xdc, 0x1e, 0x4d, 0x1e, 0x59, 0x99, 0xa2, - 0xdc, 0xd3, 0x46, 0x7a, 0xa4, 0x5d, 0x2a, 0xac, 0x4f, 0xd7, 0x4b, 0x5d, 0xbd, 0x59, 0xea, 0xea, - 0xef, 0xa5, 0xae, 0x2e, 0x56, 0xba, 0x72, 0xb3, 0xd2, 0x95, 0x1f, 0x2b, 0x5d, 0xf9, 0xf2, 0x2a, - 0x60, 0x30, 0x99, 0xb9, 0x86, 0x27, 0x22, 0x73, 0xf3, 0x7a, 0xaf, 0x1f, 0xb3, 0xaf, 0xc8, 0xed, - 0xab, 0xef, 0xee, 0xca, 0xf8, 0xcb, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa6, 0x21, 0x16, 0x68, - 0x9d, 0x04, 0x00, 0x00, -} - -func (m *Evidence) 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 *Evidence) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Evidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Sum != nil { - { - size := m.Sum.Size() - i -= size - if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - } - } - return len(dAtA) - i, nil -} - -func (m *Evidence_DuplicateVoteEvidence) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Evidence_DuplicateVoteEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.DuplicateVoteEvidence != nil { - { - size, err := m.DuplicateVoteEvidence.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintEvidence(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} -func (m *Evidence_LightClientAttackEvidence) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Evidence_LightClientAttackEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.LightClientAttackEvidence != nil { - { - size, err := m.LightClientAttackEvidence.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintEvidence(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - return len(dAtA) - i, nil -} -func (m *DuplicateVoteEvidence) 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 *DuplicateVoteEvidence) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *DuplicateVoteEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - n3, err3 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) - if err3 != nil { - return 0, err3 - } - i -= n3 - i = encodeVarintEvidence(dAtA, i, uint64(n3)) - i-- - dAtA[i] = 0x2a - if m.ValidatorPower != 0 { - i = encodeVarintEvidence(dAtA, i, uint64(m.ValidatorPower)) - i-- - dAtA[i] = 0x20 - } - if m.TotalVotingPower != 0 { - i = encodeVarintEvidence(dAtA, i, uint64(m.TotalVotingPower)) - i-- - dAtA[i] = 0x18 - } - if m.VoteB != nil { - { - size, err := m.VoteB.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintEvidence(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - if m.VoteA != nil { - { - size, err := m.VoteA.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintEvidence(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *LightClientAttackEvidence) 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 *LightClientAttackEvidence) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *LightClientAttackEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - n6, err6 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) - if err6 != nil { - return 0, err6 - } - i -= n6 - i = encodeVarintEvidence(dAtA, i, uint64(n6)) - i-- - dAtA[i] = 0x2a - if m.TotalVotingPower != 0 { - i = encodeVarintEvidence(dAtA, i, uint64(m.TotalVotingPower)) - i-- - dAtA[i] = 0x20 - } - if len(m.ByzantineValidators) > 0 { - for iNdEx := len(m.ByzantineValidators) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.ByzantineValidators[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintEvidence(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - } - if m.CommonHeight != 0 { - i = encodeVarintEvidence(dAtA, i, uint64(m.CommonHeight)) - i-- - dAtA[i] = 0x10 - } - if m.ConflictingBlock != nil { - { - size, err := m.ConflictingBlock.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintEvidence(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *EvidenceList) 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 *EvidenceList) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *EvidenceList) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Evidence) > 0 { - for iNdEx := len(m.Evidence) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Evidence[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintEvidence(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func encodeVarintEvidence(dAtA []byte, offset int, v uint64) int { - offset -= sovEvidence(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *Evidence) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Sum != nil { - n += m.Sum.Size() - } - return n -} - -func (m *Evidence_DuplicateVoteEvidence) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.DuplicateVoteEvidence != nil { - l = m.DuplicateVoteEvidence.Size() - n += 1 + l + sovEvidence(uint64(l)) - } - return n -} -func (m *Evidence_LightClientAttackEvidence) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.LightClientAttackEvidence != nil { - l = m.LightClientAttackEvidence.Size() - n += 1 + l + sovEvidence(uint64(l)) - } - return n -} -func (m *DuplicateVoteEvidence) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.VoteA != nil { - l = m.VoteA.Size() - n += 1 + l + sovEvidence(uint64(l)) - } - if m.VoteB != nil { - l = m.VoteB.Size() - n += 1 + l + sovEvidence(uint64(l)) - } - if m.TotalVotingPower != 0 { - n += 1 + sovEvidence(uint64(m.TotalVotingPower)) - } - if m.ValidatorPower != 0 { - n += 1 + sovEvidence(uint64(m.ValidatorPower)) - } - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) - n += 1 + l + sovEvidence(uint64(l)) - return n -} - -func (m *LightClientAttackEvidence) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.ConflictingBlock != nil { - l = m.ConflictingBlock.Size() - n += 1 + l + sovEvidence(uint64(l)) - } - if m.CommonHeight != 0 { - n += 1 + sovEvidence(uint64(m.CommonHeight)) - } - if len(m.ByzantineValidators) > 0 { - for _, e := range m.ByzantineValidators { - l = e.Size() - n += 1 + l + sovEvidence(uint64(l)) - } - } - if m.TotalVotingPower != 0 { - n += 1 + sovEvidence(uint64(m.TotalVotingPower)) - } - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) - n += 1 + l + sovEvidence(uint64(l)) - return n -} - -func (m *EvidenceList) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Evidence) > 0 { - for _, e := range m.Evidence { - l = e.Size() - n += 1 + l + sovEvidence(uint64(l)) - } - } - return n -} - -func sovEvidence(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozEvidence(x uint64) (n int) { - return sovEvidence(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *Evidence) 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 ErrIntOverflowEvidence - } - 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: Evidence: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Evidence: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DuplicateVoteEvidence", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvidence - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthEvidence - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthEvidence - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &DuplicateVoteEvidence{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Sum = &Evidence_DuplicateVoteEvidence{v} - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LightClientAttackEvidence", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvidence - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthEvidence - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthEvidence - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &LightClientAttackEvidence{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Sum = &Evidence_LightClientAttackEvidence{v} - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipEvidence(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthEvidence - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *DuplicateVoteEvidence) 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 ErrIntOverflowEvidence - } - 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: DuplicateVoteEvidence: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: DuplicateVoteEvidence: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field VoteA", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvidence - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthEvidence - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthEvidence - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.VoteA == nil { - m.VoteA = &Vote{} - } - if err := m.VoteA.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field VoteB", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvidence - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthEvidence - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthEvidence - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.VoteB == nil { - m.VoteB = &Vote{} - } - if err := m.VoteB.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalVotingPower", wireType) - } - m.TotalVotingPower = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvidence - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalVotingPower |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ValidatorPower", wireType) - } - m.ValidatorPower = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvidence - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ValidatorPower |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvidence - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthEvidence - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthEvidence - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipEvidence(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthEvidence - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *LightClientAttackEvidence) 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 ErrIntOverflowEvidence - } - 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: LightClientAttackEvidence: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: LightClientAttackEvidence: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ConflictingBlock", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvidence - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthEvidence - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthEvidence - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.ConflictingBlock == nil { - m.ConflictingBlock = &LightBlock{} - } - if err := m.ConflictingBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field CommonHeight", wireType) - } - m.CommonHeight = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvidence - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.CommonHeight |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ByzantineValidators", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvidence - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthEvidence - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthEvidence - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ByzantineValidators = append(m.ByzantineValidators, &Validator{}) - if err := m.ByzantineValidators[len(m.ByzantineValidators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalVotingPower", wireType) - } - m.TotalVotingPower = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvidence - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalVotingPower |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvidence - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthEvidence - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthEvidence - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipEvidence(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthEvidence - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *EvidenceList) 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 ErrIntOverflowEvidence - } - 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: EvidenceList: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: EvidenceList: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvidence - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthEvidence - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthEvidence - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Evidence = append(m.Evidence, Evidence{}) - if err := m.Evidence[len(m.Evidence)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipEvidence(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthEvidence - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipEvidence(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowEvidence - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowEvidence - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowEvidence - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthEvidence - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupEvidence - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthEvidence - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthEvidence = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowEvidence = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupEvidence = fmt.Errorf("proto: unexpected end of group") -) diff --git a/proto/tendermint/types/evidence.proto b/proto/tendermint/types/evidence.proto deleted file mode 100644 index 451b8dca3c..0000000000 --- a/proto/tendermint/types/evidence.proto +++ /dev/null @@ -1,38 +0,0 @@ -syntax = "proto3"; -package tendermint.types; - -option go_package = "github.com/tendermint/tendermint/proto/tendermint/types"; - -import "gogoproto/gogo.proto"; -import "google/protobuf/timestamp.proto"; -import "tendermint/types/types.proto"; -import "tendermint/types/validator.proto"; - -message Evidence { - oneof sum { - DuplicateVoteEvidence duplicate_vote_evidence = 1; - LightClientAttackEvidence light_client_attack_evidence = 2; - } -} - -// DuplicateVoteEvidence contains evidence of a validator signed two conflicting votes. -message DuplicateVoteEvidence { - tendermint.types.Vote vote_a = 1; - tendermint.types.Vote vote_b = 2; - int64 total_voting_power = 3; - int64 validator_power = 4; - google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; -} - -// LightClientAttackEvidence contains evidence of a set of validators attempting to mislead a light client. -message LightClientAttackEvidence { - tendermint.types.LightBlock conflicting_block = 1; - int64 common_height = 2; - repeated tendermint.types.Validator byzantine_validators = 3; - int64 total_voting_power = 4; - google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; -} - -message EvidenceList { - repeated Evidence evidence = 1 [(gogoproto.nullable) = false]; -} diff --git a/proto/tendermint/types/types.pb.go b/proto/tendermint/types/types.pb.go index 73090558ea..7d34b8a5ce 100644 --- a/proto/tendermint/types/types.pb.go +++ b/proto/tendermint/types/types.pb.go @@ -421,6 +421,11 @@ type Data struct { // NOTE: not all txs here are valid. We're just agreeing on the order first. // This means that block.AppHash does not include these txs. Txs [][]byte `protobuf:"bytes,1,rep,name=txs,proto3" json:"txs,omitempty"` + // field number 2 is reserved for intermediate state roots + Evidence EvidenceList `protobuf:"bytes,3,opt,name=evidence,proto3" json:"evidence"` + Messages Messages `protobuf:"bytes,4,opt,name=messages,proto3" json:"messages"` + OriginalSquareSize uint64 `protobuf:"varint,5,opt,name=original_square_size,json=originalSquareSize,proto3" json:"original_square_size,omitempty"` + Hash []byte `protobuf:"bytes,6,opt,name=hash,proto3" json:"hash,omitempty"` } func (m *Data) Reset() { *m = Data{} } @@ -463,6 +468,414 @@ func (m *Data) GetTxs() [][]byte { return nil } +func (m *Data) GetEvidence() EvidenceList { + if m != nil { + return m.Evidence + } + return EvidenceList{} +} + +func (m *Data) GetMessages() Messages { + if m != nil { + return m.Messages + } + return Messages{} +} + +func (m *Data) GetOriginalSquareSize() uint64 { + if m != nil { + return m.OriginalSquareSize + } + return 0 +} + +func (m *Data) GetHash() []byte { + if m != nil { + return m.Hash + } + return nil +} + +// DuplicateVoteEvidence contains evidence of a validator signed two conflicting votes. +type DuplicateVoteEvidence struct { + VoteA *Vote `protobuf:"bytes,1,opt,name=vote_a,json=voteA,proto3" json:"vote_a,omitempty"` + VoteB *Vote `protobuf:"bytes,2,opt,name=vote_b,json=voteB,proto3" json:"vote_b,omitempty"` + TotalVotingPower int64 `protobuf:"varint,3,opt,name=total_voting_power,json=totalVotingPower,proto3" json:"total_voting_power,omitempty"` + ValidatorPower int64 `protobuf:"varint,4,opt,name=validator_power,json=validatorPower,proto3" json:"validator_power,omitempty"` + Timestamp time.Time `protobuf:"bytes,5,opt,name=timestamp,proto3,stdtime" json:"timestamp"` +} + +func (m *DuplicateVoteEvidence) Reset() { *m = DuplicateVoteEvidence{} } +func (m *DuplicateVoteEvidence) String() string { return proto.CompactTextString(m) } +func (*DuplicateVoteEvidence) ProtoMessage() {} +func (*DuplicateVoteEvidence) Descriptor() ([]byte, []int) { + return fileDescriptor_d3a6e55e2345de56, []int{5} +} +func (m *DuplicateVoteEvidence) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DuplicateVoteEvidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DuplicateVoteEvidence.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 *DuplicateVoteEvidence) XXX_Merge(src proto.Message) { + xxx_messageInfo_DuplicateVoteEvidence.Merge(m, src) +} +func (m *DuplicateVoteEvidence) XXX_Size() int { + return m.Size() +} +func (m *DuplicateVoteEvidence) XXX_DiscardUnknown() { + xxx_messageInfo_DuplicateVoteEvidence.DiscardUnknown(m) +} + +var xxx_messageInfo_DuplicateVoteEvidence proto.InternalMessageInfo + +func (m *DuplicateVoteEvidence) GetVoteA() *Vote { + if m != nil { + return m.VoteA + } + return nil +} + +func (m *DuplicateVoteEvidence) GetVoteB() *Vote { + if m != nil { + return m.VoteB + } + return nil +} + +func (m *DuplicateVoteEvidence) GetTotalVotingPower() int64 { + if m != nil { + return m.TotalVotingPower + } + return 0 +} + +func (m *DuplicateVoteEvidence) GetValidatorPower() int64 { + if m != nil { + return m.ValidatorPower + } + return 0 +} + +func (m *DuplicateVoteEvidence) GetTimestamp() time.Time { + if m != nil { + return m.Timestamp + } + return time.Time{} +} + +// LightClientAttackEvidence contains evidence of a set of validators attempting to mislead a light client. +type LightClientAttackEvidence struct { + ConflictingBlock *LightBlock `protobuf:"bytes,1,opt,name=conflicting_block,json=conflictingBlock,proto3" json:"conflicting_block,omitempty"` + CommonHeight int64 `protobuf:"varint,2,opt,name=common_height,json=commonHeight,proto3" json:"common_height,omitempty"` + ByzantineValidators []*Validator `protobuf:"bytes,3,rep,name=byzantine_validators,json=byzantineValidators,proto3" json:"byzantine_validators,omitempty"` + TotalVotingPower int64 `protobuf:"varint,4,opt,name=total_voting_power,json=totalVotingPower,proto3" json:"total_voting_power,omitempty"` + Timestamp time.Time `protobuf:"bytes,5,opt,name=timestamp,proto3,stdtime" json:"timestamp"` +} + +func (m *LightClientAttackEvidence) Reset() { *m = LightClientAttackEvidence{} } +func (m *LightClientAttackEvidence) String() string { return proto.CompactTextString(m) } +func (*LightClientAttackEvidence) ProtoMessage() {} +func (*LightClientAttackEvidence) Descriptor() ([]byte, []int) { + return fileDescriptor_d3a6e55e2345de56, []int{6} +} +func (m *LightClientAttackEvidence) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *LightClientAttackEvidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_LightClientAttackEvidence.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 *LightClientAttackEvidence) XXX_Merge(src proto.Message) { + xxx_messageInfo_LightClientAttackEvidence.Merge(m, src) +} +func (m *LightClientAttackEvidence) XXX_Size() int { + return m.Size() +} +func (m *LightClientAttackEvidence) XXX_DiscardUnknown() { + xxx_messageInfo_LightClientAttackEvidence.DiscardUnknown(m) +} + +var xxx_messageInfo_LightClientAttackEvidence proto.InternalMessageInfo + +func (m *LightClientAttackEvidence) GetConflictingBlock() *LightBlock { + if m != nil { + return m.ConflictingBlock + } + return nil +} + +func (m *LightClientAttackEvidence) GetCommonHeight() int64 { + if m != nil { + return m.CommonHeight + } + return 0 +} + +func (m *LightClientAttackEvidence) GetByzantineValidators() []*Validator { + if m != nil { + return m.ByzantineValidators + } + return nil +} + +func (m *LightClientAttackEvidence) GetTotalVotingPower() int64 { + if m != nil { + return m.TotalVotingPower + } + return 0 +} + +func (m *LightClientAttackEvidence) GetTimestamp() time.Time { + if m != nil { + return m.Timestamp + } + return time.Time{} +} + +type Evidence struct { + // Types that are valid to be assigned to Sum: + // *Evidence_DuplicateVoteEvidence + // *Evidence_LightClientAttackEvidence + Sum isEvidence_Sum `protobuf_oneof:"sum"` +} + +func (m *Evidence) Reset() { *m = Evidence{} } +func (m *Evidence) String() string { return proto.CompactTextString(m) } +func (*Evidence) ProtoMessage() {} +func (*Evidence) Descriptor() ([]byte, []int) { + return fileDescriptor_d3a6e55e2345de56, []int{7} +} +func (m *Evidence) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Evidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Evidence.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 *Evidence) XXX_Merge(src proto.Message) { + xxx_messageInfo_Evidence.Merge(m, src) +} +func (m *Evidence) XXX_Size() int { + return m.Size() +} +func (m *Evidence) XXX_DiscardUnknown() { + xxx_messageInfo_Evidence.DiscardUnknown(m) +} + +var xxx_messageInfo_Evidence proto.InternalMessageInfo + +type isEvidence_Sum interface { + isEvidence_Sum() + MarshalTo([]byte) (int, error) + Size() int +} + +type Evidence_DuplicateVoteEvidence struct { + DuplicateVoteEvidence *DuplicateVoteEvidence `protobuf:"bytes,1,opt,name=duplicate_vote_evidence,json=duplicateVoteEvidence,proto3,oneof" json:"duplicate_vote_evidence,omitempty"` +} +type Evidence_LightClientAttackEvidence struct { + LightClientAttackEvidence *LightClientAttackEvidence `protobuf:"bytes,2,opt,name=light_client_attack_evidence,json=lightClientAttackEvidence,proto3,oneof" json:"light_client_attack_evidence,omitempty"` +} + +func (*Evidence_DuplicateVoteEvidence) isEvidence_Sum() {} +func (*Evidence_LightClientAttackEvidence) isEvidence_Sum() {} + +func (m *Evidence) GetSum() isEvidence_Sum { + if m != nil { + return m.Sum + } + return nil +} + +func (m *Evidence) GetDuplicateVoteEvidence() *DuplicateVoteEvidence { + if x, ok := m.GetSum().(*Evidence_DuplicateVoteEvidence); ok { + return x.DuplicateVoteEvidence + } + return nil +} + +func (m *Evidence) GetLightClientAttackEvidence() *LightClientAttackEvidence { + if x, ok := m.GetSum().(*Evidence_LightClientAttackEvidence); ok { + return x.LightClientAttackEvidence + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*Evidence) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*Evidence_DuplicateVoteEvidence)(nil), + (*Evidence_LightClientAttackEvidence)(nil), + } +} + +// EvidenceData contains any evidence of malicious wrong-doing by validators +type EvidenceList struct { + Evidence []Evidence `protobuf:"bytes,1,rep,name=evidence,proto3" json:"evidence"` +} + +func (m *EvidenceList) Reset() { *m = EvidenceList{} } +func (m *EvidenceList) String() string { return proto.CompactTextString(m) } +func (*EvidenceList) ProtoMessage() {} +func (*EvidenceList) Descriptor() ([]byte, []int) { + return fileDescriptor_d3a6e55e2345de56, []int{8} +} +func (m *EvidenceList) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EvidenceList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EvidenceList.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 *EvidenceList) XXX_Merge(src proto.Message) { + xxx_messageInfo_EvidenceList.Merge(m, src) +} +func (m *EvidenceList) XXX_Size() int { + return m.Size() +} +func (m *EvidenceList) XXX_DiscardUnknown() { + xxx_messageInfo_EvidenceList.DiscardUnknown(m) +} + +var xxx_messageInfo_EvidenceList proto.InternalMessageInfo + +func (m *EvidenceList) GetEvidence() []Evidence { + if m != nil { + return m.Evidence + } + return nil +} + +type Messages struct { + MessagesList []*Message `protobuf:"bytes,1,rep,name=messages_list,json=messagesList,proto3" json:"messages_list,omitempty"` +} + +func (m *Messages) Reset() { *m = Messages{} } +func (m *Messages) String() string { return proto.CompactTextString(m) } +func (*Messages) ProtoMessage() {} +func (*Messages) Descriptor() ([]byte, []int) { + return fileDescriptor_d3a6e55e2345de56, []int{9} +} +func (m *Messages) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Messages) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Messages.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 *Messages) XXX_Merge(src proto.Message) { + xxx_messageInfo_Messages.Merge(m, src) +} +func (m *Messages) XXX_Size() int { + return m.Size() +} +func (m *Messages) XXX_DiscardUnknown() { + xxx_messageInfo_Messages.DiscardUnknown(m) +} + +var xxx_messageInfo_Messages proto.InternalMessageInfo + +func (m *Messages) GetMessagesList() []*Message { + if m != nil { + return m.MessagesList + } + return nil +} + +type Message struct { + NamespaceId []byte `protobuf:"bytes,1,opt,name=namespace_id,json=namespaceId,proto3" json:"namespace_id,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *Message) Reset() { *m = Message{} } +func (m *Message) String() string { return proto.CompactTextString(m) } +func (*Message) ProtoMessage() {} +func (*Message) Descriptor() ([]byte, []int) { + return fileDescriptor_d3a6e55e2345de56, []int{10} +} +func (m *Message) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Message.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 *Message) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message.Merge(m, src) +} +func (m *Message) XXX_Size() int { + return m.Size() +} +func (m *Message) XXX_DiscardUnknown() { + xxx_messageInfo_Message.DiscardUnknown(m) +} + +var xxx_messageInfo_Message proto.InternalMessageInfo + +func (m *Message) GetNamespaceId() []byte { + if m != nil { + return m.NamespaceId + } + return nil +} + +func (m *Message) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + // Vote represents a prevote, precommit, or commit vote from validators for // consensus. type Vote struct { @@ -480,7 +893,7 @@ func (m *Vote) Reset() { *m = Vote{} } func (m *Vote) String() string { return proto.CompactTextString(m) } func (*Vote) ProtoMessage() {} func (*Vote) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{5} + return fileDescriptor_d3a6e55e2345de56, []int{11} } func (m *Vote) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -577,7 +990,7 @@ func (m *Commit) Reset() { *m = Commit{} } func (m *Commit) String() string { return proto.CompactTextString(m) } func (*Commit) ProtoMessage() {} func (*Commit) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{6} + return fileDescriptor_d3a6e55e2345de56, []int{12} } func (m *Commit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -646,7 +1059,7 @@ func (m *CommitSig) Reset() { *m = CommitSig{} } func (m *CommitSig) String() string { return proto.CompactTextString(m) } func (*CommitSig) ProtoMessage() {} func (*CommitSig) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{7} + return fileDescriptor_d3a6e55e2345de56, []int{13} } func (m *CommitSig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -717,7 +1130,7 @@ func (m *Proposal) Reset() { *m = Proposal{} } func (m *Proposal) String() string { return proto.CompactTextString(m) } func (*Proposal) ProtoMessage() {} func (*Proposal) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{8} + return fileDescriptor_d3a6e55e2345de56, []int{14} } func (m *Proposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -804,7 +1217,7 @@ func (m *SignedHeader) Reset() { *m = SignedHeader{} } func (m *SignedHeader) String() string { return proto.CompactTextString(m) } func (*SignedHeader) ProtoMessage() {} func (*SignedHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{9} + return fileDescriptor_d3a6e55e2345de56, []int{15} } func (m *SignedHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -856,7 +1269,7 @@ func (m *LightBlock) Reset() { *m = LightBlock{} } func (m *LightBlock) String() string { return proto.CompactTextString(m) } func (*LightBlock) ProtoMessage() {} func (*LightBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{10} + return fileDescriptor_d3a6e55e2345de56, []int{16} } func (m *LightBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -910,7 +1323,7 @@ func (m *BlockMeta) Reset() { *m = BlockMeta{} } func (m *BlockMeta) String() string { return proto.CompactTextString(m) } func (*BlockMeta) ProtoMessage() {} func (*BlockMeta) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{11} + return fileDescriptor_d3a6e55e2345de56, []int{17} } func (m *BlockMeta) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -978,7 +1391,7 @@ func (m *TxProof) Reset() { *m = TxProof{} } func (m *TxProof) String() string { return proto.CompactTextString(m) } func (*TxProof) ProtoMessage() {} func (*TxProof) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{12} + return fileDescriptor_d3a6e55e2345de56, []int{18} } func (m *TxProof) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1036,6 +1449,12 @@ func init() { proto.RegisterType((*BlockID)(nil), "tendermint.types.BlockID") proto.RegisterType((*Header)(nil), "tendermint.types.Header") proto.RegisterType((*Data)(nil), "tendermint.types.Data") + proto.RegisterType((*DuplicateVoteEvidence)(nil), "tendermint.types.DuplicateVoteEvidence") + proto.RegisterType((*LightClientAttackEvidence)(nil), "tendermint.types.LightClientAttackEvidence") + proto.RegisterType((*Evidence)(nil), "tendermint.types.Evidence") + proto.RegisterType((*EvidenceList)(nil), "tendermint.types.EvidenceList") + proto.RegisterType((*Messages)(nil), "tendermint.types.Messages") + proto.RegisterType((*Message)(nil), "tendermint.types.Message") proto.RegisterType((*Vote)(nil), "tendermint.types.Vote") proto.RegisterType((*Commit)(nil), "tendermint.types.Commit") proto.RegisterType((*CommitSig)(nil), "tendermint.types.CommitSig") @@ -1049,90 +1468,114 @@ func init() { func init() { proto.RegisterFile("tendermint/types/types.proto", fileDescriptor_d3a6e55e2345de56) } var fileDescriptor_d3a6e55e2345de56 = []byte{ - // 1314 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0xda, 0x9b, 0xd8, 0x7e, 0xb6, 0x13, 0x67, 0x95, 0xb6, 0xae, 0xdb, 0x38, 0x2b, 0x23, - 0x20, 0x2d, 0x68, 0x53, 0x52, 0xc4, 0x9f, 0x03, 0x07, 0xdb, 0x49, 0x5b, 0xab, 0x89, 0x63, 0xd6, - 0x6e, 0x11, 0x5c, 0x56, 0x6b, 0xef, 0xd4, 0x5e, 0xba, 0xde, 0x59, 0xed, 0x8c, 0x43, 0xd2, 0x4f, - 0x80, 0x72, 0xea, 0x89, 0x5b, 0x4e, 0x70, 0xe0, 0xce, 0x17, 0x40, 0x9c, 0x7a, 0xec, 0x0d, 0x2e, - 0x14, 0x94, 0x4a, 0x88, 0x8f, 0x81, 0xe6, 0x8f, 0xd7, 0xeb, 0x38, 0x86, 0xaa, 0xaa, 0xb8, 0x58, - 0x3b, 0xef, 0xfd, 0xde, 0xcc, 0x7b, 0xbf, 0xf7, 0x9b, 0x3f, 0x86, 0xeb, 0x14, 0xf9, 0x0e, 0x0a, - 0x87, 0xae, 0x4f, 0xb7, 0xe8, 0x71, 0x80, 0x88, 0xf8, 0x35, 0x82, 0x10, 0x53, 0xac, 0x15, 0x26, - 0x5e, 0x83, 0xdb, 0x4b, 0x6b, 0x7d, 0xdc, 0xc7, 0xdc, 0xb9, 0xc5, 0xbe, 0x04, 0xae, 0xb4, 0xd1, - 0xc7, 0xb8, 0xef, 0xa1, 0x2d, 0x3e, 0xea, 0x8e, 0x1e, 0x6d, 0x51, 0x77, 0x88, 0x08, 0xb5, 0x87, - 0x81, 0x04, 0xac, 0xc7, 0x96, 0xe9, 0x85, 0xc7, 0x01, 0xc5, 0x0c, 0x8b, 0x1f, 0x49, 0x77, 0x39, - 0xe6, 0x3e, 0x44, 0x21, 0x71, 0xb1, 0x1f, 0xcf, 0xa3, 0xa4, 0xcf, 0x64, 0x79, 0x68, 0x7b, 0xae, - 0x63, 0x53, 0x1c, 0x0a, 0x44, 0xe5, 0x53, 0xc8, 0xb7, 0xec, 0x90, 0xb6, 0x11, 0xbd, 0x87, 0x6c, - 0x07, 0x85, 0xda, 0x1a, 0x2c, 0x52, 0x4c, 0x6d, 0xaf, 0xa8, 0xe8, 0xca, 0x66, 0xde, 0x14, 0x03, - 0x4d, 0x03, 0x75, 0x60, 0x93, 0x41, 0x31, 0xa1, 0x2b, 0x9b, 0x39, 0x93, 0x7f, 0x57, 0x06, 0xa0, - 0xb2, 0x50, 0x16, 0xe1, 0xfa, 0x0e, 0x3a, 0x1a, 0x47, 0xf0, 0x01, 0xb3, 0x76, 0x8f, 0x29, 0x22, - 0x32, 0x44, 0x0c, 0xb4, 0x0f, 0x61, 0x91, 0xe7, 0x5f, 0x4c, 0xea, 0xca, 0x66, 0x76, 0xbb, 0x68, - 0xc4, 0x88, 0x12, 0xf5, 0x19, 0x2d, 0xe6, 0xaf, 0xa9, 0xcf, 0x5e, 0x6c, 0x2c, 0x98, 0x02, 0x5c, - 0xf1, 0x20, 0x55, 0xf3, 0x70, 0xef, 0x71, 0x63, 0x27, 0x4a, 0x44, 0x99, 0x24, 0xa2, 0xed, 0xc3, - 0x4a, 0x60, 0x87, 0xd4, 0x22, 0x88, 0x5a, 0x03, 0x5e, 0x05, 0x5f, 0x34, 0xbb, 0xbd, 0x61, 0x9c, - 0xef, 0x83, 0x31, 0x55, 0xac, 0x5c, 0x25, 0x1f, 0xc4, 0x8d, 0x95, 0xbf, 0x54, 0x58, 0x92, 0x64, - 0x7c, 0x06, 0x29, 0x49, 0x2b, 0x5f, 0x30, 0xbb, 0xbd, 0x1e, 0x9f, 0x51, 0xba, 0x8c, 0x3a, 0xf6, - 0x09, 0xf2, 0xc9, 0x88, 0xc8, 0xf9, 0xc6, 0x31, 0xda, 0x3b, 0x90, 0xee, 0x0d, 0x6c, 0xd7, 0xb7, - 0x5c, 0x87, 0x67, 0x94, 0xa9, 0x65, 0xcf, 0x5e, 0x6c, 0xa4, 0xea, 0xcc, 0xd6, 0xd8, 0x31, 0x53, - 0xdc, 0xd9, 0x70, 0xb4, 0xcb, 0xb0, 0x34, 0x40, 0x6e, 0x7f, 0x40, 0x39, 0x2d, 0x49, 0x53, 0x8e, - 0xb4, 0x4f, 0x40, 0x65, 0x82, 0x28, 0xaa, 0x7c, 0xed, 0x92, 0x21, 0xd4, 0x62, 0x8c, 0xd5, 0x62, - 0x74, 0xc6, 0x6a, 0xa9, 0xa5, 0xd9, 0xc2, 0x4f, 0xff, 0xd8, 0x50, 0x4c, 0x1e, 0xa1, 0xd5, 0x21, - 0xef, 0xd9, 0x84, 0x5a, 0x5d, 0x46, 0x1b, 0x5b, 0x7e, 0x91, 0x4f, 0x71, 0x75, 0x96, 0x10, 0x49, - 0xac, 0x4c, 0x3d, 0xcb, 0xa2, 0x84, 0xc9, 0xd1, 0x36, 0xa1, 0xc0, 0x27, 0xe9, 0xe1, 0xe1, 0xd0, - 0xa5, 0x16, 0xe7, 0x7d, 0x89, 0xf3, 0xbe, 0xcc, 0xec, 0x75, 0x6e, 0xbe, 0xc7, 0x3a, 0x70, 0x0d, - 0x32, 0x8e, 0x4d, 0x6d, 0x01, 0x49, 0x71, 0x48, 0x9a, 0x19, 0xb8, 0xf3, 0x5d, 0x58, 0x89, 0x54, - 0x47, 0x04, 0x24, 0x2d, 0x66, 0x99, 0x98, 0x39, 0xf0, 0x16, 0xac, 0xf9, 0xe8, 0x88, 0x5a, 0xe7, - 0xd1, 0x19, 0x8e, 0xd6, 0x98, 0xef, 0xe1, 0x74, 0xc4, 0xdb, 0xb0, 0xdc, 0x1b, 0x93, 0x2f, 0xb0, - 0xc0, 0xb1, 0xf9, 0xc8, 0xca, 0x61, 0x57, 0x21, 0x6d, 0x07, 0x81, 0x00, 0x64, 0x39, 0x20, 0x65, - 0x07, 0x01, 0x77, 0xdd, 0x84, 0x55, 0x5e, 0x63, 0x88, 0xc8, 0xc8, 0xa3, 0x72, 0x92, 0x1c, 0xc7, - 0xac, 0x30, 0x87, 0x29, 0xec, 0x1c, 0xfb, 0x16, 0xe4, 0xd1, 0xa1, 0xeb, 0x20, 0xbf, 0x87, 0x04, - 0x2e, 0xcf, 0x71, 0xb9, 0xb1, 0x91, 0x83, 0x6e, 0x40, 0x21, 0x08, 0x71, 0x80, 0x09, 0x0a, 0x2d, - 0xdb, 0x71, 0x42, 0x44, 0x48, 0x71, 0x59, 0xcc, 0x37, 0xb6, 0x57, 0x85, 0xb9, 0x52, 0x04, 0x75, - 0xc7, 0xa6, 0xb6, 0x56, 0x80, 0x24, 0x3d, 0x22, 0x45, 0x45, 0x4f, 0x6e, 0xe6, 0x4c, 0xf6, 0x59, - 0xf9, 0x3b, 0x01, 0xea, 0x43, 0x4c, 0x91, 0x76, 0x1b, 0x54, 0xd6, 0x26, 0xae, 0xbe, 0xe5, 0x8b, - 0xf4, 0xdc, 0x76, 0xfb, 0x3e, 0x72, 0xf6, 0x49, 0xbf, 0x73, 0x1c, 0x20, 0x93, 0x83, 0x63, 0x72, - 0x4a, 0x4c, 0xc9, 0x69, 0x0d, 0x16, 0x43, 0x3c, 0xf2, 0x1d, 0xae, 0xb2, 0x45, 0x53, 0x0c, 0xb4, - 0x5d, 0x48, 0x47, 0x2a, 0x51, 0xff, 0x4b, 0x25, 0x2b, 0x4c, 0x25, 0x4c, 0xc3, 0xd2, 0x60, 0xa6, - 0xba, 0x52, 0x2c, 0x35, 0xc8, 0x44, 0x87, 0x97, 0x54, 0xdb, 0xab, 0x09, 0x76, 0x12, 0xa6, 0xbd, - 0x07, 0xab, 0x51, 0xef, 0x23, 0xf2, 0x84, 0xe2, 0x0a, 0x91, 0x43, 0xb2, 0x37, 0x25, 0x2b, 0x4b, - 0x1c, 0x40, 0x29, 0x5e, 0xd7, 0x44, 0x56, 0x0d, 0x7e, 0x12, 0x5d, 0x87, 0x0c, 0x71, 0xfb, 0xbe, - 0x4d, 0x47, 0x21, 0x92, 0xca, 0x9b, 0x18, 0x2a, 0x3f, 0x2b, 0xb0, 0x24, 0x94, 0x1c, 0xe3, 0x4d, - 0xb9, 0x98, 0xb7, 0xc4, 0x3c, 0xde, 0x92, 0xaf, 0xcf, 0x5b, 0x15, 0x20, 0x4a, 0x86, 0x14, 0x55, - 0x3d, 0xb9, 0x99, 0xdd, 0xbe, 0x36, 0x3b, 0x91, 0x48, 0xb1, 0xed, 0xf6, 0xe5, 0x46, 0x8d, 0x05, - 0x55, 0x7e, 0x57, 0x20, 0x13, 0xf9, 0xb5, 0x2a, 0xe4, 0xc7, 0x79, 0x59, 0x8f, 0x3c, 0xbb, 0x2f, - 0xb5, 0xb3, 0x3e, 0x37, 0xb9, 0x3b, 0x9e, 0xdd, 0x37, 0xb3, 0x32, 0x1f, 0x36, 0xb8, 0xb8, 0x0f, - 0x89, 0x39, 0x7d, 0x98, 0x6a, 0x7c, 0xf2, 0xf5, 0x1a, 0x3f, 0xd5, 0x22, 0xf5, 0x7c, 0x8b, 0x7e, - 0x4a, 0x40, 0xba, 0xc5, 0xf7, 0x8e, 0xed, 0xfd, 0x1f, 0x3b, 0xe2, 0x1a, 0x64, 0x02, 0xec, 0x59, - 0xc2, 0xa3, 0x72, 0x4f, 0x3a, 0xc0, 0x9e, 0x39, 0xd3, 0xf6, 0xc5, 0x37, 0xb4, 0x5d, 0x96, 0xde, - 0x00, 0x6b, 0xa9, 0xf3, 0xac, 0x85, 0x90, 0x13, 0x54, 0xc8, 0xbb, 0xec, 0x16, 0xe3, 0x80, 0x5f, - 0x8e, 0xca, 0xec, 0xdd, 0x2b, 0xd2, 0x16, 0x48, 0x53, 0xe2, 0x58, 0x84, 0x38, 0xfa, 0xe5, 0x75, - 0x5a, 0x9c, 0x27, 0x4b, 0x53, 0xe2, 0x2a, 0xdf, 0x29, 0x00, 0x7b, 0x8c, 0x59, 0x5e, 0x2f, 0xbb, - 0x85, 0x08, 0x4f, 0xc1, 0x9a, 0x5a, 0xb9, 0x3c, 0xaf, 0x69, 0x72, 0xfd, 0x1c, 0x89, 0xe7, 0x5d, - 0x87, 0xfc, 0x44, 0x8c, 0x04, 0x8d, 0x93, 0xb9, 0x60, 0x92, 0xe8, 0x72, 0x68, 0x23, 0x6a, 0xe6, - 0x0e, 0x63, 0xa3, 0xca, 0x2f, 0x0a, 0x64, 0x78, 0x4e, 0xfb, 0x88, 0xda, 0x53, 0x3d, 0x54, 0x5e, - 0xbf, 0x87, 0xeb, 0x00, 0x62, 0x1a, 0xe2, 0x3e, 0x41, 0x52, 0x59, 0x19, 0x6e, 0x69, 0xbb, 0x4f, - 0x90, 0xf6, 0x51, 0x44, 0x78, 0xf2, 0xdf, 0x09, 0x97, 0x5b, 0x7a, 0x4c, 0xfb, 0x15, 0x48, 0xf9, - 0xa3, 0xa1, 0xc5, 0xae, 0x04, 0x55, 0xa8, 0xd5, 0x1f, 0x0d, 0x3b, 0x47, 0xa4, 0xf2, 0x35, 0xa4, - 0x3a, 0x47, 0xfc, 0x79, 0xc4, 0x24, 0x1a, 0x62, 0x2c, 0xef, 0x64, 0xf1, 0x16, 0x4a, 0x33, 0x03, - 0xbf, 0x82, 0x34, 0x50, 0xd9, 0xe5, 0x3b, 0x7e, 0xac, 0xb1, 0x6f, 0xcd, 0x78, 0xc5, 0x87, 0x97, - 0x7c, 0x72, 0xdd, 0xfc, 0x55, 0x81, 0x6c, 0xec, 0x7c, 0xd0, 0x3e, 0x80, 0x4b, 0xb5, 0xbd, 0x83, - 0xfa, 0x7d, 0xab, 0xb1, 0x63, 0xdd, 0xd9, 0xab, 0xde, 0xb5, 0x1e, 0x34, 0xef, 0x37, 0x0f, 0xbe, - 0x68, 0x16, 0x16, 0x4a, 0x97, 0x4f, 0x4e, 0x75, 0x2d, 0x86, 0x7d, 0xe0, 0x3f, 0xf6, 0xf1, 0x37, - 0xbe, 0xb6, 0x05, 0x6b, 0xd3, 0x21, 0xd5, 0x5a, 0x7b, 0xb7, 0xd9, 0x29, 0x28, 0xa5, 0x4b, 0x27, - 0xa7, 0xfa, 0x6a, 0x2c, 0xa2, 0xda, 0x25, 0xc8, 0xa7, 0xb3, 0x01, 0xf5, 0x83, 0xfd, 0xfd, 0x46, - 0xa7, 0x90, 0x98, 0x09, 0x90, 0x07, 0xf6, 0x0d, 0x58, 0x9d, 0x0e, 0x68, 0x36, 0xf6, 0x0a, 0xc9, - 0x92, 0x76, 0x72, 0xaa, 0x2f, 0xc7, 0xd0, 0x4d, 0xd7, 0x2b, 0xa5, 0xbf, 0xfd, 0xbe, 0xbc, 0xf0, - 0xe3, 0x0f, 0x65, 0x85, 0x55, 0x96, 0x9f, 0x3a, 0x23, 0xb4, 0xf7, 0xe1, 0x4a, 0xbb, 0x71, 0xb7, - 0xb9, 0xbb, 0x63, 0xed, 0xb7, 0xef, 0x5a, 0x9d, 0x2f, 0x5b, 0xbb, 0xb1, 0xea, 0x56, 0x4e, 0x4e, - 0xf5, 0xac, 0x2c, 0x69, 0x1e, 0xba, 0x65, 0xee, 0x3e, 0x3c, 0xe8, 0xec, 0x16, 0x14, 0x81, 0x6e, - 0x85, 0xe8, 0x10, 0x53, 0xc4, 0xd1, 0xb7, 0xe0, 0xea, 0x05, 0xe8, 0xa8, 0xb0, 0xd5, 0x93, 0x53, - 0x3d, 0xdf, 0x0a, 0x91, 0xd8, 0x3f, 0x3c, 0xc2, 0x80, 0xe2, 0x6c, 0xc4, 0x41, 0xeb, 0xa0, 0x5d, - 0xdd, 0x2b, 0xe8, 0xa5, 0xc2, 0xc9, 0xa9, 0x9e, 0x1b, 0x1f, 0x86, 0x0c, 0x3f, 0xa9, 0xac, 0xf6, - 0xf9, 0xb3, 0xb3, 0xb2, 0xf2, 0xfc, 0xac, 0xac, 0xfc, 0x79, 0x56, 0x56, 0x9e, 0xbe, 0x2c, 0x2f, - 0x3c, 0x7f, 0x59, 0x5e, 0xf8, 0xed, 0x65, 0x79, 0xe1, 0xab, 0x8f, 0xfb, 0x2e, 0x1d, 0x8c, 0xba, - 0x46, 0x0f, 0x0f, 0xb7, 0xe2, 0x7f, 0x09, 0x26, 0x9f, 0xe2, 0xaf, 0xc9, 0xf9, 0xbf, 0x0b, 0xdd, - 0x25, 0x6e, 0xbf, 0xfd, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4c, 0x78, 0x43, 0xdf, 0xef, 0x0c, - 0x00, 0x00, + // 1710 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcd, 0x73, 0x1b, 0x49, + 0x15, 0xf7, 0x48, 0xb2, 0x3e, 0x9e, 0x24, 0x5b, 0x1e, 0x9c, 0x44, 0x56, 0x12, 0x59, 0x88, 0x82, + 0xf5, 0x7e, 0x20, 0x87, 0x2c, 0xc5, 0x47, 0x15, 0x50, 0x2b, 0xd9, 0xde, 0x58, 0xac, 0x2d, 0x8b, + 0x91, 0x36, 0x14, 0x5c, 0xa6, 0x5a, 0x9a, 0x8e, 0x34, 0x64, 0x34, 0x33, 0x4c, 0xb7, 0xbc, 0x76, + 0xfe, 0x02, 0xca, 0xa7, 0x9c, 0xb8, 0xf9, 0x04, 0x07, 0xee, 0xfc, 0x03, 0x14, 0xa7, 0xbd, 0x50, + 0xb5, 0x37, 0xb8, 0x10, 0xa8, 0x84, 0xa2, 0xf8, 0x33, 0xa8, 0x7e, 0xdd, 0x33, 0x1a, 0x59, 0x52, + 0x48, 0xa5, 0x52, 0x5c, 0x54, 0x33, 0xef, 0xfd, 0x5e, 0xf7, 0xeb, 0xdf, 0xfb, 0xea, 0x11, 0xdc, + 0xe3, 0xd4, 0xb5, 0x68, 0x30, 0xb1, 0x5d, 0xbe, 0xcf, 0x2f, 0x7d, 0xca, 0xe4, 0x6f, 0xc3, 0x0f, + 0x3c, 0xee, 0xe9, 0xa5, 0x99, 0xb6, 0x81, 0xf2, 0xca, 0xf6, 0xc8, 0x1b, 0x79, 0xa8, 0xdc, 0x17, + 0x4f, 0x12, 0x57, 0xd9, 0x1d, 0x79, 0xde, 0xc8, 0xa1, 0xfb, 0xf8, 0x36, 0x98, 0x3e, 0xd9, 0xe7, + 0xf6, 0x84, 0x32, 0x4e, 0x26, 0xbe, 0x02, 0xdc, 0x8f, 0x6d, 0x33, 0x0c, 0x2e, 0x7d, 0xee, 0x09, + 0xac, 0xf7, 0x44, 0xa9, 0xab, 0x31, 0xf5, 0x39, 0x0d, 0x98, 0xed, 0xb9, 0x71, 0x3f, 0x2a, 0xb5, + 0x05, 0x2f, 0xcf, 0x89, 0x63, 0x5b, 0x84, 0x7b, 0x81, 0x44, 0xd4, 0x7f, 0x08, 0xc5, 0x2e, 0x09, + 0x78, 0x8f, 0xf2, 0x63, 0x4a, 0x2c, 0x1a, 0xe8, 0xdb, 0xb0, 0xce, 0x3d, 0x4e, 0x9c, 0xb2, 0x56, + 0xd3, 0xf6, 0x8a, 0x86, 0x7c, 0xd1, 0x75, 0x48, 0x8d, 0x09, 0x1b, 0x97, 0x13, 0x35, 0x6d, 0xaf, + 0x60, 0xe0, 0x73, 0x7d, 0x0c, 0x29, 0x61, 0x2a, 0x2c, 0x6c, 0xd7, 0xa2, 0x17, 0xa1, 0x05, 0xbe, + 0x08, 0xe9, 0xe0, 0x92, 0x53, 0xa6, 0x4c, 0xe4, 0x8b, 0xfe, 0x5d, 0x58, 0x47, 0xff, 0xcb, 0xc9, + 0x9a, 0xb6, 0x97, 0x7f, 0x58, 0x6e, 0xc4, 0x88, 0x92, 0xe7, 0x6b, 0x74, 0x85, 0xbe, 0x95, 0xfa, + 0xf2, 0xc5, 0xee, 0x9a, 0x21, 0xc1, 0x75, 0x07, 0x32, 0x2d, 0xc7, 0x1b, 0x3e, 0x6d, 0x1f, 0x46, + 0x8e, 0x68, 0x33, 0x47, 0xf4, 0x53, 0xd8, 0xf4, 0x49, 0xc0, 0x4d, 0x46, 0xb9, 0x39, 0xc6, 0x53, + 0xe0, 0xa6, 0xf9, 0x87, 0xbb, 0x8d, 0x9b, 0x71, 0x68, 0xcc, 0x1d, 0x56, 0xed, 0x52, 0xf4, 0xe3, + 0xc2, 0xfa, 0xbf, 0x53, 0x90, 0x56, 0x64, 0xfc, 0x18, 0x32, 0x8a, 0x56, 0xdc, 0x30, 0xff, 0xf0, + 0x7e, 0x7c, 0x45, 0xa5, 0x6a, 0x1c, 0x78, 0x2e, 0xa3, 0x2e, 0x9b, 0x32, 0xb5, 0x5e, 0x68, 0xa3, + 0x7f, 0x0b, 0xb2, 0xc3, 0x31, 0xb1, 0x5d, 0xd3, 0xb6, 0xd0, 0xa3, 0x5c, 0x2b, 0xff, 0xf2, 0xc5, + 0x6e, 0xe6, 0x40, 0xc8, 0xda, 0x87, 0x46, 0x06, 0x95, 0x6d, 0x4b, 0xbf, 0x0d, 0xe9, 0x31, 0xb5, + 0x47, 0x63, 0x8e, 0xb4, 0x24, 0x0d, 0xf5, 0xa6, 0xff, 0x00, 0x52, 0x22, 0x21, 0xca, 0x29, 0xdc, + 0xbb, 0xd2, 0x90, 0xd9, 0xd2, 0x08, 0xb3, 0xa5, 0xd1, 0x0f, 0xb3, 0xa5, 0x95, 0x15, 0x1b, 0x3f, + 0xff, 0xc7, 0xae, 0x66, 0xa0, 0x85, 0x7e, 0x00, 0x45, 0x87, 0x30, 0x6e, 0x0e, 0x04, 0x6d, 0x62, + 0xfb, 0x75, 0x5c, 0x62, 0x67, 0x91, 0x10, 0x45, 0xac, 0x72, 0x3d, 0x2f, 0xac, 0xa4, 0xc8, 0xd2, + 0xf7, 0xa0, 0x84, 0x8b, 0x0c, 0xbd, 0xc9, 0xc4, 0xe6, 0x26, 0xf2, 0x9e, 0x46, 0xde, 0x37, 0x84, + 0xfc, 0x00, 0xc5, 0xc7, 0x22, 0x02, 0x77, 0x21, 0x67, 0x11, 0x4e, 0x24, 0x24, 0x83, 0x90, 0xac, + 0x10, 0xa0, 0xf2, 0x3d, 0xd8, 0x8c, 0xb2, 0x8e, 0x49, 0x48, 0x56, 0xae, 0x32, 0x13, 0x23, 0xf0, + 0x01, 0x6c, 0xbb, 0xf4, 0x82, 0x9b, 0x37, 0xd1, 0x39, 0x44, 0xeb, 0x42, 0xf7, 0x78, 0xde, 0xe2, + 0x9b, 0xb0, 0x31, 0x0c, 0xc9, 0x97, 0x58, 0x40, 0x6c, 0x31, 0x92, 0x22, 0x6c, 0x07, 0xb2, 0xc4, + 0xf7, 0x25, 0x20, 0x8f, 0x80, 0x0c, 0xf1, 0x7d, 0x54, 0x7d, 0x00, 0x5b, 0x78, 0xc6, 0x80, 0xb2, + 0xa9, 0xc3, 0xd5, 0x22, 0x05, 0xc4, 0x6c, 0x0a, 0x85, 0x21, 0xe5, 0x88, 0xfd, 0x06, 0x14, 0xe9, + 0xb9, 0x6d, 0x51, 0x77, 0x48, 0x25, 0xae, 0x88, 0xb8, 0x42, 0x28, 0x44, 0xd0, 0xfb, 0x50, 0xf2, + 0x03, 0xcf, 0xf7, 0x18, 0x0d, 0x4c, 0x62, 0x59, 0x01, 0x65, 0xac, 0xbc, 0x21, 0xd7, 0x0b, 0xe5, + 0x4d, 0x29, 0xae, 0xbf, 0xd0, 0x20, 0x75, 0x48, 0x38, 0xd1, 0x4b, 0x90, 0xe4, 0x17, 0xac, 0xac, + 0xd5, 0x92, 0x7b, 0x05, 0x43, 0x3c, 0xea, 0x9f, 0x40, 0x36, 0x5c, 0x55, 0x95, 0x4a, 0x75, 0x31, + 0x74, 0x47, 0x0a, 0x71, 0x62, 0x33, 0xae, 0xe2, 0x17, 0x59, 0xe9, 0x3f, 0x82, 0xec, 0x84, 0x32, + 0x46, 0x46, 0x94, 0x45, 0xf9, 0xb3, 0xb0, 0xc2, 0xa9, 0x42, 0x84, 0xd6, 0xa1, 0x85, 0x08, 0x85, + 0x17, 0xd8, 0x23, 0xdb, 0x25, 0x8e, 0xc9, 0x7e, 0x3d, 0x25, 0x01, 0x35, 0x99, 0xfd, 0x8c, 0x62, + 0x1a, 0xa5, 0x0c, 0x3d, 0xd4, 0xf5, 0x50, 0xd5, 0xb3, 0x9f, 0xd1, 0xa8, 0x30, 0xd3, 0xb1, 0x0e, + 0xf1, 0x3c, 0x01, 0xb7, 0x0e, 0xa7, 0xbe, 0x63, 0x0f, 0x09, 0xa7, 0x8f, 0x3d, 0x4e, 0x43, 0x8f, + 0xf5, 0x6f, 0x43, 0xfa, 0xdc, 0xe3, 0xd4, 0x24, 0xaa, 0xae, 0x6e, 0x2f, 0xfa, 0x26, 0xf0, 0xc6, + 0xba, 0x40, 0x35, 0x23, 0xf8, 0x40, 0x15, 0xf6, 0x6b, 0xe1, 0x2d, 0xfd, 0x23, 0xd0, 0xb1, 0x6d, + 0x99, 0xe7, 0x1e, 0xb7, 0xdd, 0x91, 0xe9, 0x7b, 0x5f, 0xd0, 0x40, 0xd5, 0x56, 0x09, 0x35, 0x8f, + 0x51, 0xd1, 0x15, 0xf2, 0xb9, 0xfc, 0x54, 0xd0, 0x14, 0x42, 0x67, 0xf9, 0x29, 0x81, 0x2d, 0xc8, + 0x45, 0xfd, 0x59, 0x15, 0xd4, 0x9b, 0xd5, 0xe4, 0xcc, 0xac, 0xfe, 0x97, 0x04, 0xec, 0x9c, 0x88, + 0xe2, 0x3e, 0x70, 0x6c, 0xea, 0xf2, 0x26, 0xe7, 0x64, 0xf8, 0x34, 0xa2, 0xa5, 0x0d, 0x5b, 0x43, + 0xcf, 0x7d, 0xe2, 0xd8, 0x43, 0xf4, 0x1b, 0xab, 0x57, 0x31, 0x74, 0x6f, 0xf1, 0xc8, 0xb8, 0x0e, + 0x16, 0xab, 0x51, 0x8a, 0x99, 0xa1, 0x44, 0x24, 0xab, 0xa8, 0x5b, 0xcf, 0x35, 0x55, 0x6b, 0x49, + 0xe0, 0x99, 0x0a, 0x52, 0x78, 0x2c, 0x1b, 0x4c, 0x07, 0xb6, 0x07, 0x97, 0xcf, 0x88, 0xcb, 0x6d, + 0x97, 0xc6, 0xca, 0xae, 0x9c, 0xac, 0x25, 0xf7, 0xf2, 0x0f, 0xef, 0x2e, 0x61, 0x39, 0xc4, 0x18, + 0x5f, 0x8b, 0x0c, 0x67, 0x35, 0xb9, 0x82, 0xf8, 0xd4, 0x0a, 0xe2, 0xdf, 0x05, 0x9f, 0xff, 0xd2, + 0x20, 0x1b, 0xd1, 0x47, 0xe0, 0x8e, 0x15, 0xa6, 0x9b, 0x89, 0x09, 0x13, 0x15, 0x91, 0x24, 0xf1, + 0xbd, 0xc5, 0x13, 0x2d, 0xcd, 0xcf, 0xe3, 0x35, 0xe3, 0x96, 0xb5, 0x34, 0x71, 0x5d, 0xb8, 0xe7, + 0x08, 0xea, 0xcc, 0x21, 0xc6, 0xcf, 0x24, 0x18, 0xc0, 0xd9, 0x3e, 0x32, 0x3f, 0x3f, 0x5c, 0x11, + 0xac, 0x65, 0x41, 0x3f, 0x5e, 0x33, 0x76, 0x9c, 0x55, 0xca, 0xd6, 0x3a, 0x24, 0xd9, 0x74, 0x52, + 0x3f, 0x81, 0x42, 0xbc, 0xda, 0x45, 0x75, 0xc7, 0x8e, 0x96, 0x5c, 0x5e, 0xdd, 0xd1, 0x22, 0x37, + 0x7a, 0x43, 0xfd, 0xa7, 0x90, 0x0d, 0x2b, 0x5f, 0xff, 0x09, 0x14, 0xc3, 0xaa, 0x37, 0x1d, 0x9b, + 0x71, 0xb5, 0xdc, 0xce, 0xca, 0x66, 0x61, 0x14, 0x42, 0xbc, 0xf0, 0xa4, 0xfe, 0x09, 0x64, 0x94, + 0x42, 0xff, 0x3a, 0x14, 0x5c, 0x32, 0xa1, 0xcc, 0x27, 0x43, 0x2a, 0x66, 0x8e, 0x9c, 0xd1, 0xf9, + 0x48, 0xd6, 0xb6, 0x44, 0x97, 0x10, 0x73, 0x21, 0xbc, 0x47, 0x88, 0xe7, 0xfa, 0x7f, 0x12, 0x90, + 0x12, 0x1c, 0xeb, 0x1f, 0x43, 0x4a, 0xec, 0x84, 0x76, 0x1b, 0xcb, 0x86, 0x77, 0xcf, 0x1e, 0xb9, + 0xd4, 0x3a, 0x65, 0xa3, 0xfe, 0xa5, 0x4f, 0x0d, 0x04, 0xc7, 0x66, 0x67, 0x62, 0x6e, 0x76, 0x6e, + 0xc3, 0x7a, 0xe0, 0x4d, 0x5d, 0x0b, 0xcb, 0x7e, 0xdd, 0x90, 0x2f, 0xfa, 0x11, 0x64, 0xa3, 0x91, + 0x98, 0xfa, 0x5f, 0x23, 0x71, 0x53, 0xd0, 0x26, 0x06, 0xb6, 0x12, 0x18, 0x99, 0x81, 0x9a, 0x8c, + 0xef, 0x20, 0x73, 0xf5, 0x0f, 0x61, 0x6b, 0xd6, 0x76, 0xc2, 0x49, 0x21, 0xbb, 0x67, 0x29, 0x52, + 0xa8, 0x51, 0x31, 0xdf, 0xa3, 0xe4, 0x6d, 0x2b, 0x83, 0xe7, 0x9a, 0xf5, 0xa8, 0x36, 0x5e, 0xbb, + 0xee, 0x41, 0x8e, 0xd9, 0x23, 0x97, 0xf0, 0x69, 0x40, 0xd5, 0x98, 0x9d, 0x09, 0xea, 0x7f, 0xd2, + 0x20, 0x2d, 0xc7, 0x76, 0x8c, 0x37, 0x6d, 0x39, 0x6f, 0x89, 0x55, 0xbc, 0x25, 0xdf, 0x9e, 0xb7, + 0x26, 0x40, 0xe4, 0x8c, 0x18, 0x4b, 0x2b, 0xba, 0x8c, 0x74, 0xb1, 0x67, 0x8f, 0x54, 0xe6, 0xc6, + 0x8c, 0xea, 0x7f, 0xd7, 0x20, 0x17, 0xe9, 0xf5, 0x26, 0x14, 0x43, 0xbf, 0xcc, 0x27, 0x0e, 0x19, + 0xa9, 0xdc, 0xb9, 0xbf, 0xd2, 0xb9, 0x4f, 0x1d, 0x32, 0x32, 0xf2, 0xca, 0x1f, 0xf1, 0xb2, 0x3c, + 0x0e, 0x89, 0x15, 0x71, 0x98, 0x0b, 0x7c, 0xf2, 0xed, 0x02, 0x3f, 0x17, 0xa2, 0xd4, 0xcd, 0x10, + 0xfd, 0x31, 0x01, 0xd9, 0x2e, 0x5e, 0x14, 0x88, 0xf3, 0xff, 0xa8, 0x88, 0xbb, 0x90, 0xf3, 0x3d, + 0xc7, 0x94, 0x9a, 0x14, 0x6a, 0xb2, 0xbe, 0xe7, 0x18, 0x0b, 0x61, 0x5f, 0x7f, 0x47, 0xe5, 0x92, + 0x7e, 0x07, 0xac, 0x65, 0x6e, 0xb2, 0x16, 0x40, 0x41, 0x52, 0xa1, 0x2e, 0xee, 0x0f, 0x04, 0x07, + 0xf8, 0x25, 0xa0, 0x2d, 0x7e, 0x68, 0x48, 0xb7, 0x25, 0xd2, 0x50, 0x38, 0x61, 0x21, 0xef, 0xb9, + 0xaa, 0x85, 0x97, 0x57, 0xa5, 0xa5, 0xa1, 0x70, 0xf5, 0xdf, 0x6a, 0x00, 0xb3, 0x11, 0x2c, 0xae, + 0xdc, 0x0c, 0x5d, 0x30, 0xe7, 0x76, 0xae, 0xae, 0x0a, 0x9a, 0xda, 0xbf, 0xc0, 0xe2, 0x7e, 0x1f, + 0x40, 0x71, 0x96, 0x8c, 0x8c, 0x86, 0xce, 0x54, 0x5f, 0x33, 0x89, 0x7b, 0x94, 0x1b, 0x85, 0xf3, + 0xd8, 0x5b, 0xfd, 0xcf, 0x1a, 0xe4, 0xd0, 0xa7, 0x53, 0xca, 0xc9, 0x5c, 0x0c, 0xb5, 0xb7, 0x8f, + 0xe1, 0x7d, 0x00, 0xb9, 0x0c, 0xde, 0x03, 0x65, 0x66, 0xe5, 0x50, 0x82, 0xd7, 0xbf, 0xef, 0x45, + 0x84, 0x27, 0x5f, 0x4f, 0xb8, 0x2a, 0xe9, 0x90, 0xf6, 0x3b, 0x90, 0x71, 0xa7, 0x13, 0x53, 0x5c, + 0x7f, 0xe5, 0x35, 0x21, 0xed, 0x4e, 0x27, 0xfd, 0x0b, 0x56, 0xff, 0x15, 0x64, 0xfa, 0x17, 0xf8, + 0x2d, 0x28, 0x52, 0x34, 0xf0, 0x3c, 0xf5, 0x01, 0x22, 0x87, 0x4a, 0x56, 0x08, 0xf0, 0xbe, 0xbd, + 0x64, 0xa2, 0xe8, 0x8d, 0x37, 0xfc, 0xca, 0x54, 0xdf, 0x97, 0x1f, 0xfc, 0x55, 0x83, 0x7c, 0xac, + 0x3f, 0xe8, 0xdf, 0x81, 0x5b, 0xad, 0x93, 0xb3, 0x83, 0xcf, 0xcc, 0xf6, 0xa1, 0xf9, 0xe9, 0x49, + 0xf3, 0x91, 0xf9, 0x79, 0xe7, 0xb3, 0xce, 0xd9, 0xcf, 0x3b, 0xa5, 0xb5, 0xca, 0xed, 0xab, 0xeb, + 0x9a, 0x1e, 0xc3, 0x7e, 0xee, 0x3e, 0x75, 0xbd, 0x2f, 0x5c, 0x7d, 0x1f, 0xb6, 0xe7, 0x4d, 0x9a, + 0xad, 0xde, 0x51, 0xa7, 0x5f, 0xd2, 0x2a, 0xb7, 0xae, 0xae, 0x6b, 0x5b, 0x31, 0x8b, 0xe6, 0x80, + 0x51, 0x97, 0x2f, 0x1a, 0x1c, 0x9c, 0x9d, 0x9e, 0xb6, 0xfb, 0xa5, 0xc4, 0x82, 0x81, 0x6a, 0xd8, + 0xef, 0xc3, 0xd6, 0xbc, 0x41, 0xa7, 0x7d, 0x52, 0x4a, 0x56, 0xf4, 0xab, 0xeb, 0xda, 0x46, 0x0c, + 0xdd, 0xb1, 0x9d, 0x4a, 0xf6, 0x37, 0xbf, 0xab, 0xae, 0xfd, 0xe1, 0xf7, 0x55, 0x4d, 0x9c, 0xac, + 0x38, 0xd7, 0x23, 0xf4, 0x8f, 0xe0, 0x4e, 0xaf, 0xfd, 0xa8, 0x73, 0x74, 0x68, 0x9e, 0xf6, 0x1e, + 0x99, 0xfd, 0x5f, 0x74, 0x8f, 0x62, 0xa7, 0xdb, 0xbc, 0xba, 0xae, 0xe5, 0xd5, 0x91, 0x56, 0xa1, + 0xbb, 0xc6, 0xd1, 0xe3, 0xb3, 0xfe, 0x51, 0x49, 0x93, 0xe8, 0x6e, 0x40, 0xc5, 0x4d, 0x0b, 0xd1, + 0x0f, 0x60, 0x67, 0x09, 0x3a, 0x3a, 0xd8, 0xd6, 0xd5, 0x75, 0xad, 0xd8, 0x0d, 0xa8, 0xac, 0x1f, + 0xb4, 0x68, 0x40, 0x79, 0xd1, 0xe2, 0xac, 0x7b, 0xd6, 0x6b, 0x9e, 0x94, 0x6a, 0x95, 0xd2, 0xd5, + 0x75, 0xad, 0x10, 0x36, 0x43, 0x81, 0x9f, 0x9d, 0xac, 0xf5, 0xb3, 0x2f, 0x5f, 0x56, 0xb5, 0xaf, + 0x5e, 0x56, 0xb5, 0x7f, 0xbe, 0xac, 0x6a, 0xcf, 0x5f, 0x55, 0xd7, 0xbe, 0x7a, 0x55, 0x5d, 0xfb, + 0xdb, 0xab, 0xea, 0xda, 0x2f, 0xbf, 0x3f, 0xb2, 0xf9, 0x78, 0x3a, 0x68, 0x0c, 0xbd, 0xc9, 0x7e, + 0xfc, 0xff, 0x8f, 0xd9, 0xa3, 0xfc, 0x1f, 0xe6, 0xe6, 0x7f, 0x23, 0x83, 0x34, 0xca, 0x3f, 0xfe, + 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x7a, 0x87, 0x97, 0xdc, 0x11, 0x00, 0x00, } func (m *PartSetHeader) Marshal() (dAtA []byte, err error) { @@ -1401,6 +1844,38 @@ func (m *Data) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Hash))) + i-- + dAtA[i] = 0x32 + } + if m.OriginalSquareSize != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.OriginalSquareSize)) + i-- + dAtA[i] = 0x28 + } + { + size, err := m.Messages.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size, err := m.Evidence.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a if len(m.Txs) > 0 { for iNdEx := len(m.Txs) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.Txs[iNdEx]) @@ -1413,7 +1888,7 @@ func (m *Data) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *Vote) Marshal() (dAtA []byte, err error) { +func (m *DuplicateVoteEvidence) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1423,72 +1898,62 @@ func (m *Vote) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *Vote) MarshalTo(dAtA []byte) (int, error) { +func (m *DuplicateVoteEvidence) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Vote) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *DuplicateVoteEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Signature) > 0 { - i -= len(m.Signature) - copy(dAtA[i:], m.Signature) - i = encodeVarintTypes(dAtA, i, uint64(len(m.Signature))) - i-- - dAtA[i] = 0x42 - } - if m.ValidatorIndex != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.ValidatorIndex)) - i-- - dAtA[i] = 0x38 - } - if len(m.ValidatorAddress) > 0 { - i -= len(m.ValidatorAddress) - copy(dAtA[i:], m.ValidatorAddress) - i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) - i-- - dAtA[i] = 0x32 + n8, err8 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + if err8 != nil { + return 0, err8 } - n6, err6 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) - if err6 != nil { - return 0, err6 - } - i -= n6 - i = encodeVarintTypes(dAtA, i, uint64(n6)) + i -= n8 + i = encodeVarintTypes(dAtA, i, uint64(n8)) i-- dAtA[i] = 0x2a - { - size, err := m.BlockID.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) + if m.ValidatorPower != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ValidatorPower)) + i-- + dAtA[i] = 0x20 } - i-- - dAtA[i] = 0x22 - if m.Round != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.Round)) + if m.TotalVotingPower != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.TotalVotingPower)) i-- dAtA[i] = 0x18 } - if m.Height != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.Height)) + if m.VoteB != nil { + { + size, err := m.VoteB.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } i-- - dAtA[i] = 0x10 + dAtA[i] = 0x12 } - if m.Type != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.Type)) + if m.VoteA != nil { + { + size, err := m.VoteA.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } i-- - dAtA[i] = 0x8 + dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *Commit) Marshal() (dAtA []byte, err error) { +func (m *LightClientAttackEvidence) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1498,20 +1963,33 @@ func (m *Commit) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *Commit) MarshalTo(dAtA []byte) (int, error) { +func (m *LightClientAttackEvidence) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Commit) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *LightClientAttackEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Signatures) > 0 { - for iNdEx := len(m.Signatures) - 1; iNdEx >= 0; iNdEx-- { + n11, err11 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + if err11 != nil { + return 0, err11 + } + i -= n11 + i = encodeVarintTypes(dAtA, i, uint64(n11)) + i-- + dAtA[i] = 0x2a + if m.TotalVotingPower != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.TotalVotingPower)) + i-- + dAtA[i] = 0x20 + } + if len(m.ByzantineValidators) > 0 { + for iNdEx := len(m.ByzantineValidators) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.Signatures[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.ByzantineValidators[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -1519,33 +1997,30 @@ func (m *Commit) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x22 - } - } - { - size, err := m.BlockID.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + dAtA[i] = 0x1a } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0x1a - if m.Round != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.Round)) + if m.CommonHeight != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.CommonHeight)) i-- dAtA[i] = 0x10 } - if m.Height != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.Height)) + if m.ConflictingBlock != nil { + { + size, err := m.ConflictingBlock.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } i-- - dAtA[i] = 0x8 + dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *CommitSig) Marshal() (dAtA []byte, err error) { +func (m *Evidence) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1555,115 +2030,71 @@ func (m *CommitSig) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *CommitSig) MarshalTo(dAtA []byte) (int, error) { +func (m *Evidence) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *CommitSig) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *Evidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Signature) > 0 { - i -= len(m.Signature) - copy(dAtA[i:], m.Signature) - i = encodeVarintTypes(dAtA, i, uint64(len(m.Signature))) - i-- - dAtA[i] = 0x22 - } - n9, err9 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) - if err9 != nil { - return 0, err9 - } - i -= n9 - i = encodeVarintTypes(dAtA, i, uint64(n9)) - i-- - dAtA[i] = 0x1a - if len(m.ValidatorAddress) > 0 { - i -= len(m.ValidatorAddress) - copy(dAtA[i:], m.ValidatorAddress) - i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) - i-- - dAtA[i] = 0x12 - } - if m.BlockIdFlag != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.BlockIdFlag)) - i-- - dAtA[i] = 0x8 + if m.Sum != nil { + { + size := m.Sum.Size() + i -= size + if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } } return len(dAtA) - i, nil } -func (m *Proposal) Marshal() (dAtA []byte, err error) { +func (m *Evidence_DuplicateVoteEvidence) MarshalTo(dAtA []byte) (int, error) { size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Proposal) MarshalTo(dAtA []byte) (int, error) { +func (m *Evidence_DuplicateVoteEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.DuplicateVoteEvidence != nil { + { + size, err := m.DuplicateVoteEvidence.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} +func (m *Evidence_LightClientAttackEvidence) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Proposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *Evidence_LightClientAttackEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Signature) > 0 { - i -= len(m.Signature) - copy(dAtA[i:], m.Signature) - i = encodeVarintTypes(dAtA, i, uint64(len(m.Signature))) - i-- - dAtA[i] = 0x3a - } - n10, err10 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) - if err10 != nil { - return 0, err10 - } - i -= n10 - i = encodeVarintTypes(dAtA, i, uint64(n10)) - i-- - dAtA[i] = 0x32 - { - size, err := m.BlockID.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if m.LightClientAttackEvidence != nil { + { + size, err := m.LightClientAttackEvidence.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - if m.PolRound != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.PolRound)) - i-- - dAtA[i] = 0x20 - } - if m.Round != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.Round)) - i-- - dAtA[i] = 0x18 - } - if m.Height != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.Height)) - i-- - dAtA[i] = 0x10 - } - if m.Type != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.Type)) i-- - dAtA[i] = 0x8 + dAtA[i] = 0x12 } return len(dAtA) - i, nil } - -func (m *SignedHeader) Marshal() (dAtA []byte, err error) { +func (m *EvidenceList) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1673,44 +2104,34 @@ func (m *SignedHeader) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *SignedHeader) MarshalTo(dAtA []byte) (int, error) { +func (m *EvidenceList) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *SignedHeader) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *EvidenceList) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.Commit != nil { - { - size, err := m.Commit.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - if m.Header != nil { - { - size, err := m.Header.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if len(m.Evidence) > 0 { + for iNdEx := len(m.Evidence) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Evidence[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa } - i-- - dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *LightBlock) Marshal() (dAtA []byte, err error) { +func (m *Messages) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1720,44 +2141,71 @@ func (m *LightBlock) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *LightBlock) MarshalTo(dAtA []byte) (int, error) { +func (m *Messages) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *LightBlock) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *Messages) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.ValidatorSet != nil { - { - size, err := m.ValidatorSet.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if len(m.MessagesList) > 0 { + for iNdEx := len(m.MessagesList) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.MessagesList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa } + } + return len(dAtA) - i, nil +} + +func (m *Message) 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 *Message) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Message) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Data))) i-- dAtA[i] = 0x12 } - if m.SignedHeader != nil { - { - size, err := m.SignedHeader.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } + 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] = 0xa } return len(dAtA) - i, nil } -func (m *BlockMeta) Marshal() (dAtA []byte, err error) { +func (m *Vote) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1767,23 +2215,45 @@ func (m *BlockMeta) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *BlockMeta) MarshalTo(dAtA []byte) (int, error) { +func (m *Vote) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *BlockMeta) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *Vote) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.NumTxs != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.NumTxs)) + if len(m.Signature) > 0 { + i -= len(m.Signature) + copy(dAtA[i:], m.Signature) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Signature))) i-- - dAtA[i] = 0x20 + dAtA[i] = 0x42 + } + if m.ValidatorIndex != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ValidatorIndex)) + i-- + dAtA[i] = 0x38 + } + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0x32 } + n15, err15 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + if err15 != nil { + return 0, err15 + } + i -= n15 + i = encodeVarintTypes(dAtA, i, uint64(n15)) + i-- + dAtA[i] = 0x2a { - size, err := m.Header.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.BlockID.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -1791,12 +2261,59 @@ func (m *BlockMeta) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a - if m.BlockSize != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.BlockSize)) + dAtA[i] = 0x22 + if m.Round != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Round)) + i-- + dAtA[i] = 0x18 + } + if m.Height != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Height)) i-- dAtA[i] = 0x10 } + if m.Type != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Commit) 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 *Commit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Commit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signatures) > 0 { + for iNdEx := len(m.Signatures) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Signatures[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } { size, err := m.BlockID.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -1806,11 +2323,21 @@ func (m *BlockMeta) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0xa + dAtA[i] = 0x1a + if m.Round != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Round)) + i-- + dAtA[i] = 0x10 + } + if m.Height != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } -func (m *TxProof) Marshal() (dAtA []byte, err error) { +func (m *CommitSig) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1820,399 +2347,1384 @@ func (m *TxProof) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *TxProof) MarshalTo(dAtA []byte) (int, error) { +func (m *CommitSig) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *TxProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *CommitSig) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.Proof != nil { - { - size, err := m.Proof.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } + if len(m.Signature) > 0 { + i -= len(m.Signature) + copy(dAtA[i:], m.Signature) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Signature))) i-- - dAtA[i] = 0x1a + dAtA[i] = 0x22 } - if len(m.Data) > 0 { - i -= len(m.Data) - copy(dAtA[i:], m.Data) - i = encodeVarintTypes(dAtA, i, uint64(len(m.Data))) + n18, err18 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + if err18 != nil { + return 0, err18 + } + i -= n18 + i = encodeVarintTypes(dAtA, i, uint64(n18)) + i-- + dAtA[i] = 0x1a + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) i-- dAtA[i] = 0x12 } - if len(m.RootHash) > 0 { - i -= len(m.RootHash) - copy(dAtA[i:], m.RootHash) - i = encodeVarintTypes(dAtA, i, uint64(len(m.RootHash))) + if m.BlockIdFlag != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.BlockIdFlag)) i-- - dAtA[i] = 0xa + dAtA[i] = 0x8 } return len(dAtA) - i, nil } -func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { - offset -= sovTypes(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *Proposal) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *PartSetHeader) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Total != 0 { - n += 1 + sovTypes(uint64(m.Total)) - } - l = len(m.Hash) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - return n + +func (m *Proposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Part) Size() (n int) { - if m == nil { - return 0 - } +func (m *Proposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.Index != 0 { - n += 1 + sovTypes(uint64(m.Index)) + if len(m.Signature) > 0 { + i -= len(m.Signature) + copy(dAtA[i:], m.Signature) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Signature))) + i-- + dAtA[i] = 0x3a } - l = len(m.Bytes) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) + n19, err19 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + if err19 != nil { + return 0, err19 } - l = m.Proof.Size() - n += 1 + l + sovTypes(uint64(l)) - return n -} - -func (m *BlockID) Size() (n int) { - if m == nil { - return 0 + i -= n19 + i = encodeVarintTypes(dAtA, i, uint64(n19)) + i-- + dAtA[i] = 0x32 + { + size, err := m.BlockID.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) } - var l int - _ = l - l = len(m.Hash) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - l = m.PartSetHeader.Size() - n += 1 + l + sovTypes(uint64(l)) - return n -} - -func (m *Header) Size() (n int) { - if m == nil { - return 0 + i-- + dAtA[i] = 0x2a + if m.PolRound != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.PolRound)) + i-- + dAtA[i] = 0x20 } - var l int - _ = l - l = m.Version.Size() - n += 1 + l + sovTypes(uint64(l)) - l = len(m.ChainID) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) + if m.Round != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Round)) + i-- + dAtA[i] = 0x18 } if m.Height != 0 { - n += 1 + sovTypes(uint64(m.Height)) - } - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Time) - n += 1 + l + sovTypes(uint64(l)) - l = m.LastBlockId.Size() - n += 1 + l + sovTypes(uint64(l)) - l = len(m.LastCommitHash) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - l = len(m.DataHash) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - l = len(m.ValidatorsHash) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - l = len(m.NextValidatorsHash) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - l = len(m.ConsensusHash) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - l = len(m.AppHash) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - l = len(m.LastResultsHash) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - l = len(m.EvidenceHash) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) + i = encodeVarintTypes(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x10 } - l = len(m.ProposerAddress) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) + if m.Type != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x8 } - return n + return len(dAtA) - i, nil } -func (m *Data) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Txs) > 0 { - for _, b := range m.Txs { - l = len(b) - n += 1 + l + sovTypes(uint64(l)) - } +func (m *SignedHeader) 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 n + return dAtA[:n], nil } -func (m *Vote) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Type != 0 { - n += 1 + sovTypes(uint64(m.Type)) - } - if m.Height != 0 { - n += 1 + sovTypes(uint64(m.Height)) - } - if m.Round != 0 { - n += 1 + sovTypes(uint64(m.Round)) - } - l = m.BlockID.Size() - n += 1 + l + sovTypes(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) - n += 1 + l + sovTypes(uint64(l)) - l = len(m.ValidatorAddress) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - if m.ValidatorIndex != 0 { - n += 1 + sovTypes(uint64(m.ValidatorIndex)) - } - l = len(m.Signature) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - return n +func (m *SignedHeader) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Commit) Size() (n int) { - if m == nil { - return 0 - } +func (m *SignedHeader) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.Height != 0 { - n += 1 + sovTypes(uint64(m.Height)) - } - if m.Round != 0 { - n += 1 + sovTypes(uint64(m.Round)) + if m.Commit != nil { + { + size, err := m.Commit.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 } - l = m.BlockID.Size() - n += 1 + l + sovTypes(uint64(l)) - if len(m.Signatures) > 0 { - for _, e := range m.Signatures { - l = e.Size() - n += 1 + l + sovTypes(uint64(l)) + if m.Header != nil { + { + size, err := m.Header.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0xa } - return n + return len(dAtA) - i, nil } -func (m *CommitSig) Size() (n int) { - if m == nil { - return 0 +func (m *LightBlock) 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 *LightBlock) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *LightBlock) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.BlockIdFlag != 0 { - n += 1 + sovTypes(uint64(m.BlockIdFlag)) - } - l = len(m.ValidatorAddress) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) + if m.ValidatorSet != nil { + { + size, err := m.ValidatorSet.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 } - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) - n += 1 + l + sovTypes(uint64(l)) - l = len(m.Signature) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) + if m.SignedHeader != nil { + { + size, err := m.SignedHeader.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa } - return n + return len(dAtA) - i, nil } -func (m *Proposal) Size() (n int) { - if m == nil { - return 0 +func (m *BlockMeta) 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 *BlockMeta) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BlockMeta) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.Type != 0 { - n += 1 + sovTypes(uint64(m.Type)) - } - if m.Height != 0 { - n += 1 + sovTypes(uint64(m.Height)) + if m.NumTxs != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.NumTxs)) + i-- + dAtA[i] = 0x20 } - if m.Round != 0 { - n += 1 + sovTypes(uint64(m.Round)) + { + size, err := m.Header.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) } - if m.PolRound != 0 { - n += 1 + sovTypes(uint64(m.PolRound)) + i-- + dAtA[i] = 0x1a + if m.BlockSize != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.BlockSize)) + i-- + dAtA[i] = 0x10 } - l = m.BlockID.Size() - n += 1 + l + sovTypes(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) - n += 1 + l + sovTypes(uint64(l)) - l = len(m.Signature) + { + size, err := m.BlockID.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *TxProof) 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 *TxProof) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TxProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Proof != nil { + { + size, err := m.Proof.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x12 + } + if len(m.RootHash) > 0 { + i -= len(m.RootHash) + copy(dAtA[i:], m.RootHash) + i = encodeVarintTypes(dAtA, i, uint64(len(m.RootHash))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PartSetHeader) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Total != 0 { + n += 1 + sovTypes(uint64(m.Total)) + } + l = len(m.Hash) if l > 0 { n += 1 + l + sovTypes(uint64(l)) } return n } -func (m *SignedHeader) Size() (n int) { +func (m *Part) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.Header != nil { - l = m.Header.Size() + if m.Index != 0 { + n += 1 + sovTypes(uint64(m.Index)) + } + l = len(m.Bytes) + if l > 0 { n += 1 + l + sovTypes(uint64(l)) } - if m.Commit != nil { - l = m.Commit.Size() + l = m.Proof.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *BlockID) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Hash) + if l > 0 { n += 1 + l + sovTypes(uint64(l)) } + l = m.PartSetHeader.Size() + n += 1 + l + sovTypes(uint64(l)) return n } -func (m *LightBlock) Size() (n int) { +func (m *Header) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.SignedHeader != nil { - l = m.SignedHeader.Size() + l = m.Version.Size() + n += 1 + l + sovTypes(uint64(l)) + l = len(m.ChainID) + if l > 0 { n += 1 + l + sovTypes(uint64(l)) } - if m.ValidatorSet != nil { - l = m.ValidatorSet.Size() + if m.Height != 0 { + n += 1 + sovTypes(uint64(m.Height)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Time) + n += 1 + l + sovTypes(uint64(l)) + l = m.LastBlockId.Size() + n += 1 + l + sovTypes(uint64(l)) + l = len(m.LastCommitHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.DataHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorsHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.NextValidatorsHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ConsensusHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.AppHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.LastResultsHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.EvidenceHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ProposerAddress) + if l > 0 { n += 1 + l + sovTypes(uint64(l)) } return n } -func (m *BlockMeta) Size() (n int) { +func (m *Data) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = m.BlockID.Size() - n += 1 + l + sovTypes(uint64(l)) - if m.BlockSize != 0 { - n += 1 + sovTypes(uint64(m.BlockSize)) + if len(m.Txs) > 0 { + for _, b := range m.Txs { + l = len(b) + n += 1 + l + sovTypes(uint64(l)) + } } - l = m.Header.Size() + l = m.Evidence.Size() n += 1 + l + sovTypes(uint64(l)) - if m.NumTxs != 0 { - n += 1 + sovTypes(uint64(m.NumTxs)) + l = m.Messages.Size() + n += 1 + l + sovTypes(uint64(l)) + if m.OriginalSquareSize != 0 { + n += 1 + sovTypes(uint64(m.OriginalSquareSize)) + } + l = len(m.Hash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) } return n } -func (m *TxProof) Size() (n int) { +func (m *DuplicateVoteEvidence) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.RootHash) - if l > 0 { + if m.VoteA != nil { + l = m.VoteA.Size() n += 1 + l + sovTypes(uint64(l)) } - l = len(m.Data) - if l > 0 { + if m.VoteB != nil { + l = m.VoteB.Size() n += 1 + l + sovTypes(uint64(l)) } - if m.Proof != nil { - l = m.Proof.Size() + if m.TotalVotingPower != 0 { + n += 1 + sovTypes(uint64(m.TotalVotingPower)) + } + if m.ValidatorPower != 0 { + n += 1 + sovTypes(uint64(m.ValidatorPower)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *LightClientAttackEvidence) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ConflictingBlock != nil { + l = m.ConflictingBlock.Size() n += 1 + l + sovTypes(uint64(l)) } + if m.CommonHeight != 0 { + n += 1 + sovTypes(uint64(m.CommonHeight)) + } + if len(m.ByzantineValidators) > 0 { + for _, e := range m.ByzantineValidators { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + if m.TotalVotingPower != 0 { + n += 1 + sovTypes(uint64(m.TotalVotingPower)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) + n += 1 + l + sovTypes(uint64(l)) return n } -func sovTypes(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 +func (m *Evidence) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sum != nil { + n += m.Sum.Size() + } + return n } -func sozTypes(x uint64) (n int) { - return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + +func (m *Evidence_DuplicateVoteEvidence) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.DuplicateVoteEvidence != nil { + l = m.DuplicateVoteEvidence.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n } -func (m *PartSetHeader) 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 +func (m *Evidence_LightClientAttackEvidence) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.LightClientAttackEvidence != nil { + l = m.LightClientAttackEvidence.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} +func (m *EvidenceList) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Evidence) > 0 { + for _, e := range m.Evidence { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *Messages) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.MessagesList) > 0 { + for _, e := range m.MessagesList { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *Message) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.NamespaceId) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *Vote) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Type != 0 { + n += 1 + sovTypes(uint64(m.Type)) + } + if m.Height != 0 { + n += 1 + sovTypes(uint64(m.Height)) + } + if m.Round != 0 { + n += 1 + sovTypes(uint64(m.Round)) + } + l = m.BlockID.Size() + n += 1 + l + sovTypes(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) + n += 1 + l + sovTypes(uint64(l)) + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.ValidatorIndex != 0 { + n += 1 + sovTypes(uint64(m.ValidatorIndex)) + } + l = len(m.Signature) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *Commit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Height != 0 { + n += 1 + sovTypes(uint64(m.Height)) + } + if m.Round != 0 { + n += 1 + sovTypes(uint64(m.Round)) + } + l = m.BlockID.Size() + n += 1 + l + sovTypes(uint64(l)) + if len(m.Signatures) > 0 { + for _, e := range m.Signatures { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *CommitSig) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BlockIdFlag != 0 { + n += 1 + sovTypes(uint64(m.BlockIdFlag)) + } + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) + n += 1 + l + sovTypes(uint64(l)) + l = len(m.Signature) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *Proposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Type != 0 { + n += 1 + sovTypes(uint64(m.Type)) + } + if m.Height != 0 { + n += 1 + sovTypes(uint64(m.Height)) + } + if m.Round != 0 { + n += 1 + sovTypes(uint64(m.Round)) + } + if m.PolRound != 0 { + n += 1 + sovTypes(uint64(m.PolRound)) + } + l = m.BlockID.Size() + n += 1 + l + sovTypes(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) + n += 1 + l + sovTypes(uint64(l)) + l = len(m.Signature) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *SignedHeader) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Header != nil { + l = m.Header.Size() + n += 1 + l + sovTypes(uint64(l)) + } + if m.Commit != nil { + l = m.Commit.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *LightBlock) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SignedHeader != nil { + l = m.SignedHeader.Size() + n += 1 + l + sovTypes(uint64(l)) + } + if m.ValidatorSet != nil { + l = m.ValidatorSet.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *BlockMeta) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.BlockID.Size() + n += 1 + l + sovTypes(uint64(l)) + if m.BlockSize != 0 { + n += 1 + sovTypes(uint64(m.BlockSize)) + } + l = m.Header.Size() + n += 1 + l + sovTypes(uint64(l)) + if m.NumTxs != 0 { + n += 1 + sovTypes(uint64(m.NumTxs)) + } + return n +} + +func (m *TxProof) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.RootHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.Proof != nil { + l = m.Proof.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PartSetHeader) 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: PartSetHeader: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PartSetHeader: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType) + } + m.Total = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Total |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hash", 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.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) + if m.Hash == nil { + m.Hash = []byte{} + } + 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 *Part) 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: Part: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Part: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + m.Index = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Index |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Bytes", 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.Bytes = append(m.Bytes[:0], dAtA[iNdEx:postIndex]...) + if m.Bytes == nil { + m.Bytes = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proof", 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 err := m.Proof.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 *BlockID) 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: BlockID: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlockID: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hash", 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.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) + if m.Hash == nil { + m.Hash = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PartSetHeader", 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 err := m.PartSetHeader.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 *Header) 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: Header: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Header: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", 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 err := m.Version.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Time", 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 err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LastBlockId", 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 err := m.LastBlockId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LastCommitHash", 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.LastCommitHash = append(m.LastCommitHash[:0], dAtA[iNdEx:postIndex]...) + if m.LastCommitHash == nil { + m.LastCommitHash = []byte{} + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DataHash", 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 iNdEx >= l { + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + m.DataHash = append(m.DataHash[:0], dAtA[iNdEx:postIndex]...) + if m.DataHash == nil { + m.DataHash = []byte{} } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: PartSetHeader: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: PartSetHeader: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorsHash", wireType) } - m.Total = 0 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2222,14 +3734,29 @@ func (m *PartSetHeader) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Total |= uint32(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - case 2: + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorsHash = append(m.ValidatorsHash[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorsHash == nil { + m.ValidatorsHash = []byte{} + } + iNdEx = postIndex + case 9: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field NextValidatorsHash", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -2256,66 +3783,84 @@ func (m *PartSetHeader) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) - if m.Hash == nil { - m.Hash = []byte{} + m.NextValidatorsHash = append(m.NextValidatorsHash[:0], dAtA[iNdEx:postIndex]...) + if m.NextValidatorsHash == nil { + m.NextValidatorsHash = []byte{} } iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsensusHash", wireType) } - if (skippy < 0) || (iNdEx+skippy) < 0 { + 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 } - if (iNdEx + skippy) > l { + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { return io.ErrUnexpectedEOF } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Part) 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 + m.ConsensusHash = append(m.ConsensusHash[:0], dAtA[iNdEx:postIndex]...) + if m.ConsensusHash == nil { + m.ConsensusHash = []byte{} } - if iNdEx >= l { + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppHash", 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 } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + m.AppHash = append(m.AppHash[:0], dAtA[iNdEx:postIndex]...) + if m.AppHash == nil { + m.AppHash = []byte{} } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Part: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Part: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LastResultsHash", wireType) } - m.Index = 0 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2325,14 +3870,29 @@ func (m *Part) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Index |= uint32(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - case 2: + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LastResultsHash = append(m.LastResultsHash[:0], dAtA[iNdEx:postIndex]...) + if m.LastResultsHash == nil { + m.LastResultsHash = []byte{} + } + iNdEx = postIndex + case 13: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Bytes", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field EvidenceHash", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -2359,16 +3919,16 @@ func (m *Part) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Bytes = append(m.Bytes[:0], dAtA[iNdEx:postIndex]...) - if m.Bytes == nil { - m.Bytes = []byte{} + m.EvidenceHash = append(m.EvidenceHash[:0], dAtA[iNdEx:postIndex]...) + if m.EvidenceHash == nil { + m.EvidenceHash = []byte{} } iNdEx = postIndex - case 3: + case 14: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProposerAddress", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2378,23 +3938,24 @@ func (m *Part) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Proof.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.ProposerAddress = append(m.ProposerAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ProposerAddress == nil { + m.ProposerAddress = []byte{} } iNdEx = postIndex default: @@ -2418,7 +3979,7 @@ func (m *Part) Unmarshal(dAtA []byte) error { } return nil } -func (m *BlockID) Unmarshal(dAtA []byte) error { +func (m *Data) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2437,21 +3998,53 @@ func (m *BlockID) Unmarshal(dAtA []byte) error { if b < 0x80 { break } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: BlockID: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: BlockID: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Data: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Data: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Txs", 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.Txs = append(m.Txs, make([]byte, postIndex-iNdEx)) + copy(m.Txs[len(m.Txs)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) } - var byteLen int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2461,29 +4054,28 @@ func (m *BlockID) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) - if m.Hash == nil { - m.Hash = []byte{} + if err := m.Evidence.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } iNdEx = postIndex - case 2: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PartSetHeader", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Messages", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2510,10 +4102,63 @@ func (m *BlockID) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.PartSetHeader.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Messages.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OriginalSquareSize", wireType) + } + m.OriginalSquareSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OriginalSquareSize |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hash", 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.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) + if m.Hash == nil { + m.Hash = []byte{} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -2535,7 +4180,7 @@ func (m *BlockID) Unmarshal(dAtA []byte) error { } return nil } -func (m *Header) Unmarshal(dAtA []byte) error { +func (m *DuplicateVoteEvidence) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2558,15 +4203,15 @@ func (m *Header) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Header: wiretype end group for non-group") + return fmt.Errorf("proto: DuplicateVoteEvidence: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Header: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: DuplicateVoteEvidence: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field VoteA", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2593,15 +4238,18 @@ func (m *Header) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Version.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if m.VoteA == nil { + m.VoteA = &Vote{} + } + if err := m.VoteA.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field VoteB", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2611,29 +4259,33 @@ func (m *Header) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.ChainID = string(dAtA[iNdEx:postIndex]) + if m.VoteB == nil { + m.VoteB = &Vote{} + } + if err := m.VoteB.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 3: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field TotalVotingPower", wireType) } - m.Height = 0 + m.TotalVotingPower = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2643,16 +4295,16 @@ func (m *Header) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Height |= int64(b&0x7F) << shift + m.TotalVotingPower |= int64(b&0x7F) << shift if b < 0x80 { break } } case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorPower", wireType) } - var msglen int + m.ValidatorPower = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2662,28 +4314,14 @@ func (m *Header) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + m.ValidatorPower |= int64(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 err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LastBlockId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2710,15 +4348,65 @@ func (m *Header) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.LastBlockId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 6: + 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 *LightClientAttackEvidence) 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: LightClientAttackEvidence: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LightClientAttackEvidence: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LastCommitHash", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ConflictingBlock", wireType) } - var byteLen int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2728,31 +4416,33 @@ func (m *Header) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.LastCommitHash = append(m.LastCommitHash[:0], dAtA[iNdEx:postIndex]...) - if m.LastCommitHash == nil { - m.LastCommitHash = []byte{} + if m.ConflictingBlock == nil { + m.ConflictingBlock = &LightBlock{} + } + if err := m.ConflictingBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DataHash", wireType) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonHeight", wireType) } - var byteLen int + m.CommonHeight = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2762,31 +4452,16 @@ func (m *Header) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + m.CommonHeight |= int64(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.DataHash = append(m.DataHash[:0], dAtA[iNdEx:postIndex]...) - if m.DataHash == nil { - m.DataHash = []byte{} - } - iNdEx = postIndex - case 8: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ValidatorsHash", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ByzantineValidators", wireType) } - var byteLen int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2796,31 +4471,31 @@ func (m *Header) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.ValidatorsHash = append(m.ValidatorsHash[:0], dAtA[iNdEx:postIndex]...) - if m.ValidatorsHash == nil { - m.ValidatorsHash = []byte{} + m.ByzantineValidators = append(m.ByzantineValidators, &Validator{}) + if err := m.ByzantineValidators[len(m.ByzantineValidators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } iNdEx = postIndex - case 9: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field NextValidatorsHash", wireType) + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalVotingPower", wireType) } - var byteLen int + m.TotalVotingPower = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2830,31 +4505,16 @@ func (m *Header) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + m.TotalVotingPower |= int64(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.NextValidatorsHash = append(m.NextValidatorsHash[:0], dAtA[iNdEx:postIndex]...) - if m.NextValidatorsHash == nil { - m.NextValidatorsHash = []byte{} - } - iNdEx = postIndex - case 10: + case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ConsensusHash", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) } - var byteLen int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2864,31 +4524,80 @@ func (m *Header) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.ConsensusHash = append(m.ConsensusHash[:0], dAtA[iNdEx:postIndex]...) - if m.ConsensusHash == nil { - m.ConsensusHash = []byte{} + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil { + return err } iNdEx = postIndex - case 11: + 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 *Evidence) 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: Evidence: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Evidence: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AppHash", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DuplicateVoteEvidence", wireType) } - var byteLen int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2898,31 +4607,32 @@ func (m *Header) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.AppHash = append(m.AppHash[:0], dAtA[iNdEx:postIndex]...) - if m.AppHash == nil { - m.AppHash = []byte{} + v := &DuplicateVoteEvidence{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } + m.Sum = &Evidence_DuplicateVoteEvidence{v} iNdEx = postIndex - case 12: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LastResultsHash", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field LightClientAttackEvidence", wireType) } - var byteLen int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2932,31 +4642,82 @@ func (m *Header) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.LastResultsHash = append(m.LastResultsHash[:0], dAtA[iNdEx:postIndex]...) - if m.LastResultsHash == nil { - m.LastResultsHash = []byte{} + v := &LightClientAttackEvidence{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } + m.Sum = &Evidence_LightClientAttackEvidence{v} iNdEx = postIndex - case 13: + 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 *EvidenceList) 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: EvidenceList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EvidenceList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field EvidenceHash", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) } - var byteLen int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -2966,31 +4727,81 @@ func (m *Header) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.EvidenceHash = append(m.EvidenceHash[:0], dAtA[iNdEx:postIndex]...) - if m.EvidenceHash == nil { - m.EvidenceHash = []byte{} + m.Evidence = append(m.Evidence, Evidence{}) + if err := m.Evidence[len(m.Evidence)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } iNdEx = postIndex - case 14: + 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 *Messages) 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: Messages: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Messages: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProposerAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MessagesList", wireType) } - var byteLen int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -3000,24 +4811,24 @@ func (m *Header) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.ProposerAddress = append(m.ProposerAddress[:0], dAtA[iNdEx:postIndex]...) - if m.ProposerAddress == nil { - m.ProposerAddress = []byte{} + m.MessagesList = append(m.MessagesList, &Message{}) + if err := m.MessagesList[len(m.MessagesList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } iNdEx = postIndex default: @@ -3041,7 +4852,7 @@ func (m *Header) Unmarshal(dAtA []byte) error { } return nil } -func (m *Data) Unmarshal(dAtA []byte) error { +func (m *Message) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3064,15 +4875,15 @@ func (m *Data) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Data: wiretype end group for non-group") + return fmt.Errorf("proto: Message: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Data: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Message: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Txs", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field NamespaceId", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -3099,8 +4910,44 @@ func (m *Data) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Txs = append(m.Txs, make([]byte, postIndex-iNdEx)) - copy(m.Txs[len(m.Txs)-1], dAtA[iNdEx:postIndex]) + m.NamespaceId = append(m.NamespaceId[:0], dAtA[iNdEx:postIndex]...) + if m.NamespaceId == nil { + m.NamespaceId = []byte{} + } + iNdEx = postIndex + case 2: + 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[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } iNdEx = postIndex default: iNdEx = preIndex diff --git a/proto/tendermint/types/types.proto b/proto/tendermint/types/types.proto index 8d4f009729..7416e0636d 100644 --- a/proto/tendermint/types/types.proto +++ b/proto/tendermint/types/types.proto @@ -87,6 +87,51 @@ message Data { // NOTE: not all txs here are valid. We're just agreeing on the order first. // This means that block.AppHash does not include these txs. repeated bytes txs = 1; + + // field number 2 is reserved for intermediate state roots + EvidenceList evidence = 3 [(gogoproto.nullable) = false]; + Messages messages = 4 [(gogoproto.nullable) = false]; + uint64 original_square_size = 5; + bytes hash = 6; +} + +// DuplicateVoteEvidence contains evidence of a validator signed two conflicting votes. +message DuplicateVoteEvidence { + tendermint.types.Vote vote_a = 1; + tendermint.types.Vote vote_b = 2; + int64 total_voting_power = 3; + int64 validator_power = 4; + google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; +} + +// LightClientAttackEvidence contains evidence of a set of validators attempting to mislead a light client. +message LightClientAttackEvidence { + tendermint.types.LightBlock conflicting_block = 1; + int64 common_height = 2; + repeated tendermint.types.Validator byzantine_validators = 3; + int64 total_voting_power = 4; + google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; +} + +message Evidence { + oneof sum { + DuplicateVoteEvidence duplicate_vote_evidence = 1; + LightClientAttackEvidence light_client_attack_evidence = 2; + } +} + +// EvidenceData contains any evidence of malicious wrong-doing by validators +message EvidenceList { + repeated Evidence evidence = 1 [(gogoproto.nullable) = false]; +} + +message Messages { + repeated Message messages_list = 1; +} + +message Message { + bytes namespace_id = 1; + bytes data = 2; } // Vote represents a prevote, precommit, or commit vote from validators for diff --git a/test/Makefile b/test/Makefile index 86226cf03a..bc788bc97d 100644 --- a/test/Makefile +++ b/test/Makefile @@ -5,6 +5,8 @@ BINDIR ?= $(GOPATH)/bin +PACKAGES=$(shell go list ./...) + ## required to be run first by most tests build_docker_test_image: docker build -t tester -f ./test/docker/Dockerfile . diff --git a/types/block.go b/types/block.go index 2f444be748..f81ad83008 100644 --- a/types/block.go +++ b/types/block.go @@ -44,8 +44,7 @@ type Block struct { Header `json:"header"` Data `json:"data"` - Evidence EvidenceData `json:"evidence"` - LastCommit *Commit `json:"last_commit"` + LastCommit *Commit `json:"last_commit"` } // ValidateBasic performs basic validation that doesn't involve state data. @@ -217,12 +216,6 @@ func (b *Block) ToProto() (*tmproto.Block, error) { pb.LastCommit = b.LastCommit.ToProto() pb.Data = b.Data.ToProto() - protoEvidence, err := b.Evidence.ToProto() - if err != nil { - return nil, err - } - pb.Evidence = *protoEvidence - return pb, nil } @@ -244,9 +237,6 @@ func BlockFromProto(bp *tmproto.Block) (*Block, error) { return nil, err } b.Data = data - if err := b.Evidence.FromProto(&bp.Evidence); err != nil { - return nil, err - } if bp.LastCommit != nil { lc, err := CommitFromProto(bp.LastCommit) @@ -314,9 +304,9 @@ func MakeBlock(height int64, txs []Tx, lastCommit *Commit, evidence []Evidence) Height: height, }, Data: Data{ - Txs: txs, + Txs: txs, + Evidence: EvidenceData{Evidence: evidence}, }, - Evidence: EvidenceData{Evidence: evidence}, LastCommit: lastCommit, } block.fillHeader() @@ -997,14 +987,31 @@ func CommitFromProto(cp *tmproto.Commit) (*Commit, error) { //----------------------------------------------------------------------------- -// Data contains the set of transactions included in the block +// Data contains all the available Data of the block. +// Data with reserved namespaces (Txs, IntermediateStateRoots, Evidence) and +// Celestia application specific Messages. type Data struct { - // Txs that will be applied by state @ block.Height+1. // NOTE: not all txs here are valid. We're just agreeing on the order first. // This means that block.AppHash does not include these txs. Txs Txs `json:"txs"` + Evidence EvidenceData `json:"evidence"` + + // The messages included in this block. + // TODO: how do messages end up here? (abci) app <-> ll-core? + // A simple approach could be: include them in the Tx above and + // have a mechanism to split them out somehow? Probably better to include + // them only when necessary (before proposing the block) as messages do not + // really need to be processed by tendermint + Messages Messages `json:"msgs"` + + // OriginalSquareSize is the size of the square after splitting all the block data + // into shares. The erasure data is discarded after generation, and keeping this + // value avoids unnecessarily regenerating all of the shares when returning + // proofs that some element was included in the block + OriginalSquareSize uint64 `json:"square_size"` + // Volatile hash tmbytes.HexBytes } @@ -1052,6 +1059,25 @@ func (data *Data) ToProto() tmproto.Data { tp.Txs = txBzs } + pevd, err := data.Evidence.ToProto() + if err != nil { + // TODO(evan): fix + panic(err) + } + tp.Evidence = *pevd + + protoMsgs := make([]*tmproto.Message, len(data.Messages.MessagesList)) + for i, msg := range data.Messages.MessagesList { + protoMsgs[i] = &tmproto.Message{ + NamespaceId: msg.NamespaceID, + Data: msg.Data, + } + } + tp.Messages = tmproto.Messages{MessagesList: protoMsgs} + tp.OriginalSquareSize = data.OriginalSquareSize + + tp.Hash = data.hash + return *tp } @@ -1073,6 +1099,27 @@ func DataFromProto(dp *tmproto.Data) (Data, error) { data.Txs = Txs{} } + if len(dp.Messages.MessagesList) > 0 { + msgs := make([]Message, len(dp.Messages.MessagesList)) + for i, m := range dp.Messages.MessagesList { + msgs[i] = Message{NamespaceID: m.NamespaceId, Data: m.Data} + } + data.Messages = Messages{MessagesList: msgs} + } else { + data.Messages = Messages{} + } + + evdData := new(EvidenceData) + err := evdData.FromProto(&dp.Evidence) + if err != nil { + return Data{}, err + } + if evdData != nil { + data.Evidence = *evdData + } + data.OriginalSquareSize = dp.OriginalSquareSize + data.hash = dp.Hash + return *data, nil } From bf2d8b46c1caf1fed52e7db9bf8aa6a9847d84ab Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Tue, 3 May 2022 13:32:33 -0500 Subject: [PATCH 05/31] add share merging and splitting Co-authored-by: John Adler Co-authored-by: Ismail Khoffi Co-authored-by: Hlib Kanunnikov --- types/block.go | 212 ++++++++++++++- types/share_merging.go | 307 +++++++++++++++++++++ types/share_splitting.go | 257 ++++++++++++++++++ types/shares.go | 54 ++++ types/shares_test.go | 574 +++++++++++++++++++++++++++++++++++++++ types/tx.go | 29 ++ 6 files changed, 1426 insertions(+), 7 deletions(-) create mode 100644 types/share_merging.go create mode 100644 types/share_splitting.go create mode 100644 types/shares.go create mode 100644 types/shares_test.go diff --git a/types/block.go b/types/block.go index f81ad83008..abf481a407 100644 --- a/types/block.go +++ b/types/block.go @@ -4,19 +4,25 @@ import ( "bytes" "errors" "fmt" + "math" + "sort" "strings" "time" + "github.com/celestiaorg/nmt/namespace" "github.com/gogo/protobuf/proto" gogotypes "github.com/gogo/protobuf/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/crypto/tmhash" + "github.com/tendermint/tendermint/internal/libs/protoio" tmsync "github.com/tendermint/tendermint/internal/libs/sync" "github.com/tendermint/tendermint/libs/bits" tmbytes "github.com/tendermint/tendermint/libs/bytes" tmmath "github.com/tendermint/tendermint/libs/math" + "github.com/tendermint/tendermint/pkg/consts" + "github.com/tendermint/tendermint/pkg/da" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/version" ) @@ -1018,15 +1024,188 @@ type Data struct { // Hash returns the hash of the data func (data *Data) Hash() tmbytes.HexBytes { - if data == nil { - return (Txs{}).Hash() + if data.hash != nil { + return data.hash } - if data.hash == nil { - data.hash = data.Txs.Hash() // NOTE: leaves of merkle tree are TxIDs + + // compute the data availability header + // todo(evan): add the non redundant shares back into the header + shares, _, err := data.ComputeShares(data.OriginalSquareSize) + if err != nil { + // todo(evan): see if we can get rid of this panic + panic(err) } + rawShares := shares.RawShares() + + eds, err := da.ExtendShares(data.OriginalSquareSize, rawShares) + if err != nil { + panic(err) + } + + dah := da.NewDataAvailabilityHeader(eds) + + data.hash = dah.Hash() + return data.hash } +// ComputeShares splits block data into shares of an original data square and +// returns them along with an amount of non-redundant shares. If a square size +// of 0 is passed, then it is determined based on how many shares are needed to +// fill the square for the underlying block data. The square size is stored in +// the local instance of the struct. +func (data *Data) ComputeShares(squareSize uint64) (NamespacedShares, int, error) { + if squareSize != 0 { + if !powerOf2(squareSize) { + return nil, 0, errors.New("square size is not a power of two") + } + } + + // reserved shares: + txShares := data.Txs.SplitIntoShares() + evidenceShares := data.Evidence.SplitIntoShares() + + // application data shares from messages: + msgShares := data.Messages.SplitIntoShares() + curLen := len(txShares) + len(evidenceShares) + len(msgShares) + + if curLen > consts.MaxShareCount { + panic(fmt.Sprintf("Block data exceeds the max square size. Number of shares required: %d\n", curLen)) + } + + // find the number of shares needed to create a square that has a power of + // two width + wantLen := int(squareSize * squareSize) + if squareSize == 0 { + wantLen = paddedLen(curLen) + } + + if wantLen < curLen { + return nil, 0, errors.New("square size too small to fit block data") + } + + // ensure that the min square size is used + if wantLen < consts.MinSharecount { + wantLen = consts.MinSharecount + } + + tailShares := TailPaddingShares(wantLen - curLen) + + shares := append(append(append( + txShares, + evidenceShares...), + msgShares...), + tailShares...) + + if squareSize == 0 { + squareSize = uint64(math.Sqrt(float64(wantLen))) + } + + data.OriginalSquareSize = squareSize + + return shares, curLen, nil +} + +// paddedLen calculates the number of shares needed to make a power of 2 square +// given the current number of shares +func paddedLen(length int) int { + width := uint32(math.Ceil(math.Sqrt(float64(length)))) + width = nextHighestPowerOf2(width) + return int(width * width) +} + +// nextPowerOf2 returns the next highest power of 2 unless the input is a power +// of two, in which case it returns the input +func nextHighestPowerOf2(v uint32) uint32 { + if v == 0 { + return 0 + } + + // find the next highest power using bit mashing + v-- + v |= v >> 1 + v |= v >> 2 + v |= v >> 4 + v |= v >> 8 + v |= v >> 16 + v++ + + // return the next highest power + return v +} + +// powerOf2 checks if number is power of 2 +func powerOf2(v uint64) bool { + if v&(v-1) == 0 && v != 0 { + return true + } + return false +} + +type Messages struct { + MessagesList []Message `json:"msgs"` +} + +func (msgs Messages) SplitIntoShares() NamespacedShares { + shares := make([]NamespacedShare, 0) + msgs.sortMessages() + for _, m := range msgs.MessagesList { + rawData, err := m.MarshalDelimited() + if err != nil { + panic(fmt.Sprintf("app accepted a Message that can not be encoded %#v", m)) + } + shares = AppendToShares(shares, m.NamespaceID, rawData) + } + return shares +} + +func (msgs *Messages) sortMessages() { + sort.Slice(msgs.MessagesList, func(i, j int) bool { + return bytes.Compare(msgs.MessagesList[i].NamespaceID, msgs.MessagesList[j].NamespaceID) < 0 + }) +} + +type Message struct { + // NamespaceID defines the namespace of this message, i.e. the + // namespace it will use in the namespaced Merkle tree. + // + // TODO: spec out constrains and + // introduce dedicated type instead of just []byte + NamespaceID namespace.ID + + // Data is the actual data contained in the message + // (e.g. a block of a virtual sidechain). + Data []byte +} + +var ( + MessageEmpty = Message{} + MessagesEmpty = Messages{} +) + +func MessageFromProto(p *tmproto.Message) Message { + if p == nil { + return MessageEmpty + } + return Message{ + NamespaceID: p.NamespaceId, + Data: p.Data, + } +} + +func MessagesFromProto(p *tmproto.Messages) Messages { + if p == nil { + return MessagesEmpty + } + + msgs := make([]Message, 0, len(p.MessagesList)) + + for i := 0; i < len(p.MessagesList); i++ { + msgs = append(msgs, MessageFromProto(p.MessagesList[i])) + } + return Messages{MessagesList: msgs} +} + // StringIndented returns an indented string representation of the transactions. func (data *Data) StringIndented(indent string) string { if data == nil { @@ -1042,9 +1221,8 @@ func (data *Data) StringIndented(indent string) string { } return fmt.Sprintf(`Data{ %s %v -%s}#%v`, - indent, strings.Join(txStrings, "\n"+indent+" "), - indent, data.hash) +}`, + indent, strings.Join(txStrings, "\n"+indent+" ")) } // ToProto converts Data to protobuf @@ -1214,6 +1392,26 @@ func (data *EvidenceData) FromProto(eviData *tmproto.EvidenceList) error { return nil } +func (data *EvidenceData) SplitIntoShares() NamespacedShares { + rawDatas := make([][]byte, 0, len(data.Evidence)) + for _, ev := range data.Evidence { + pev, err := EvidenceToProto(ev) + if err != nil { + panic("failure to convert evidence to equivalent proto type") + } + rawData, err := protoio.MarshalDelimited(pev) + if err != nil { + panic(err) + } + rawDatas = append(rawDatas, rawData) + } + w := NewContiguousShareWriter(consts.EvidenceNamespaceID) + for _, evd := range rawDatas { + w.Write(evd) + } + return w.Export() +} + //-------------------------------------------------------------------------------- // BlockID diff --git a/types/share_merging.go b/types/share_merging.go new file mode 100644 index 0000000000..73ac48ba2f --- /dev/null +++ b/types/share_merging.go @@ -0,0 +1,307 @@ +package types + +import ( + "bytes" + "encoding/binary" + "errors" + + "github.com/celestiaorg/rsmt2d" + "github.com/gogo/protobuf/proto" + "github.com/tendermint/tendermint/pkg/consts" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" +) + +// DataFromSquare extracts block data from an extended data square. +func DataFromSquare(eds *rsmt2d.ExtendedDataSquare) (Data, error) { + originalWidth := eds.Width() / 2 + + // sort block data shares by namespace + var ( + sortedTxShares [][]byte + sortedEvdShares [][]byte + sortedMsgShares [][]byte + ) + + // iterate over each row index + for x := uint(0); x < originalWidth; x++ { + // iterate over each share in the original data square + row := eds.Row(x) + + for _, share := range row[:originalWidth] { + // sort the data of that share types via namespace + nid := share[:consts.NamespaceSize] + switch { + case bytes.Equal(consts.TxNamespaceID, nid): + sortedTxShares = append(sortedTxShares, share) + + case bytes.Equal(consts.EvidenceNamespaceID, nid): + sortedEvdShares = append(sortedEvdShares, share) + + case bytes.Equal(consts.TailPaddingNamespaceID, nid): + continue + + // ignore unused but reserved namespaces + case bytes.Compare(nid, consts.MaxReservedNamespace) < 1: + continue + + // every other namespaceID should be a message + default: + sortedMsgShares = append(sortedMsgShares, share) + } + } + } + + // pass the raw share data to their respective parsers + txs, err := ParseTxs(sortedTxShares) + if err != nil { + return Data{}, err + } + + evd, err := ParseEvd(sortedEvdShares) + if err != nil { + return Data{}, err + } + + msgs, err := ParseMsgs(sortedMsgShares) + if err != nil { + return Data{}, err + } + + return Data{ + Txs: txs, + Evidence: evd, + Messages: msgs, + }, nil +} + +// ParseTxs collects all of the transactions from the shares provided +func ParseTxs(shares [][]byte) (Txs, error) { + // parse the sharse + rawTxs, err := processContiguousShares(shares) + if err != nil { + return nil, err + } + + // convert to the Tx type + txs := make(Txs, len(rawTxs)) + for i := 0; i < len(txs); i++ { + txs[i] = Tx(rawTxs[i]) + } + + return txs, nil +} + +// ParseEvd collects all evidence from the shares provided. +func ParseEvd(shares [][]byte) (EvidenceData, error) { + // the raw data returned does not have length delimiters or namespaces and + // is ready to be unmarshaled + rawEvd, err := processContiguousShares(shares) + if err != nil { + return EvidenceData{}, err + } + + evdList := make(EvidenceList, len(rawEvd)) + + // parse into protobuf bytes + for i := 0; i < len(rawEvd); i++ { + // unmarshal the evidence + var protoEvd tmproto.Evidence + err := proto.Unmarshal(rawEvd[i], &protoEvd) + if err != nil { + return EvidenceData{}, err + } + evd, err := EvidenceFromProto(&protoEvd) + if err != nil { + return EvidenceData{}, err + } + + evdList[i] = evd + } + + return EvidenceData{Evidence: evdList}, nil +} + +// ParseMsgs collects all messages from the shares provided +func ParseMsgs(shares [][]byte) (Messages, error) { + msgList, err := parseMsgShares(shares) + if err != nil { + return Messages{}, err + } + + return Messages{ + MessagesList: msgList, + }, nil +} + +// processContiguousShares takes raw shares and extracts out transactions, +// intermediate state roots, or evidence. The returned [][]byte do have +// namespaces or length delimiters and are ready to be unmarshalled +func processContiguousShares(shares [][]byte) (txs [][]byte, err error) { + if len(shares) == 0 { + return nil, nil + } + + ss := newShareStack(shares) + return ss.resolve() +} + +// shareStack hold variables for peel +type shareStack struct { + shares [][]byte + txLen uint64 + txs [][]byte + cursor int +} + +func newShareStack(shares [][]byte) *shareStack { + return &shareStack{shares: shares} +} + +func (ss *shareStack) resolve() ([][]byte, error) { + if len(ss.shares) == 0 { + return nil, nil + } + err := ss.peel(ss.shares[0][consts.NamespaceSize+consts.ShareReservedBytes:], true) + return ss.txs, err +} + +// peel recursively parses each chunk of data (either a transaction, +// intermediate state root, or evidence) and adds it to the underlying slice of data. +func (ss *shareStack) peel(share []byte, delimited bool) (err error) { + if delimited { + var txLen uint64 + share, txLen, err = ParseDelimiter(share) + if err != nil { + return err + } + if txLen == 0 { + return nil + } + ss.txLen = txLen + } + // safeLen describes the point in the share where it can be safely split. If + // split beyond this point, it is possible to break apart a length + // delimiter, which will result in incorrect share merging + safeLen := len(share) - binary.MaxVarintLen64 + if safeLen < 0 { + safeLen = 0 + } + if ss.txLen <= uint64(safeLen) { + ss.txs = append(ss.txs, share[:ss.txLen]) + share = share[ss.txLen:] + return ss.peel(share, true) + } + // add the next share to the current share to continue merging if possible + if len(ss.shares) > ss.cursor+1 { + ss.cursor++ + share := append(share, ss.shares[ss.cursor][consts.NamespaceSize+consts.ShareReservedBytes:]...) + return ss.peel(share, false) + } + // collect any remaining data + if ss.txLen <= uint64(len(share)) { + ss.txs = append(ss.txs, share[:ss.txLen]) + share = share[ss.txLen:] + return ss.peel(share, true) + } + return errors.New("failure to parse block data: transaction length exceeded data length") +} + +// parseMsgShares iterates through raw shares and separates the contiguous chunks +// of data. It is only used for Messages, i.e. shares with a non-reserved namespace. +func parseMsgShares(shares [][]byte) ([]Message, error) { + if len(shares) == 0 { + return nil, nil + } + + // set the first nid and current share + nid := shares[0][:consts.NamespaceSize] + currentShare := shares[0][consts.NamespaceSize:] + // find and remove the msg len delimiter + currentShare, msgLen, err := ParseDelimiter(currentShare) + if err != nil { + return nil, err + } + + var msgs []Message + for cursor := uint64(0); cursor < uint64(len(shares)); { + var msg Message + currentShare, nid, cursor, msgLen, msg, err = nextMsg( + shares, + currentShare, + nid, + cursor, + msgLen, + ) + if err != nil { + return nil, err + } + if msg.Data != nil { + msgs = append(msgs, msg) + } + } + + return msgs, nil +} + +func nextMsg( + shares [][]byte, + current, + nid []byte, + cursor, + msgLen uint64, +) ([]byte, []byte, uint64, uint64, Message, error) { + switch { + // the message uses all of the current share data and at least some of the + // next share + case msgLen > uint64(len(current)): + // add the next share to the current one and try again + cursor++ + current = append(current, shares[cursor][consts.NamespaceSize:]...) + return nextMsg(shares, current, nid, cursor, msgLen) + + // the msg we're looking for is contained in the current share + case msgLen <= uint64(len(current)): + msg := Message{nid, current[:msgLen]} + cursor++ + + // call it a day if the work is done + if cursor >= uint64(len(shares)) { + return nil, nil, cursor, 0, msg, nil + } + + nextNid := shares[cursor][:consts.NamespaceSize] + next, msgLen, err := ParseDelimiter(shares[cursor][consts.NamespaceSize:]) + return next, nextNid, cursor, msgLen, msg, err + } + // this code is unreachable but the compiler doesn't know that + return nil, nil, 0, 0, Message{}, nil +} + +// ParseDelimiter finds and returns the length delimiter of the message provided +// while also removing the delimiter bytes from the input +func ParseDelimiter(input []byte) ([]byte, uint64, error) { + if len(input) == 0 { + return input, 0, nil + } + + l := binary.MaxVarintLen64 + if len(input) < binary.MaxVarintLen64 { + l = len(input) + } + + delimiter := zeroPadIfNecessary(input[:l], binary.MaxVarintLen64) + + // read the length of the message + r := bytes.NewBuffer(delimiter) + msgLen, err := binary.ReadUvarint(r) + if err != nil { + return nil, 0, err + } + + // calculate the number of bytes used by the delimiter + lenBuf := make([]byte, binary.MaxVarintLen64) + n := binary.PutUvarint(lenBuf, msgLen) + + // return the input without the length delimiter + return input[n:], msgLen, nil +} diff --git a/types/share_splitting.go b/types/share_splitting.go new file mode 100644 index 0000000000..f6c690e4de --- /dev/null +++ b/types/share_splitting.go @@ -0,0 +1,257 @@ +package types + +import ( + "bytes" + "fmt" + "sort" + + "github.com/celestiaorg/nmt/namespace" + "github.com/tendermint/tendermint/pkg/consts" +) + +// MessageShareWriter lazily merges messages into shares that will eventually be +// included in a data square. It also has methods to help progressively count +// how many shares the messages written take up. +type MessageShareWriter struct { + shares [][]NamespacedShare + count int +} + +func NewMessageShareWriter() *MessageShareWriter { + return &MessageShareWriter{} +} + +// Write adds the delimited data to the underlying contiguous shares. +func (msw *MessageShareWriter) Write(msg Message) { + rawMsg, err := msg.MarshalDelimited() + if err != nil { + panic(fmt.Sprintf("app accepted a Message that can not be encoded %#v", msg)) + } + newShares := make([]NamespacedShare, 0) + newShares = AppendToShares(newShares, msg.NamespaceID, rawMsg) + msw.shares = append(msw.shares, newShares) + msw.count += len(newShares) +} + +// Export finalizes and returns the underlying contiguous shares. +func (msw *MessageShareWriter) Export() NamespacedShares { + msw.sortMsgs() + shares := make([]NamespacedShare, msw.count) + cursor := 0 + for _, messageShares := range msw.shares { + for _, share := range messageShares { + shares[cursor] = share + cursor++ + } + } + return shares +} + +func (msw *MessageShareWriter) sortMsgs() { + sort.Slice(msw.shares, func(i, j int) bool { + return bytes.Compare(msw.shares[i][0].ID, msw.shares[j][0].ID) < 0 + }) +} + +// Count returns the current number of shares that will be made if exporting. +func (msw *MessageShareWriter) Count() int { + return msw.count +} + +// appendToShares appends raw data as shares. +// Used for messages. +func AppendToShares(shares []NamespacedShare, nid namespace.ID, rawData []byte) []NamespacedShare { + if len(rawData) <= consts.MsgShareSize { + rawShare := append(append( + make([]byte, 0, len(nid)+len(rawData)), + nid...), + rawData..., + ) + paddedShare := zeroPadIfNecessary(rawShare, consts.ShareSize) + share := NamespacedShare{paddedShare, nid} + shares = append(shares, share) + } else { // len(rawData) > MsgShareSize + shares = append(shares, splitMessage(rawData, nid)...) + } + return shares +} + +// splitMessage breaks the data in a message into the minimum number of +// namespaced shares +func splitMessage(rawData []byte, nid namespace.ID) NamespacedShares { + shares := make([]NamespacedShare, 0) + firstRawShare := append(append( + make([]byte, 0, consts.ShareSize), + nid...), + rawData[:consts.MsgShareSize]..., + ) + shares = append(shares, NamespacedShare{firstRawShare, nid}) + rawData = rawData[consts.MsgShareSize:] + for len(rawData) > 0 { + shareSizeOrLen := min(consts.MsgShareSize, len(rawData)) + rawShare := append(append( + make([]byte, 0, consts.ShareSize), + nid...), + rawData[:shareSizeOrLen]..., + ) + paddedShare := zeroPadIfNecessary(rawShare, consts.ShareSize) + share := NamespacedShare{paddedShare, nid} + shares = append(shares, share) + rawData = rawData[shareSizeOrLen:] + } + return shares +} + +// ContiguousShareWriter will write raw data contiguously across a progressively +// increasing set of shares. It is used to lazily split block data such as transactions +// into shares. +type ContiguousShareWriter struct { + shares []NamespacedShare + pendingShare NamespacedShare + namespace namespace.ID +} + +// NewContiguousShareWriter returns a ContigousShareWriter using the provided +// namespace. +func NewContiguousShareWriter(ns namespace.ID) *ContiguousShareWriter { + pendingShare := NamespacedShare{ID: ns, Share: make([]byte, 0, consts.ShareSize)} + pendingShare.Share = append(pendingShare.Share, ns...) + return &ContiguousShareWriter{pendingShare: pendingShare, namespace: ns} +} + +// Write adds the delimited data to the underlying contiguous shares. +func (csw *ContiguousShareWriter) Write(rawData []byte) { + // if this is the first time writing to a pending share, we must add the + // reserved bytes + if len(csw.pendingShare.Share) == consts.NamespaceSize { + csw.pendingShare.Share = append(csw.pendingShare.Share, 0) + } + + txCursor := len(rawData) + for txCursor != 0 { + // find the len left in the pending share + pendingLeft := consts.ShareSize - len(csw.pendingShare.Share) + + // if we can simply add the tx to the share without creating a new + // pending share, do so and return + if len(rawData) <= pendingLeft { + csw.pendingShare.Share = append(csw.pendingShare.Share, rawData...) + break + } + + // if we can only add a portion of the transaction to the pending share, + // then we add it and add the pending share to the finalized shares. + chunk := rawData[:pendingLeft] + csw.pendingShare.Share = append(csw.pendingShare.Share, chunk...) + csw.stackPending() + + // update the cursor + rawData = rawData[pendingLeft:] + txCursor = len(rawData) + + // add the share reserved bytes to the new pending share + pendingCursor := len(rawData) + consts.NamespaceSize + consts.ShareReservedBytes + var reservedByte byte + if pendingCursor >= consts.ShareSize { + // the share reserve byte is zero when some contiguously written + // data takes up the entire share + reservedByte = byte(0) + } else { + reservedByte = byte(pendingCursor) + } + + csw.pendingShare.Share = append(csw.pendingShare.Share, reservedByte) + } + + // if the share is exactly the correct size, then append to shares + if len(csw.pendingShare.Share) == consts.ShareSize { + csw.stackPending() + } +} + +// stackPending will add the pending share to accumlated shares provided that it is long enough +func (csw *ContiguousShareWriter) stackPending() { + if len(csw.pendingShare.Share) < consts.ShareSize { + return + } + csw.shares = append(csw.shares, csw.pendingShare) + newPendingShare := make([]byte, 0, consts.ShareSize) + newPendingShare = append(newPendingShare, csw.namespace...) + csw.pendingShare = NamespacedShare{ + Share: newPendingShare, + ID: csw.namespace, + } +} + +// Export finalizes and returns the underlying contiguous shares. +func (csw *ContiguousShareWriter) Export() NamespacedShares { + // add the pending share to the current shares before returning + if len(csw.pendingShare.Share) > consts.NamespaceSize { + csw.pendingShare.Share = zeroPadIfNecessary(csw.pendingShare.Share, consts.ShareSize) + csw.shares = append(csw.shares, csw.pendingShare) + } + // force the last share to have a reserve byte of zero + if len(csw.shares) == 0 { + return csw.shares + } + lastShare := csw.shares[len(csw.shares)-1] + rawLastShare := lastShare.Data() + + for i := 0; i < consts.ShareReservedBytes; i++ { + // here we force the last share reserved byte to be zero to avoid any + // confusion for light clients parsing these shares, as the rest of the + // data after transaction is padding. See + // https://github.com/celestiaorg/celestia-specs/blob/master/src/specs/data_structures.md#share + rawLastShare[consts.NamespaceSize+i] = byte(0) + } + + newLastShare := NamespacedShare{ + Share: rawLastShare, + ID: lastShare.NamespaceID(), + } + csw.shares[len(csw.shares)-1] = newLastShare + return csw.shares +} + +// Count returns the current number of shares that will be made if exporting. +func (csw *ContiguousShareWriter) Count() (count, availableBytes int) { + availableBytes = consts.TxShareSize - (len(csw.pendingShare.Share) - consts.NamespaceSize) + return len(csw.shares), availableBytes +} + +// tail is filler for all tail padded shares +// it is allocated once and used everywhere +var tailPaddingShare = append( + append(make([]byte, 0, consts.ShareSize), consts.TailPaddingNamespaceID...), + bytes.Repeat([]byte{0}, consts.ShareSize-consts.NamespaceSize)..., +) + +func TailPaddingShares(n int) NamespacedShares { + shares := make([]NamespacedShare, n) + for i := 0; i < n; i++ { + shares[i] = NamespacedShare{ + Share: tailPaddingShare, + ID: consts.TailPaddingNamespaceID, + } + } + return shares +} + +func min(a, b int) int { + if a <= b { + return a + } + return b +} + +func zeroPadIfNecessary(share []byte, width int) []byte { + oldLen := len(share) + if oldLen < width { + missingBytes := width - oldLen + padByte := []byte{0} + padding := bytes.Repeat(padByte, missingBytes) + share = append(share, padding...) + return share + } + return share +} diff --git a/types/shares.go b/types/shares.go new file mode 100644 index 0000000000..ac0b517009 --- /dev/null +++ b/types/shares.go @@ -0,0 +1,54 @@ +package types + +import ( + "encoding/binary" + + "github.com/celestiaorg/nmt/namespace" +) + +// Share contains the raw share data without the corresponding namespace. +type Share []byte + +// NamespacedShare extends a Share with the corresponding namespace. +type NamespacedShare struct { + Share + ID namespace.ID +} + +func (n NamespacedShare) NamespaceID() namespace.ID { + return n.ID +} + +func (n NamespacedShare) Data() []byte { + return n.Share +} + +// NamespacedShares is just a list of NamespacedShare elements. +// It can be used to extract the raw raw shares. +type NamespacedShares []NamespacedShare + +// RawShares returns the raw shares that can be fed into the erasure coding +// library (e.g. rsmt2d). +func (ns NamespacedShares) RawShares() [][]byte { + res := make([][]byte, len(ns)) + for i, nsh := range ns { + res[i] = nsh.Share + } + return res +} + +func (tx Tx) MarshalDelimited() ([]byte, error) { + lenBuf := make([]byte, binary.MaxVarintLen64) + length := uint64(len(tx)) + n := binary.PutUvarint(lenBuf, length) + return append(lenBuf[:n], tx...), nil +} + +// MarshalDelimited marshals the raw data (excluding the namespace) of this +// message and prefixes it with the length of that encoding. +func (msg Message) MarshalDelimited() ([]byte, error) { + lenBuf := make([]byte, binary.MaxVarintLen64) + length := uint64(len(msg.Data)) + n := binary.PutUvarint(lenBuf, length) + return append(lenBuf[:n], msg.Data...), nil +} diff --git a/types/shares_test.go b/types/shares_test.go new file mode 100644 index 0000000000..eebd8477d3 --- /dev/null +++ b/types/shares_test.go @@ -0,0 +1,574 @@ +package types + +import ( + "bytes" + "context" + "fmt" + "math" + "math/rand" + "reflect" + "sort" + "testing" + "time" + + "github.com/celestiaorg/nmt/namespace" + "github.com/celestiaorg/rsmt2d" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/internal/libs/protoio" + "github.com/tendermint/tendermint/pkg/consts" +) + +type Splitter interface { + SplitIntoShares() NamespacedShares +} + +func TestMakeShares(t *testing.T) { + reservedTxNamespaceID := append(bytes.Repeat([]byte{0}, 7), 1) + reservedEvidenceNamespaceID := append(bytes.Repeat([]byte{0}, 7), 3) + val := NewMockPV() + blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash")) + blockID2 := makeBlockID([]byte("blockhash2"), 1000, []byte("partshash")) + vote1 := makeVote(t, val, "chainID", 0, 10, 2, 1, blockID, defaultVoteTime) + vote2 := makeVote(t, val, "chainID", 0, 10, 2, 1, blockID2, defaultVoteTime) + testEvidence := &DuplicateVoteEvidence{ + VoteA: vote1, + VoteB: vote2, + } + protoTestEvidence, err := EvidenceToProto(testEvidence) + if err != nil { + t.Error(err) + } + testEvidenceBytes, err := protoio.MarshalDelimited(protoTestEvidence) + largeTx := Tx(bytes.Repeat([]byte("large Tx"), 50)) + largeTxLenDelimited, _ := largeTx.MarshalDelimited() + smolTx := Tx("small Tx") + smolTxLenDelimited, _ := smolTx.MarshalDelimited() + msg1 := Message{ + NamespaceID: namespace.ID("8bytesss"), + Data: []byte("some data"), + } + msg1Marshaled, _ := msg1.MarshalDelimited() + if err != nil { + t.Fatalf("Could not encode evidence: %v, error: %v\n", testEvidence, err) + } + + type args struct { + data Splitter + } + tests := []struct { + name string + args args + want NamespacedShares + }{ + { + name: "evidence", + args: args{ + data: &EvidenceData{ + Evidence: []Evidence{testEvidence}, + }, + }, + want: NamespacedShares{ + NamespacedShare{ + Share: append( + append(reservedEvidenceNamespaceID, byte(0)), + testEvidenceBytes[:consts.TxShareSize]..., + ), + ID: reservedEvidenceNamespaceID, + }, + NamespacedShare{ + Share: append( + append(reservedEvidenceNamespaceID, byte(0)), + zeroPadIfNecessary(testEvidenceBytes[consts.TxShareSize:], consts.TxShareSize)..., + ), + ID: reservedEvidenceNamespaceID, + }, + }, + }, + {"small LL Tx", + args{ + data: Txs{smolTx}, + }, + NamespacedShares{ + NamespacedShare{ + Share: append( + append(reservedTxNamespaceID, byte(0)), + zeroPadIfNecessary(smolTxLenDelimited, consts.TxShareSize)..., + ), + ID: reservedTxNamespaceID, + }, + }, + }, + {"one large LL Tx", + args{ + data: Txs{largeTx}, + }, + NamespacedShares{ + NamespacedShare{ + Share: append( + append(reservedTxNamespaceID, byte(0)), + largeTxLenDelimited[:consts.TxShareSize]..., + ), + ID: reservedTxNamespaceID, + }, + NamespacedShare{ + Share: append( + append(reservedTxNamespaceID, byte(0)), + zeroPadIfNecessary(largeTxLenDelimited[consts.TxShareSize:], consts.TxShareSize)..., + ), + ID: reservedTxNamespaceID, + }, + }, + }, + {"large then small LL Tx", + args{ + data: Txs{largeTx, smolTx}, + }, + NamespacedShares{ + NamespacedShare{ + Share: append( + append(reservedTxNamespaceID, byte(0)), + largeTxLenDelimited[:consts.TxShareSize]..., + ), + ID: reservedTxNamespaceID, + }, + NamespacedShare{ + Share: append( + append( + reservedTxNamespaceID, + byte(0), + ), + zeroPadIfNecessary( + append(largeTxLenDelimited[consts.TxShareSize:], smolTxLenDelimited...), + consts.TxShareSize, + )..., + ), + ID: reservedTxNamespaceID, + }, + }, + }, + {"ll-app message", + args{ + data: Messages{[]Message{msg1}}, + }, + NamespacedShares{ + NamespacedShare{ + Share: append( + []byte(msg1.NamespaceID), + zeroPadIfNecessary(msg1Marshaled, consts.MsgShareSize)..., + ), + ID: msg1.NamespaceID, + }, + }, + }, + } + for i, tt := range tests { + tt := tt // stupid scopelint :-/ + i := i + t.Run(tt.name, func(t *testing.T) { + got := tt.args.data.SplitIntoShares() + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("%v: makeShares() = \n%+v\nwant\n%+v\n", i, got, tt.want) + } + }) + } +} + +func Test_zeroPadIfNecessary(t *testing.T) { + type args struct { + share []byte + width int + } + tests := []struct { + name string + args args + want []byte + }{ + {"pad", args{[]byte{1, 2, 3}, 6}, []byte{1, 2, 3, 0, 0, 0}}, + {"not necessary (equal to shareSize)", args{[]byte{1, 2, 3}, 3}, []byte{1, 2, 3}}, + {"not necessary (greater shareSize)", args{[]byte{1, 2, 3}, 2}, []byte{1, 2, 3}}, + } + for _, tt := range tests { + tt := tt // stupid scopelint :-/ + t.Run(tt.name, func(t *testing.T) { + if got := zeroPadIfNecessary(tt.args.share, tt.args.width); !reflect.DeepEqual(got, tt.want) { + t.Errorf("zeroPadIfNecessary() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_appendToSharesOverwrite(t *testing.T) { + var shares NamespacedShares + + // generate some arbitrary namespaced shares first share that must be split + newShare := generateRandomNamespacedShares(1, consts.MsgShareSize+1)[0] + + // make a copy of the portion of the share to check if it's overwritten later + extraCopy := make([]byte, consts.MsgShareSize) + copy(extraCopy, newShare.Share[:consts.MsgShareSize]) + + // use appendToShares to add our new share + AppendToShares(shares, newShare.ID, newShare.Share) + + // check if the original share data has been overwritten. + assert.Equal(t, extraCopy, []byte(newShare.Share[:consts.MsgShareSize])) +} + +func TestDataFromSquare(t *testing.T) { + type test struct { + name string + txCount int + evdCount int + msgCount int + maxSize int // max size of each tx or msg + } + + tests := []test{ + {"one of each random small size", 1, 1, 1, 40}, + {"one of each random large size", 1, 1, 1, 400}, + {"many of each random large size", 10, 10, 10, 40}, + {"many of each random large size", 10, 10, 10, 400}, + {"only transactions", 10, 0, 0, 400}, + {"only evidence", 0, 10, 0, 400}, + {"only messages", 0, 0, 10, 400}, + } + + for _, tc := range tests { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + // generate random data + data := generateRandomBlockData( + tc.txCount, + tc.evdCount, + tc.msgCount, + tc.maxSize, + ) + + shares, _, err := data.ComputeShares(0) + require.NoError(t, err) + rawShares := shares.RawShares() + + eds, err := rsmt2d.ComputeExtendedDataSquare(rawShares, consts.DefaultCodec(), rsmt2d.NewDefaultTree) + if err != nil { + t.Error(err) + } + + res, err := DataFromSquare(eds) + if err != nil { + t.Fatal(err) + } + + // we have to compare the evidence by string because the the + // timestamps differ not by actual time represented, but by + // internals see https://github.com/stretchr/testify/issues/666 + for i := 0; i < len(data.Evidence.Evidence); i++ { + inputEvidence := data.Evidence.Evidence[i].(*DuplicateVoteEvidence) + resultEvidence := res.Evidence.Evidence[i].(*DuplicateVoteEvidence) + assert.Equal(t, inputEvidence.String(), resultEvidence.String()) + } + + // compare the original to the result w/o the evidence + data.Evidence = EvidenceData{} + res.Evidence = EvidenceData{} + + res.OriginalSquareSize = data.OriginalSquareSize + + assert.Equal(t, data, res) + }) + } +} + +func TestFuzz_DataFromSquare(t *testing.T) { + t.Skip() + // run random shares through processContiguousShares for a minute + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + for { + select { + case <-ctx.Done(): + return + default: + TestDataFromSquare(t) + } + } +} + +func Test_processContiguousShares(t *testing.T) { + // exactTxShareSize is the length of tx that will fit exactly into a single + // share, accounting for namespace id and the length delimiter prepended to + // each tx + const exactTxShareSize = consts.TxShareSize - 1 + + type test struct { + name string + txSize int + txCount int + } + + // each test is ran twice, once using txSize as an exact size, and again + // using it as a cap for randomly sized txs + tests := []test{ + {"single small tx", 10, 1}, + {"many small txs", 10, 10}, + {"single big tx", 1000, 1}, + {"many big txs", 1000, 10}, + {"single exact size tx", exactTxShareSize, 1}, + {"many exact size txs", exactTxShareSize, 10}, + } + + for _, tc := range tests { + tc := tc + + // run the tests with identically sized txs + t.Run(fmt.Sprintf("%s idendically sized ", tc.name), func(t *testing.T) { + txs := generateRandomContiguousShares(tc.txCount, tc.txSize) + + shares := txs.SplitIntoShares() + + parsedTxs, err := processContiguousShares(shares.RawShares()) + if err != nil { + t.Error(err) + } + + // check that the data parsed is identical + for i := 0; i < len(txs); i++ { + assert.Equal(t, []byte(txs[i]), parsedTxs[i]) + } + }) + + // run the same tests using randomly sized txs with caps of tc.txSize + t.Run(fmt.Sprintf("%s randomly sized", tc.name), func(t *testing.T) { + txs := generateRandomlySizedContiguousShares(tc.txCount, tc.txSize) + + shares := txs.SplitIntoShares() + + parsedTxs, err := processContiguousShares(shares.RawShares()) + if err != nil { + t.Error(err) + } + + // check that the data parsed is identical to the original + for i := 0; i < len(txs); i++ { + assert.Equal(t, []byte(txs[i]), parsedTxs[i]) + } + }) + } +} + +func TestFuzz_processContiguousShares(t *testing.T) { + t.Skip() + // run random shares through processContiguousShares for a minute + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + for { + select { + case <-ctx.Done(): + return + default: + Test_processContiguousShares(t) + } + } +} + +func Test_parseMsgShares(t *testing.T) { + // exactMsgShareSize is the length of message that will fit exactly into a single + // share, accounting for namespace id and the length delimiter prepended to + // each message + const exactMsgShareSize = consts.MsgShareSize - 2 + + type test struct { + name string + msgSize int + msgCount int + } + + // each test is ran twice, once using msgSize as an exact size, and again + // using it as a cap for randomly sized leaves + tests := []test{ + {"single small msg", 1, 1}, + {"many small msgs", 4, 10}, + {"single big msg", 1000, 1}, + {"many big msgs", 1000, 10}, + {"single exact size msg", exactMsgShareSize, 1}, + {"many exact size msgs", exactMsgShareSize, 10}, + } + + for _, tc := range tests { + tc := tc + + // run the tests with identically sized messagses + t.Run(fmt.Sprintf("%s idendically sized ", tc.name), func(t *testing.T) { + rawmsgs := make([]Message, tc.msgCount) + for i := 0; i < tc.msgCount; i++ { + rawmsgs[i] = generateRandomMessage(tc.msgSize) + } + msgs := Messages{MessagesList: rawmsgs} + + shares := msgs.SplitIntoShares() + + parsedMsgs, err := parseMsgShares(shares.RawShares()) + if err != nil { + t.Error(err) + } + + // check that the namesapces and data are the same + for i := 0; i < len(msgs.MessagesList); i++ { + assert.Equal(t, msgs.MessagesList[i].NamespaceID, parsedMsgs[i].NamespaceID) + assert.Equal(t, msgs.MessagesList[i].Data, parsedMsgs[i].Data) + } + }) + + // run the same tests using randomly sized messages with caps of tc.msgSize + t.Run(fmt.Sprintf("%s randomly sized", tc.name), func(t *testing.T) { + msgs := generateRandomlySizedMessages(tc.msgCount, tc.msgSize) + shares := msgs.SplitIntoShares() + + parsedMsgs, err := parseMsgShares(shares.RawShares()) + if err != nil { + t.Error(err) + } + + // check that the namesapces and data are the same + for i := 0; i < len(msgs.MessagesList); i++ { + assert.Equal(t, msgs.MessagesList[i].NamespaceID, parsedMsgs[i].NamespaceID) + assert.Equal(t, msgs.MessagesList[i].Data, parsedMsgs[i].Data) + } + }) + } +} + +func TestContigShareWriter(t *testing.T) { + // note that this test is mainly for debugging purposes, the main round trip + // tests occur in TestDataFromSquare and Test_processContiguousShares + w := NewContiguousShareWriter(consts.TxNamespaceID) + txs := generateRandomContiguousShares(33, 200) + for _, tx := range txs { + rawTx, _ := tx.MarshalDelimited() + w.Write(rawTx) + } + resShares := w.Export() + rawResTxs, err := processContiguousShares(resShares.RawShares()) + resTxs := ToTxs(rawResTxs) + require.NoError(t, err) + + assert.Equal(t, txs, resTxs) +} + +func Test_parseDelimiter(t *testing.T) { + for i := uint64(0); i < 100; i++ { + tx := generateRandomContiguousShares(1, int(i))[0] + input, err := tx.MarshalDelimited() + if err != nil { + panic(err) + } + res, txLen, err := ParseDelimiter(input) + if err != nil { + panic(err) + } + assert.Equal(t, i, txLen) + assert.Equal(t, []byte(tx), res) + } +} + +// generateRandomBlockData returns randomly generated block data for testing purposes +func generateRandomBlockData(txCount, evdCount, msgCount, maxSize int) Data { + var out Data + out.Txs = generateRandomlySizedContiguousShares(txCount, maxSize) + out.Evidence = generateIdenticalEvidence(evdCount) + out.Messages = generateRandomlySizedMessages(msgCount, maxSize) + return out +} + +func generateRandomlySizedContiguousShares(count, max int) Txs { + txs := make(Txs, count) + for i := 0; i < count; i++ { + size := rand.Intn(max) + if size == 0 { + size = 1 + } + txs[i] = generateRandomContiguousShares(1, size)[0] + } + return txs +} + +func generateRandomContiguousShares(count, size int) Txs { + txs := make(Txs, count) + for i := 0; i < count; i++ { + tx := make([]byte, size) + _, err := rand.Read(tx) + if err != nil { + panic(err) + } + txs[i] = tx + } + return txs +} + +func generateIdenticalEvidence(count int) EvidenceData { + evidence := make([]Evidence, count) + for i := 0; i < count; i++ { + ev := NewMockDuplicateVoteEvidence(math.MaxInt64, time.Now(), "chainID") + evidence[i] = ev + } + return EvidenceData{Evidence: evidence} +} + +func generateRandomlySizedMessages(count, maxMsgSize int) Messages { + msgs := make([]Message, count) + for i := 0; i < count; i++ { + msgs[i] = generateRandomMessage(rand.Intn(maxMsgSize)) + } + + // this is just to let us use assert.Equal + if count == 0 { + msgs = nil + } + + messages := Messages{MessagesList: msgs} + messages.sortMessages() + return messages +} + +func generateRandomMessage(size int) Message { + share := generateRandomNamespacedShares(1, size)[0] + msg := Message{ + NamespaceID: share.NamespaceID(), + Data: share.Data(), + } + return msg +} + +func generateRandomNamespacedShares(count, msgSize int) NamespacedShares { + shares := generateRandNamespacedRawData(uint32(count), consts.NamespaceSize, uint32(msgSize)) + msgs := make([]Message, count) + for i, s := range shares { + msgs[i] = Message{ + Data: s[consts.NamespaceSize:], + NamespaceID: s[:consts.NamespaceSize], + } + } + return Messages{MessagesList: msgs}.SplitIntoShares() +} + +func generateRandNamespacedRawData(total, nidSize, leafSize uint32) [][]byte { + data := make([][]byte, total) + for i := uint32(0); i < total; i++ { + nid := make([]byte, nidSize) + rand.Read(nid) + data[i] = nid + } + sortByteArrays(data) + for i := uint32(0); i < total; i++ { + d := make([]byte, leafSize) + rand.Read(d) + data[i] = append(data[i], d...) + } + + return data +} + +func sortByteArrays(src [][]byte) { + sort.Slice(src, func(i, j int) bool { return bytes.Compare(src[i], src[j]) < 0 }) +} diff --git a/types/tx.go b/types/tx.go index 19ee41dace..22093bf288 100644 --- a/types/tx.go +++ b/types/tx.go @@ -9,6 +9,7 @@ import ( "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/crypto/tmhash" tmbytes "github.com/tendermint/tendermint/libs/bytes" + "github.com/tendermint/tendermint/pkg/consts" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) @@ -122,6 +123,7 @@ func (tp TxProof) ToProto() tmproto.TxProof { return pbtp } + func TxProofFromProto(pb tmproto.TxProof) (TxProof, error) { pbProof, err := merkle.ProofFromProto(pb.Proof) @@ -138,6 +140,24 @@ func TxProofFromProto(pb tmproto.TxProof) (TxProof, error) { return pbtp, nil } +func (txs Txs) SplitIntoShares() NamespacedShares { + rawDatas := make([][]byte, len(txs)) + for i, tx := range txs { + rawData, err := tx.MarshalDelimited() + if err != nil { + panic(fmt.Sprintf("included Tx in mem-pool that can not be encoded %v", tx)) + } + rawDatas[i] = rawData + } + + w := NewContiguousShareWriter(consts.TxNamespaceID) + for _, tx := range rawDatas { + w.Write(tx) + } + + return w.Export() +} + // ComputeProtoSizeForTxs wraps the transactions in tmproto.Data{} and calculates the size. // https://developers.google.com/protocol-buffers/docs/encoding func ComputeProtoSizeForTxs(txs []Tx) int64 { @@ -145,3 +165,12 @@ func ComputeProtoSizeForTxs(txs []Tx) int64 { pdData := data.ToProto() return int64(pdData.Size()) } + +// ToTxs converts a raw slice of byte slices into a Txs type. +func ToTxs(txs [][]byte) Txs { + txBzs := make(Txs, len(txs)) + for i := 0; i < len(txs); i++ { + txBzs[i] = txs[i] + } + return txBzs +} From c4b4ed68bf6fe25540facde60dc2f48f2fa687be Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 27 Apr 2022 15:37:05 -0500 Subject: [PATCH 06/31] update to go 1.17 patch remainting tests update to go 1.17 switch back to using rsmt2d v0.5 patch protobuf encoding tests linter --- DOCKER/Dockerfile | 2 +- docs/tutorials/go.md | 4 +- go.mod | 182 ++++++++++++++++++++++++++++++++- networks/remote/integration.sh | 4 +- node/node_test.go | 2 +- test/docker/Dockerfile | 2 +- test/e2e/docker/Dockerfile | 2 +- types/block_test.go | 27 ++--- 8 files changed, 197 insertions(+), 28 deletions(-) diff --git a/DOCKER/Dockerfile b/DOCKER/Dockerfile index 0465bec09c..55b69f940c 100644 --- a/DOCKER/Dockerfile +++ b/DOCKER/Dockerfile @@ -1,5 +1,5 @@ # stage 1 Generate Tendermint Binary -FROM golang:1.16-alpine as builder +FROM golang:1.17-alpine as builder RUN apk update && \ apk upgrade && \ apk --no-cache add make diff --git a/docs/tutorials/go.md b/docs/tutorials/go.md index 6614cffe53..cd3804440c 100644 --- a/docs/tutorials/go.md +++ b/docs/tutorials/go.md @@ -43,7 +43,7 @@ Verify that you have the latest version of Go installed: ```bash $ go version -go version go1.16.x darwin/amd64 +go version go1.17.x darwin/amd64 ``` ## 1.2 Creating a new Go project @@ -446,7 +446,7 @@ This will populate the `go.mod` with a release number followed by a hash for Ten ```go module github.com/me/example -go 1.16 +go 1.17 require ( github.com/dgraph-io/badger v1.6.2 diff --git a/go.mod b/go.mod index d6b49080d3..d74fdb914d 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/tendermint/tendermint -go 1.16 +go 1.17 require ( github.com/BurntSushi/toml v1.1.0 @@ -13,9 +13,6 @@ require ( github.com/creachadair/atomicfile v0.2.5 github.com/creachadair/taskgroup v0.3.2 github.com/creachadair/tomledit v0.0.18 - github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect - github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect - github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect github.com/fortytw2/leaktest v1.3.0 github.com/go-kit/kit v0.12.0 github.com/gogo/protobuf v1.3.2 @@ -50,3 +47,180 @@ require ( google.golang.org/grpc v1.46.0 pgregory.net/rapid v0.4.7 ) + +require ( + 4d63.com/gochecknoglobals v0.1.0 // indirect + github.com/Antonboom/errname v0.1.5 // indirect + github.com/Antonboom/nilnil v0.1.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/DataDog/zstd v1.4.1 // indirect + github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect + github.com/Masterminds/semver v1.5.0 // indirect + github.com/Microsoft/go-winio v0.5.1 // indirect + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect + github.com/OpenPeeDeeP/depguard v1.1.0 // indirect + github.com/alexkohler/prealloc v1.0.0 // indirect + github.com/ashanbrown/forbidigo v1.3.0 // indirect + github.com/ashanbrown/makezero v1.1.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bkielbasa/cyclop v1.2.0 // indirect + github.com/blizzy78/varnamelen v0.6.1 // indirect + github.com/bombsimon/wsl/v3 v3.3.0 // indirect + github.com/breml/bidichk v0.2.2 // indirect + github.com/breml/errchkjson v0.2.3 // indirect + github.com/butuzov/ireturn v0.1.1 // indirect + github.com/celestiaorg/go-leopard v0.1.0 // indirect + github.com/celestiaorg/merkletree v0.0.0-20210714075610-a84dc3ddbbe4 // indirect + github.com/cenkalti/backoff v2.2.1+incompatible // indirect + github.com/cespare/xxhash v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/charithe/durationcheck v0.0.9 // indirect + github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af // indirect + github.com/containerd/continuity v0.2.1 // indirect + github.com/daixiang0/gci v0.3.3 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/denis-tingaikin/go-header v0.4.3 // indirect + github.com/dgraph-io/badger/v2 v2.2007.2 // indirect + github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect + github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.4.0 // indirect + github.com/dustin/go-humanize v1.0.0 // indirect + github.com/esimonov/ifshort v1.0.4 // indirect + github.com/ettle/strcase v0.1.1 // indirect + github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect + github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect + github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/fatih/structtag v1.2.0 // indirect + github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/fzipp/gocyclo v0.4.0 // indirect + github.com/go-critic/go-critic v0.6.2 // indirect + github.com/go-toolsmith/astcast v1.0.0 // indirect + github.com/go-toolsmith/astcopy v1.0.0 // indirect + github.com/go-toolsmith/astequal v1.0.1 // indirect + github.com/go-toolsmith/astfmt v1.0.0 // indirect + github.com/go-toolsmith/astp v1.0.0 // indirect + github.com/go-toolsmith/strparse v1.0.0 // indirect + github.com/go-toolsmith/typep v1.0.2 // indirect + github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/gofrs/flock v0.8.1 // indirect + github.com/golang/snappy v0.0.3 // indirect + github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect + github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect + github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 // indirect + github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a // indirect + github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect + github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect + github.com/golangci/misspell v0.3.5 // indirect + github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2 // indirect + github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect + github.com/google/btree v1.0.0 // indirect + github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 // indirect + github.com/gostaticanalysis/analysisutil v0.7.1 // indirect + github.com/gostaticanalysis/comment v1.4.2 // indirect + github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect + github.com/gostaticanalysis/nilerr v0.1.1 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-version v1.4.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hexops/gotextdiff v1.0.3 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jgautheron/goconst v1.5.1 // indirect + github.com/jingyugao/rowserrcheck v1.1.1 // indirect + github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect + github.com/jmhodges/levigo v1.0.0 // indirect + github.com/julz/importas v0.1.0 // indirect + github.com/kisielk/errcheck v1.6.0 // indirect + github.com/kisielk/gotool v1.0.0 // indirect + github.com/kulti/thelper v0.5.1 // indirect + github.com/kunwardeep/paralleltest v1.0.3 // indirect + github.com/kyoh86/exportloopref v0.1.8 // indirect + github.com/ldez/gomoddirectives v0.2.2 // indirect + github.com/ldez/tagliatelle v0.3.1 // indirect + github.com/leonklingele/grouper v1.1.0 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/maratori/testpackage v1.0.1 // indirect + github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mbilski/exhaustivestruct v1.2.0 // indirect + github.com/mgechev/revive v1.1.4 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.4.3 // indirect + github.com/moricho/tparallel v0.2.1 // indirect + github.com/nakabonne/nestif v0.3.1 // indirect + github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect + github.com/nishanths/exhaustive v0.7.11 // indirect + github.com/nishanths/predeclared v0.2.1 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/opencontainers/runc v1.0.3 // indirect + github.com/pelletier/go-toml v1.9.4 // indirect + github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect + github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect + github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/polyfloyd/go-errorlint v0.0.0-20211125173453-6d6d39c5bb8b // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/quasilyte/go-ruleguard v0.3.15 // indirect + github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3 // indirect + github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect + github.com/ryancurrah/gomodguard v1.2.3 // indirect + github.com/ryanrolds/sqlclosecheck v0.3.0 // indirect + github.com/sanposhiho/wastedassign/v2 v2.0.6 // indirect + github.com/securego/gosec/v2 v2.10.0 // indirect + github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect + github.com/sirupsen/logrus v1.8.1 // indirect + github.com/sivchari/containedctx v1.0.2 // indirect + github.com/sivchari/tenv v1.4.7 // indirect + github.com/sonatard/noctx v0.0.1 // indirect + github.com/sourcegraph/go-diff v0.6.1 // indirect + github.com/spf13/afero v1.8.2 // indirect + github.com/spf13/cast v1.4.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect + github.com/stretchr/objx v0.1.1 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + github.com/sylvia7788/contextcheck v1.0.4 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect + github.com/tdakkota/asciicheck v0.1.1 // indirect + github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect + github.com/tetafro/godot v1.4.11 // indirect + github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 // indirect + github.com/tomarrell/wrapcheck/v2 v2.5.0 // indirect + github.com/tommy-muehle/go-mnd/v2 v2.5.0 // indirect + github.com/ultraware/funlen v0.0.3 // indirect + github.com/ultraware/whitespace v0.0.5 // indirect + github.com/uudashr/gocognit v1.0.5 // indirect + github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3 // indirect + github.com/yagipy/maintidx v1.0.0 // indirect + github.com/yeya24/promlinter v0.1.1-0.20210918184747-d757024714a1 // indirect + gitlab.com/bosi/decorder v0.2.1 // indirect + go.etcd.io/bbolt v1.3.6 // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.10 // indirect + golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect + google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac // indirect + google.golang.org/protobuf v1.28.0 // indirect + gopkg.in/ini.v1 v1.66.4 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + honnef.co/go/tools v0.2.2 // indirect + mvdan.cc/gofumpt v0.3.0 // indirect + mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect + mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect + mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5 // indirect +) diff --git a/networks/remote/integration.sh b/networks/remote/integration.sh index 0960f8962c..ec9b9de56f 100644 --- a/networks/remote/integration.sh +++ b/networks/remote/integration.sh @@ -10,8 +10,8 @@ sudo apt-get upgrade -y sudo apt-get install -y jq unzip python-pip software-properties-common make # get and unpack golang -curl -O https://dl.google.com/go/go1.16.5.linux-amd64.tar.gz -tar -xvf go1.16.5.linux-amd64.tar.gz +curl -O https://dl.google.com/go/go1.17.1.linux-amd64.tar.gz +tar -xvf go1.17.1.linux-amd64.tar.gz ## move binary and add to path mv go /usr/local diff --git a/node/node_test.go b/node/node_test.go index 3e52ce961b..cb1edc1b3a 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -345,7 +345,7 @@ func TestMaxTxsProposalBlockSize(t *testing.T) { // fill the mempool with one txs just below the maximum size txLength := int(types.MaxDataBytesNoEvidence(maxBytes, 1)) - tx := tmrand.Bytes(txLength - 4) // to account for the varint + tx := tmrand.Bytes(txLength - 4 - 5) // to account for the varint err = mp.CheckTx(context.Background(), tx, nil, mempool.TxInfo{}) assert.NoError(t, err) diff --git a/test/docker/Dockerfile b/test/docker/Dockerfile index 9110b4bf57..6d472db4cc 100644 --- a/test/docker/Dockerfile +++ b/test/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.16 +FROM golang:1.17 # Grab deps (jq, hexdump, xxd, killall) RUN apt-get update && \ diff --git a/test/e2e/docker/Dockerfile b/test/e2e/docker/Dockerfile index 260df23f3a..4e19fe9f8e 100644 --- a/test/e2e/docker/Dockerfile +++ b/test/e2e/docker/Dockerfile @@ -1,7 +1,7 @@ # We need to build in a Linux environment to support C libraries, e.g. RocksDB. # We use Debian instead of Alpine, so that we can use binary database packages # instead of spending time compiling them. -FROM golang:1.16 +FROM golang:1.17 RUN apt-get -qq update -y && apt-get -qq upgrade -y >/dev/null RUN apt-get -qq install -y libleveldb-dev librocksdb-dev >/dev/null diff --git a/types/block_test.go b/types/block_test.go index 1c762653b8..d026bfa0f1 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -213,21 +213,11 @@ func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) BlockID { var nilBytes []byte -// This follows RFC-6962, i.e. `echo -n '' | sha256sum` -var emptyBytes = []byte{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, - 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, - 0x78, 0x52, 0xb8, 0x55} - func TestNilHeaderHashDoesntCrash(t *testing.T) { assert.Equal(t, nilBytes, []byte((*Header)(nil).Hash())) assert.Equal(t, nilBytes, []byte((new(Header)).Hash())) } -func TestNilDataHashDoesntCrash(t *testing.T) { - assert.Equal(t, emptyBytes, []byte((*Data)(nil).Hash())) - assert.Equal(t, emptyBytes, []byte(new(Data).Hash())) -} - func TestCommit(t *testing.T) { lastID := makeBlockIDRandom() h := int64(3) @@ -649,12 +639,11 @@ func TestBlockProtoBuf(t *testing.T) { b1 := MakeBlock(h, []Tx{Tx([]byte{1})}, &Commit{Signatures: []CommitSig{}}, []Evidence{}) b1.ProposerAddress = tmrand.Bytes(crypto.AddressSize) - b2 := MakeBlock(h, []Tx{Tx([]byte{1})}, c1, []Evidence{}) - b2.ProposerAddress = tmrand.Bytes(crypto.AddressSize) evidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC) evi := NewMockDuplicateVoteEvidence(h, evidenceTime, "block-test-chain") - b2.Evidence = EvidenceData{Evidence: EvidenceList{evi}} - b2.EvidenceHash = b2.Evidence.Hash() + b2 := MakeBlock(h, []Tx{Tx([]byte{1})}, c1, []Evidence{evi}) + b2.ProposerAddress = tmrand.Bytes(crypto.AddressSize) + b2.Data.Evidence.ByteSize() b3 := MakeBlock(h, []Tx{}, c1, []Evidence{}) b3.ProposerAddress = tmrand.Bytes(crypto.AddressSize) @@ -691,8 +680,14 @@ func TestBlockProtoBuf(t *testing.T) { } func TestDataProtoBuf(t *testing.T) { - data := &Data{Txs: Txs{Tx([]byte{1}), Tx([]byte{2}), Tx([]byte{3})}} - data2 := &Data{Txs: Txs{}} + data := &Data{ + Txs: Txs{Tx([]byte{1}), Tx([]byte{2}), Tx([]byte{3})}, + Evidence: EvidenceData{Evidence: EvidenceList{}}, + } + data2 := &Data{ + Txs: Txs{}, + Evidence: EvidenceData{Evidence: EvidenceList{}}, + } testCases := []struct { msg string data1 *Data From d59c60e346a1420bb4379198521f6613c081183d Mon Sep 17 00:00:00 2001 From: nwhite1 Date: Wed, 22 Sep 2021 09:20:40 -0700 Subject: [PATCH 07/31] update with social links and careers section (#542) * update with social links and careers section * make careers section not a subsection of resources Co-authored-by: Ismail Khoffi Co-authored-by: Ismail Khoffi --- README.md | 43 +++++++++---------------------------------- 1 file changed, 9 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 0fc06a7ade..94413f587f 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,11 @@ ![banner](docs/tendermint-core-image.jpg) -[Byzantine-Fault Tolerant](https://en.wikipedia.org/wiki/Byzantine_fault_tolerance) -[State Machines](https://en.wikipedia.org/wiki/State_machine_replication). -Or [Blockchain](), for short. +![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/celestiaorg/celestia-core) +[![license](https://img.shields.io/github/license/tendermint/tendermint.svg)](https://github.com/celestiaorg/celestia-core/blob/master/LICENSE) +[![Community](https://img.shields.io/discord/638338779505229824?color=7389D8&label=chat%20on%20discord&logo=6A7EC2)](https://discord.gg/YsnTPcSfWQ) +[![Community](https://img.shields.io/discourse/topics?label=forum&server=https%3A%2F%2Fforum.celestia.org%2F)](https://forum.celestia.org/) +[![Community](https://img.shields.io/twitter/follow/CelestiaOrg?style=social)](https://twitter.com/CelestiaOrg) [![version](https://img.shields.io/github/tag/tendermint/tendermint.svg)](https://github.com/tendermint/tendermint/releases/latest) [![API Reference](https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667)](https://pkg.go.dev/github.com/tendermint/tendermint) @@ -111,36 +113,9 @@ in [UPGRADING.md](./UPGRADING.md). ### Tendermint Core -For details about the blockchain data structures and the p2p protocols, see the -[Tendermint specification](https://docs.tendermint.com/master/spec/). +For more information on Tendermint Core and pointers to documentation for Tendermint visit +this [repository](https://github.com/tendermint/tendermint). -For details on using the software, see the [documentation](/docs/) which is also -hosted at: +## Careers -### Tools - -Benchmarking is provided by [`tm-load-test`](https://github.com/informalsystems/tm-load-test). -Additional tooling can be found in [/docs/tools](/docs/tools). - -### Applications - -- [Cosmos SDK](http://github.com/cosmos/cosmos-sdk); a cryptocurrency application framework -- [Ethermint](http://github.com/cosmos/ethermint); Ethereum on Tendermint -- [Many more](https://tendermint.com/ecosystem) - -### Research - -- [The latest gossip on BFT consensus](https://arxiv.org/abs/1807.04938) -- [Master's Thesis on Tendermint](https://atrium.lib.uoguelph.ca/xmlui/handle/10214/9769) -- [Original Whitepaper: "Tendermint: Consensus Without Mining"](https://tendermint.com/static/docs/tendermint.pdf) -- [Tendermint Core Blog](https://medium.com/tendermint/tagged/tendermint-core) -- [Cosmos Blog](https://blog.cosmos.network/tendermint/home) - -## Join us! - -Tendermint Core is maintained by [Interchain GmbH](https://interchain.berlin). -If you'd like to work full-time on Tendermint Core, [we're hiring](https://interchain-gmbh.breezy.hr/p/682fb7e8a6f601-software-engineer-tendermint-core)! - -Funding for Tendermint Core development comes primarily from the [Interchain Foundation](https://interchain.io), -a Swiss non-profit. The Tendermint trademark is owned by [Tendermint Inc.](https://tendermint.com), the for-profit entity - that also maintains [tendermint.com](https://tendermint.com). +We are hiring Go engineers! Join us in building the future of blockchain scaling and interoperability. [Apply here](https://angel.co/company/celestialabs/jobs). From b44c3c6decd49531a0b8f5ee289a61392cf8b814 Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Fri, 17 Sep 2021 06:04:44 -0500 Subject: [PATCH 08/31] use celestia specific readme (#529) * Modify README.md - summarize LL and why it's useful - add banner - add further resources * Delet tokei.rs link seems down * Update README.md * Update community link * Update readme Go version badge. * Update community link * Update readme Go version badge. * Rebranding (#415) * new logo * Update README.md * review feedback * remove install + quick start sections as links are broken * finish rebrand and update golang Co-authored-by: Ismail Khoffi Co-authored-by: Mustafa Al-Bassam Co-authored-by: John Adler Co-authored-by: rene <41963722+renaynay@users.noreply.github.com> --- README.md | 121 ++++++++++++----------------------------- docs/celestia-logo.png | Bin 0 -> 40963 bytes 2 files changed, 35 insertions(+), 86 deletions(-) create mode 100644 docs/celestia-logo.png diff --git a/README.md b/README.md index 94413f587f..e723e941a0 100644 --- a/README.md +++ b/README.md @@ -1,115 +1,64 @@ -# Tendermint +# Celestia Core -![banner](docs/tendermint-core-image.jpg) + + + ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/celestiaorg/celestia-core) +[![Community](https://img.shields.io/badge/chat%20on-discord-orange?&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/YsnTPcSfWQ) [![license](https://img.shields.io/github/license/tendermint/tendermint.svg)](https://github.com/celestiaorg/celestia-core/blob/master/LICENSE) -[![Community](https://img.shields.io/discord/638338779505229824?color=7389D8&label=chat%20on%20discord&logo=6A7EC2)](https://discord.gg/YsnTPcSfWQ) -[![Community](https://img.shields.io/discourse/topics?label=forum&server=https%3A%2F%2Fforum.celestia.org%2F)](https://forum.celestia.org/) -[![Community](https://img.shields.io/twitter/follow/CelestiaOrg?style=social)](https://twitter.com/CelestiaOrg) -[![version](https://img.shields.io/github/tag/tendermint/tendermint.svg)](https://github.com/tendermint/tendermint/releases/latest) -[![API Reference](https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667)](https://pkg.go.dev/github.com/tendermint/tendermint) -[![Go version](https://img.shields.io/badge/go-1.16-blue.svg)](https://github.com/moovweb/gvm) -[![Discord chat](https://img.shields.io/discord/669268347736686612.svg)](https://discord.gg/cosmosnetwork) -[![license](https://img.shields.io/github/license/tendermint/tendermint.svg)](https://github.com/tendermint/tendermint/blob/master/LICENSE) -[![tendermint/tendermint](https://tokei.rs/b1/github/tendermint/tendermint?category=lines)](https://github.com/tendermint/tendermint) -[![Sourcegraph](https://sourcegraph.com/github.com/tendermint/tendermint/-/badge.svg)](https://sourcegraph.com/github.com/tendermint/tendermint?badge) +Celestia Core will power the Celestia main chain by leveraging Tendermint. -| Branch | Tests | Coverage | Linting | -|--------|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------| -| master | ![Tests](https://github.com/tendermint/tendermint/workflows/Tests/badge.svg?branch=master) | [![codecov](https://codecov.io/gh/tendermint/tendermint/branch/master/graph/badge.svg)](https://codecov.io/gh/tendermint/tendermint) | ![Lint](https://github.com/tendermint/tendermint/workflows/Lint/badge.svg) | +Celestia itself is a scale-out data availability-focused minimal blockchain. +It allows users to post arbitrary data on the chain, as well as define their own execution layers. +This data is ordered on-chain but not executed. This allows for the first scalable data layer for +decentralised applications, including optimistic rollup sidechains. Additionally, this design allows developers to +define their own execution environments. -Tendermint Core is a Byzantine Fault Tolerant (BFT) middleware that takes a state transition machine - written in any programming language - and securely replicates it on many machines. +Read this [blog post](https://blog.celestia.org/celestia-a-scalable-general-purpose-data-availability-layer-for-decentralized-apps-and-trust-minimized-sidechains/) +to learn more about what we are building. -For protocol details, see [the specification](https://github.com/tendermint/spec). - -For detailed analysis of the consensus protocol, including safety and liveness proofs, -see our recent paper, "[The latest gossip on BFT consensus](https://arxiv.org/abs/1807.04938)". - -## Releases - -Please do not depend on master as your production branch. Use [releases](https://github.com/tendermint/tendermint/releases) instead. - -Tendermint has been in the production of private and public environments, most notably the blockchains of the Cosmos Network. we haven't released v1.0 yet since we are making breaking changes to the protocol and the APIs. -See below for more details about [versioning](#versioning). - -In any case, if you intend to run Tendermint in production, we're happy to help. You can -contact us [over email](mailto:hello@interchain.berlin) or [join the chat](https://discord.gg/cosmosnetwork). - -## Security - -To report a security vulnerability, see our [bug bounty program](https://hackerone.com/cosmos). -For examples of the kinds of bugs we're looking for, see [our security policy](SECURITY.md). +## Documentation -We also maintain a dedicated mailing list for security updates. We will only ever use this mailing list -to notify you of vulnerabilities and fixes in Tendermint Core. You can subscribe [here](http://eepurl.com/gZ5hQD). +The original [whitepaper](https://arxiv.org/abs/1905.09274) and the +[specification](https://github.com/celestiaorg/celestia-specs) which we are currently wrapping up can give you +a more detailed overview what to expect from this repository. -## Minimum requirements +### Minimum requirements | Requirement | Notes | |-------------|------------------| -| Go version | Go1.16 or higher | - -## Documentation - -Complete documentation can be found on the [website](https://docs.tendermint.com/master/). - -### Install - -See the [install instructions](/docs/introduction/install.md). - -### Quick Start - -- [Single node](/docs/introduction/quick-start.md) -- [Local cluster using docker-compose](/docs/tools/docker-compose.md) -- [Remote cluster using Terraform and Ansible](/docs/tools/terraform-and-ansible.md) -- [Join the Cosmos testnet](https://cosmos.network/testnet) +| Go version | Go1.17 or higher | ## Contributing -Please abide by the [Code of Conduct](CODE_OF_CONDUCT.md) in all interactions. - Before contributing to the project, please take a look at the [contributing guidelines](CONTRIBUTING.md) -and the [style guide](STYLE_GUIDE.md). You may also find it helpful to read the -[specifications](https://github.com/tendermint/spec), watch the [Developer Sessions](/docs/DEV_SESSIONS.md), -and familiarize yourself with our -[Architectural Decision Records](https://github.com/tendermint/tendermint/tree/master/docs/architecture). +and the [style guide](STYLE_GUIDE.md). + +Join the community at [Telegram](https://t.me/CelestiaCommunity) or jump onto the [Forum](https://forum.celestia.org/) +to get more involved into discussions. + +Learn more by reading the code and the +[specifications](https://github.com/celestiaorg/celestia-specs). ## Versioning ### Semantic Versioning -Tendermint uses [Semantic Versioning](http://semver.org/) to determine when and how the version changes. +Celestia Core uses [Semantic Versioning](http://semver.org/) to determine when and how the version changes. According to SemVer, anything in the public API can change at any time before version 1.0.0 -To provide some stability to users of 0.X.X versions of Tendermint, the MINOR version is used -to signal breaking changes across Tendermint's API. This API includes all -publicly exposed types, functions, and methods in non-internal Go packages as well as -the types and methods accessible via the Tendermint RPC interface. - -Breaking changes to these public APIs will be documented in the CHANGELOG. - -### Upgrades - -In an effort to avoid accumulating technical debt prior to 1.0.0, -we do not guarantee that breaking changes (ie. bumps in the MINOR version) -will work with existing Tendermint blockchains. In these cases you will -have to start a new blockchain, or write something custom to get the old -data into the new chain. However, any bump in the PATCH version should be -compatible with existing blockchain histories. - - -For more information on upgrading, see [UPGRADING.md](./UPGRADING.md). - -### Supported Versions +## Resources -Because we are a small core team, we only ship patch updates, including security updates, -to the most recent minor release and the second-most recent minor release. Consequently, -we strongly recommend keeping Tendermint up-to-date. Upgrading instructions can be found -in [UPGRADING.md](./UPGRADING.md). +### Celestia (formerly LazyLedger) -## Resources +- [Ethereum research post](https://ethresear.ch/t/a-data-availability-blockchain-with-sub-linear-full-block-validation/5503) +- [Academic paper](https://arxiv.org/abs/1905.09274) +- [Blog](https://blog.celestia.org) +- [Project web site](https://celestia.org) +- [Academic prototype](https://github.com/celestiaorg/lazyledger-prototype) +- [Follow Celestia on Twitter](https://twitter.com/CelestiaOrg) ### Tendermint Core diff --git a/docs/celestia-logo.png b/docs/celestia-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..dce8b0b34d2ee13ed1e5bf6436cd4f5fca3d28be GIT binary patch literal 40963 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

9e@by)1D@Qf#^*qa8RgBjGV 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 literal 0 HcmV?d00001 From 7685bac265d28f80ab9ef1ec8ae25f5825f20c10 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 27 Apr 2022 18:57:43 -0500 Subject: [PATCH 09/31] change makeblock to accept messages Add messages when converting to protobuf version of block data (#580) * export parsing functions * add messages to proto version of data * remove redundant test * remove redundant test --- internal/evidence/pool_test.go | 2 +- internal/mempool/v0/clist_mempool.go | 6 + internal/mempool/v0/clist_mempool_test.go | 23 ++ internal/state/execution.go | 2 +- internal/state/helpers_test.go | 2 +- internal/state/state.go | 3 +- internal/state/test/factory/block.go | 3 +- internal/state/validation_test.go | 2 +- proto/tendermint/blocksync/message_test.go | 2 +- proto/tendermint/types/types.pb.go | 445 ++++++++++++++++----- proto/tendermint/types/types.proto | 7 + types/block.go | 6 +- types/block_test.go | 22 +- types/event_bus_test.go | 4 +- types/tx.go | 27 ++ 15 files changed, 427 insertions(+), 129 deletions(-) diff --git a/internal/evidence/pool_test.go b/internal/evidence/pool_test.go index f38c09e02e..2439fedcd7 100644 --- a/internal/evidence/pool_test.go +++ b/internal/evidence/pool_test.go @@ -202,7 +202,7 @@ func TestEvidencePoolUpdate(t *testing.T) { evidenceChainID, ) lastCommit := makeCommit(height, val.PrivKey.PubKey().Address()) - block := types.MakeBlock(height+1, []types.Tx{}, lastCommit, []types.Evidence{ev}) + block := types.MakeBlock(height+1, []types.Tx{}, []types.Evidence{ev}, nil, lastCommit) // update state (partially) state.LastBlockHeight = height + 1 diff --git a/internal/mempool/v0/clist_mempool.go b/internal/mempool/v0/clist_mempool.go index 0a12c70009..eb82817a74 100644 --- a/internal/mempool/v0/clist_mempool.go +++ b/internal/mempool/v0/clist_mempool.go @@ -626,6 +626,12 @@ func (mem *CListMempool) Update( // https://github.com/tendermint/tendermint/issues/3322. if e, ok := mem.txsMap.Load(tx.Key()); ok { mem.removeTx(tx, e.(*clist.CElement), false) + // see if the transaction is a child transaction of a some parent + // transaction that exists in the mempool + } else if parentHash, _, isChild := types.DecodeChildTx(tx); isChild { + var parentKey [TxKeySize]byte + copy(parentKey[:], parentHash) + mem.RemoveTxByKey(parentKey, false) } } diff --git a/internal/mempool/v0/clist_mempool_test.go b/internal/mempool/v0/clist_mempool_test.go index a68d42f7d2..bc8c584cd7 100644 --- a/internal/mempool/v0/clist_mempool_test.go +++ b/internal/mempool/v0/clist_mempool_test.go @@ -223,6 +223,29 @@ func TestMempoolUpdate(t *testing.T) { err = mp.CheckTx(context.Background(), []byte{0x03}, nil, mempool.TxInfo{}) require.NoError(t, err) } + + // 4. Removes a parent transaction after receiving a child transaction in the update + { + mempool.Flush() + parentTx := []byte{1, 2, 3, 4} + childTx := []byte{1, 2} + parentHash := sha256.Sum256(parentTx) + + // create the wrapped child transaction + wTx, err := types.WrapChildTx(parentHash[:], childTx) + require.NoError(t, err) + + // add the parent transaction to the mempool + err = mempool.CheckTx(parentTx, nil, TxInfo{}) + require.NoError(t, err) + + // remove the parent from the mempool using the wrapped child tx + err = mempool.Update(1, []types.Tx{wTx}, abciResponses(1, abci.CodeTypeOK), nil, nil) + require.NoError(t, err) + + assert.Zero(t, mempool.Size()) + + } } func TestMempoolUpdateDoesNotPanicWhenApplicationMissedTx(t *testing.T) { diff --git a/internal/state/execution.go b/internal/state/execution.go index e3dc80dca9..69851c19bc 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -115,7 +115,7 @@ func (blockExec *BlockExecutor) CreateProposalBlock( txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas) - return state.MakeBlock(height, txs, commit, evidence, proposerAddr) + return state.MakeBlock(height, txs, commit, evidence, nil, proposerAddr) } // ValidateBlock validates the given block against the given state. diff --git a/internal/state/helpers_test.go b/internal/state/helpers_test.go index 0cedebb008..b4f4708593 100644 --- a/internal/state/helpers_test.go +++ b/internal/state/helpers_test.go @@ -58,7 +58,7 @@ func makeAndCommitGoodBlock( func makeAndApplyGoodBlock(state sm.State, height int64, lastCommit *types.Commit, proposerAddr []byte, blockExec *sm.BlockExecutor, evidence []types.Evidence) (sm.State, types.BlockID, error) { - block, _ := state.MakeBlock(height, factory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) + block, _ := state.MakeBlock(height, factory.MakeTenTxs(height), lastCommit, evidence, nil, proposerAddr) if err := blockExec.ValidateBlock(state, block); err != nil { return state, types.BlockID{}, err } diff --git a/internal/state/state.go b/internal/state/state.go index 6a1ea3c65b..ea29d46cde 100644 --- a/internal/state/state.go +++ b/internal/state/state.go @@ -257,11 +257,12 @@ func (state State) MakeBlock( txs []types.Tx, commit *types.Commit, evidence []types.Evidence, + messages []types.Message, proposerAddress []byte, ) (*types.Block, *types.PartSet) { // Build base block with block data. - block := types.MakeBlock(height, txs, commit, evidence) + block := types.MakeBlock(height, txs, evidence, messages, commit) // Set time. var timestamp time.Time diff --git a/internal/state/test/factory/block.go b/internal/state/test/factory/block.go index dfcf5ebd92..244766e748 100644 --- a/internal/state/test/factory/block.go +++ b/internal/state/test/factory/block.go @@ -41,6 +41,7 @@ func MakeBlock(state sm.State, height int64, c *types.Commit) *types.Block { factory.MakeTenTxs(state.LastBlockHeight), c, nil, + nil, state.Validators.GetProposer().Address, ) return block @@ -61,5 +62,5 @@ func makeBlockAndPartSet(state sm.State, lastBlock *types.Block, lastBlockMeta * lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) } - return state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address) + return state.MakeBlock(height, []types.Tx{}, lastCommit, nil, nil, state.Validators.GetProposer().Address) } diff --git a/internal/state/validation_test.go b/internal/state/validation_test.go index eb0cebbb73..85f7b928cc 100644 --- a/internal/state/validation_test.go +++ b/internal/state/validation_test.go @@ -278,7 +278,7 @@ func TestValidateBlockEvidence(t *testing.T) { evidence = append(evidence, newEv) currentBytes += int64(len(newEv.Bytes())) } - block, _ := state.MakeBlock(height, testfactory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) + block, _ := state.MakeBlock(height, testfactory.MakeTenTxs(height), lastCommit, evidence, nil, proposerAddr) err := blockExec.ValidateBlock(state, block) if assert.Error(t, err) { _, ok := err.(*types.ErrEvidenceOverflow) diff --git a/proto/tendermint/blocksync/message_test.go b/proto/tendermint/blocksync/message_test.go index 5642527b72..0ea7e43a09 100644 --- a/proto/tendermint/blocksync/message_test.go +++ b/proto/tendermint/blocksync/message_test.go @@ -85,7 +85,7 @@ func TestStatusResponse_Validate(t *testing.T) { } func TestBlockchainMessageVectors(t *testing.T) { - block := types.MakeBlock(int64(3), []types.Tx{types.Tx("Hello World")}, nil, nil) + block := types.MakeBlock(int64(3), []types.Tx{types.Tx("Hello World")}, nil, nil, nil) block.Version.Block = 11 // overwrite updated protocol version bpb, err := block.ToProto() diff --git a/proto/tendermint/types/types.pb.go b/proto/tendermint/types/types.pb.go index 7d34b8a5ce..f31dd6aef8 100644 --- a/proto/tendermint/types/types.pb.go +++ b/proto/tendermint/types/types.pb.go @@ -1441,6 +1441,60 @@ func (m *TxProof) GetProof() *crypto.Proof { return nil } +// ChildTx wraps a transaction that was derived from a parent transaction. This +// allows for removal of the parent transaction from the mempool. +type ChildTx struct { + ParentTxHash []byte `protobuf:"bytes,1,opt,name=parent_tx_hash,json=parentTxHash,proto3" json:"parent_tx_hash,omitempty"` + Tx []byte `protobuf:"bytes,2,opt,name=tx,proto3" json:"tx,omitempty"` +} + +func (m *ChildTx) Reset() { *m = ChildTx{} } +func (m *ChildTx) String() string { return proto.CompactTextString(m) } +func (*ChildTx) ProtoMessage() {} +func (*ChildTx) Descriptor() ([]byte, []int) { + return fileDescriptor_d3a6e55e2345de56, []int{19} +} +func (m *ChildTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ChildTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ChildTx.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 *ChildTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChildTx.Merge(m, src) +} +func (m *ChildTx) XXX_Size() int { + return m.Size() +} +func (m *ChildTx) XXX_DiscardUnknown() { + xxx_messageInfo_ChildTx.DiscardUnknown(m) +} + +var xxx_messageInfo_ChildTx proto.InternalMessageInfo + +func (m *ChildTx) GetParentTxHash() []byte { + if m != nil { + return m.ParentTxHash + } + return nil +} + +func (m *ChildTx) GetTx() []byte { + if m != nil { + return m.Tx + } + return nil +} + func init() { proto.RegisterEnum("tendermint.types.BlockIDFlag", BlockIDFlag_name, BlockIDFlag_value) proto.RegisterEnum("tendermint.types.SignedMsgType", SignedMsgType_name, SignedMsgType_value) @@ -1463,119 +1517,122 @@ func init() { proto.RegisterType((*LightBlock)(nil), "tendermint.types.LightBlock") proto.RegisterType((*BlockMeta)(nil), "tendermint.types.BlockMeta") proto.RegisterType((*TxProof)(nil), "tendermint.types.TxProof") + proto.RegisterType((*ChildTx)(nil), "tendermint.types.ChildTx") } func init() { proto.RegisterFile("tendermint/types/types.proto", fileDescriptor_d3a6e55e2345de56) } var fileDescriptor_d3a6e55e2345de56 = []byte{ - // 1710 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcd, 0x73, 0x1b, 0x49, - 0x15, 0xf7, 0x48, 0xb2, 0x3e, 0x9e, 0x24, 0x5b, 0x1e, 0x9c, 0x44, 0x56, 0x12, 0x59, 0x88, 0x82, - 0xf5, 0x7e, 0x20, 0x87, 0x2c, 0xc5, 0x47, 0x15, 0x50, 0x2b, 0xd9, 0xde, 0x58, 0xac, 0x2d, 0x8b, - 0x91, 0x36, 0x14, 0x5c, 0xa6, 0x5a, 0x9a, 0x8e, 0x34, 0x64, 0x34, 0x33, 0x4c, 0xb7, 0xbc, 0x76, - 0xfe, 0x02, 0xca, 0xa7, 0x9c, 0xb8, 0xf9, 0x04, 0x07, 0xee, 0xfc, 0x03, 0x14, 0xa7, 0xbd, 0x50, - 0xb5, 0x37, 0xb8, 0x10, 0xa8, 0x84, 0xa2, 0xf8, 0x33, 0xa8, 0x7e, 0xdd, 0x33, 0x1a, 0x59, 0x52, - 0x48, 0xa5, 0x52, 0x5c, 0x54, 0x33, 0xef, 0xfd, 0x5e, 0xf7, 0xeb, 0xdf, 0xfb, 0xea, 0x11, 0xdc, - 0xe3, 0xd4, 0xb5, 0x68, 0x30, 0xb1, 0x5d, 0xbe, 0xcf, 0x2f, 0x7d, 0xca, 0xe4, 0x6f, 0xc3, 0x0f, - 0x3c, 0xee, 0xe9, 0xa5, 0x99, 0xb6, 0x81, 0xf2, 0xca, 0xf6, 0xc8, 0x1b, 0x79, 0xa8, 0xdc, 0x17, - 0x4f, 0x12, 0x57, 0xd9, 0x1d, 0x79, 0xde, 0xc8, 0xa1, 0xfb, 0xf8, 0x36, 0x98, 0x3e, 0xd9, 0xe7, - 0xf6, 0x84, 0x32, 0x4e, 0x26, 0xbe, 0x02, 0xdc, 0x8f, 0x6d, 0x33, 0x0c, 0x2e, 0x7d, 0xee, 0x09, - 0xac, 0xf7, 0x44, 0xa9, 0xab, 0x31, 0xf5, 0x39, 0x0d, 0x98, 0xed, 0xb9, 0x71, 0x3f, 0x2a, 0xb5, - 0x05, 0x2f, 0xcf, 0x89, 0x63, 0x5b, 0x84, 0x7b, 0x81, 0x44, 0xd4, 0x7f, 0x08, 0xc5, 0x2e, 0x09, - 0x78, 0x8f, 0xf2, 0x63, 0x4a, 0x2c, 0x1a, 0xe8, 0xdb, 0xb0, 0xce, 0x3d, 0x4e, 0x9c, 0xb2, 0x56, - 0xd3, 0xf6, 0x8a, 0x86, 0x7c, 0xd1, 0x75, 0x48, 0x8d, 0x09, 0x1b, 0x97, 0x13, 0x35, 0x6d, 0xaf, - 0x60, 0xe0, 0x73, 0x7d, 0x0c, 0x29, 0x61, 0x2a, 0x2c, 0x6c, 0xd7, 0xa2, 0x17, 0xa1, 0x05, 0xbe, - 0x08, 0xe9, 0xe0, 0x92, 0x53, 0xa6, 0x4c, 0xe4, 0x8b, 0xfe, 0x5d, 0x58, 0x47, 0xff, 0xcb, 0xc9, - 0x9a, 0xb6, 0x97, 0x7f, 0x58, 0x6e, 0xc4, 0x88, 0x92, 0xe7, 0x6b, 0x74, 0x85, 0xbe, 0x95, 0xfa, - 0xf2, 0xc5, 0xee, 0x9a, 0x21, 0xc1, 0x75, 0x07, 0x32, 0x2d, 0xc7, 0x1b, 0x3e, 0x6d, 0x1f, 0x46, - 0x8e, 0x68, 0x33, 0x47, 0xf4, 0x53, 0xd8, 0xf4, 0x49, 0xc0, 0x4d, 0x46, 0xb9, 0x39, 0xc6, 0x53, - 0xe0, 0xa6, 0xf9, 0x87, 0xbb, 0x8d, 0x9b, 0x71, 0x68, 0xcc, 0x1d, 0x56, 0xed, 0x52, 0xf4, 0xe3, - 0xc2, 0xfa, 0xbf, 0x53, 0x90, 0x56, 0x64, 0xfc, 0x18, 0x32, 0x8a, 0x56, 0xdc, 0x30, 0xff, 0xf0, - 0x7e, 0x7c, 0x45, 0xa5, 0x6a, 0x1c, 0x78, 0x2e, 0xa3, 0x2e, 0x9b, 0x32, 0xb5, 0x5e, 0x68, 0xa3, - 0x7f, 0x0b, 0xb2, 0xc3, 0x31, 0xb1, 0x5d, 0xd3, 0xb6, 0xd0, 0xa3, 0x5c, 0x2b, 0xff, 0xf2, 0xc5, - 0x6e, 0xe6, 0x40, 0xc8, 0xda, 0x87, 0x46, 0x06, 0x95, 0x6d, 0x4b, 0xbf, 0x0d, 0xe9, 0x31, 0xb5, - 0x47, 0x63, 0x8e, 0xb4, 0x24, 0x0d, 0xf5, 0xa6, 0xff, 0x00, 0x52, 0x22, 0x21, 0xca, 0x29, 0xdc, - 0xbb, 0xd2, 0x90, 0xd9, 0xd2, 0x08, 0xb3, 0xa5, 0xd1, 0x0f, 0xb3, 0xa5, 0x95, 0x15, 0x1b, 0x3f, - 0xff, 0xc7, 0xae, 0x66, 0xa0, 0x85, 0x7e, 0x00, 0x45, 0x87, 0x30, 0x6e, 0x0e, 0x04, 0x6d, 0x62, - 0xfb, 0x75, 0x5c, 0x62, 0x67, 0x91, 0x10, 0x45, 0xac, 0x72, 0x3d, 0x2f, 0xac, 0xa4, 0xc8, 0xd2, - 0xf7, 0xa0, 0x84, 0x8b, 0x0c, 0xbd, 0xc9, 0xc4, 0xe6, 0x26, 0xf2, 0x9e, 0x46, 0xde, 0x37, 0x84, - 0xfc, 0x00, 0xc5, 0xc7, 0x22, 0x02, 0x77, 0x21, 0x67, 0x11, 0x4e, 0x24, 0x24, 0x83, 0x90, 0xac, - 0x10, 0xa0, 0xf2, 0x3d, 0xd8, 0x8c, 0xb2, 0x8e, 0x49, 0x48, 0x56, 0xae, 0x32, 0x13, 0x23, 0xf0, - 0x01, 0x6c, 0xbb, 0xf4, 0x82, 0x9b, 0x37, 0xd1, 0x39, 0x44, 0xeb, 0x42, 0xf7, 0x78, 0xde, 0xe2, - 0x9b, 0xb0, 0x31, 0x0c, 0xc9, 0x97, 0x58, 0x40, 0x6c, 0x31, 0x92, 0x22, 0x6c, 0x07, 0xb2, 0xc4, - 0xf7, 0x25, 0x20, 0x8f, 0x80, 0x0c, 0xf1, 0x7d, 0x54, 0x7d, 0x00, 0x5b, 0x78, 0xc6, 0x80, 0xb2, - 0xa9, 0xc3, 0xd5, 0x22, 0x05, 0xc4, 0x6c, 0x0a, 0x85, 0x21, 0xe5, 0x88, 0xfd, 0x06, 0x14, 0xe9, - 0xb9, 0x6d, 0x51, 0x77, 0x48, 0x25, 0xae, 0x88, 0xb8, 0x42, 0x28, 0x44, 0xd0, 0xfb, 0x50, 0xf2, - 0x03, 0xcf, 0xf7, 0x18, 0x0d, 0x4c, 0x62, 0x59, 0x01, 0x65, 0xac, 0xbc, 0x21, 0xd7, 0x0b, 0xe5, - 0x4d, 0x29, 0xae, 0xbf, 0xd0, 0x20, 0x75, 0x48, 0x38, 0xd1, 0x4b, 0x90, 0xe4, 0x17, 0xac, 0xac, - 0xd5, 0x92, 0x7b, 0x05, 0x43, 0x3c, 0xea, 0x9f, 0x40, 0x36, 0x5c, 0x55, 0x95, 0x4a, 0x75, 0x31, - 0x74, 0x47, 0x0a, 0x71, 0x62, 0x33, 0xae, 0xe2, 0x17, 0x59, 0xe9, 0x3f, 0x82, 0xec, 0x84, 0x32, - 0x46, 0x46, 0x94, 0x45, 0xf9, 0xb3, 0xb0, 0xc2, 0xa9, 0x42, 0x84, 0xd6, 0xa1, 0x85, 0x08, 0x85, - 0x17, 0xd8, 0x23, 0xdb, 0x25, 0x8e, 0xc9, 0x7e, 0x3d, 0x25, 0x01, 0x35, 0x99, 0xfd, 0x8c, 0x62, - 0x1a, 0xa5, 0x0c, 0x3d, 0xd4, 0xf5, 0x50, 0xd5, 0xb3, 0x9f, 0xd1, 0xa8, 0x30, 0xd3, 0xb1, 0x0e, - 0xf1, 0x3c, 0x01, 0xb7, 0x0e, 0xa7, 0xbe, 0x63, 0x0f, 0x09, 0xa7, 0x8f, 0x3d, 0x4e, 0x43, 0x8f, - 0xf5, 0x6f, 0x43, 0xfa, 0xdc, 0xe3, 0xd4, 0x24, 0xaa, 0xae, 0x6e, 0x2f, 0xfa, 0x26, 0xf0, 0xc6, - 0xba, 0x40, 0x35, 0x23, 0xf8, 0x40, 0x15, 0xf6, 0x6b, 0xe1, 0x2d, 0xfd, 0x23, 0xd0, 0xb1, 0x6d, - 0x99, 0xe7, 0x1e, 0xb7, 0xdd, 0x91, 0xe9, 0x7b, 0x5f, 0xd0, 0x40, 0xd5, 0x56, 0x09, 0x35, 0x8f, - 0x51, 0xd1, 0x15, 0xf2, 0xb9, 0xfc, 0x54, 0xd0, 0x14, 0x42, 0x67, 0xf9, 0x29, 0x81, 0x2d, 0xc8, - 0x45, 0xfd, 0x59, 0x15, 0xd4, 0x9b, 0xd5, 0xe4, 0xcc, 0xac, 0xfe, 0x97, 0x04, 0xec, 0x9c, 0x88, - 0xe2, 0x3e, 0x70, 0x6c, 0xea, 0xf2, 0x26, 0xe7, 0x64, 0xf8, 0x34, 0xa2, 0xa5, 0x0d, 0x5b, 0x43, - 0xcf, 0x7d, 0xe2, 0xd8, 0x43, 0xf4, 0x1b, 0xab, 0x57, 0x31, 0x74, 0x6f, 0xf1, 0xc8, 0xb8, 0x0e, - 0x16, 0xab, 0x51, 0x8a, 0x99, 0xa1, 0x44, 0x24, 0xab, 0xa8, 0x5b, 0xcf, 0x35, 0x55, 0x6b, 0x49, - 0xe0, 0x99, 0x0a, 0x52, 0x78, 0x2c, 0x1b, 0x4c, 0x07, 0xb6, 0x07, 0x97, 0xcf, 0x88, 0xcb, 0x6d, - 0x97, 0xc6, 0xca, 0xae, 0x9c, 0xac, 0x25, 0xf7, 0xf2, 0x0f, 0xef, 0x2e, 0x61, 0x39, 0xc4, 0x18, - 0x5f, 0x8b, 0x0c, 0x67, 0x35, 0xb9, 0x82, 0xf8, 0xd4, 0x0a, 0xe2, 0xdf, 0x05, 0x9f, 0xff, 0xd2, - 0x20, 0x1b, 0xd1, 0x47, 0xe0, 0x8e, 0x15, 0xa6, 0x9b, 0x89, 0x09, 0x13, 0x15, 0x91, 0x24, 0xf1, - 0xbd, 0xc5, 0x13, 0x2d, 0xcd, 0xcf, 0xe3, 0x35, 0xe3, 0x96, 0xb5, 0x34, 0x71, 0x5d, 0xb8, 0xe7, - 0x08, 0xea, 0xcc, 0x21, 0xc6, 0xcf, 0x24, 0x18, 0xc0, 0xd9, 0x3e, 0x32, 0x3f, 0x3f, 0x5c, 0x11, - 0xac, 0x65, 0x41, 0x3f, 0x5e, 0x33, 0x76, 0x9c, 0x55, 0xca, 0xd6, 0x3a, 0x24, 0xd9, 0x74, 0x52, - 0x3f, 0x81, 0x42, 0xbc, 0xda, 0x45, 0x75, 0xc7, 0x8e, 0x96, 0x5c, 0x5e, 0xdd, 0xd1, 0x22, 0x37, - 0x7a, 0x43, 0xfd, 0xa7, 0x90, 0x0d, 0x2b, 0x5f, 0xff, 0x09, 0x14, 0xc3, 0xaa, 0x37, 0x1d, 0x9b, - 0x71, 0xb5, 0xdc, 0xce, 0xca, 0x66, 0x61, 0x14, 0x42, 0xbc, 0xf0, 0xa4, 0xfe, 0x09, 0x64, 0x94, - 0x42, 0xff, 0x3a, 0x14, 0x5c, 0x32, 0xa1, 0xcc, 0x27, 0x43, 0x2a, 0x66, 0x8e, 0x9c, 0xd1, 0xf9, - 0x48, 0xd6, 0xb6, 0x44, 0x97, 0x10, 0x73, 0x21, 0xbc, 0x47, 0x88, 0xe7, 0xfa, 0x7f, 0x12, 0x90, - 0x12, 0x1c, 0xeb, 0x1f, 0x43, 0x4a, 0xec, 0x84, 0x76, 0x1b, 0xcb, 0x86, 0x77, 0xcf, 0x1e, 0xb9, - 0xd4, 0x3a, 0x65, 0xa3, 0xfe, 0xa5, 0x4f, 0x0d, 0x04, 0xc7, 0x66, 0x67, 0x62, 0x6e, 0x76, 0x6e, - 0xc3, 0x7a, 0xe0, 0x4d, 0x5d, 0x0b, 0xcb, 0x7e, 0xdd, 0x90, 0x2f, 0xfa, 0x11, 0x64, 0xa3, 0x91, - 0x98, 0xfa, 0x5f, 0x23, 0x71, 0x53, 0xd0, 0x26, 0x06, 0xb6, 0x12, 0x18, 0x99, 0x81, 0x9a, 0x8c, - 0xef, 0x20, 0x73, 0xf5, 0x0f, 0x61, 0x6b, 0xd6, 0x76, 0xc2, 0x49, 0x21, 0xbb, 0x67, 0x29, 0x52, - 0xa8, 0x51, 0x31, 0xdf, 0xa3, 0xe4, 0x6d, 0x2b, 0x83, 0xe7, 0x9a, 0xf5, 0xa8, 0x36, 0x5e, 0xbb, - 0xee, 0x41, 0x8e, 0xd9, 0x23, 0x97, 0xf0, 0x69, 0x40, 0xd5, 0x98, 0x9d, 0x09, 0xea, 0x7f, 0xd2, - 0x20, 0x2d, 0xc7, 0x76, 0x8c, 0x37, 0x6d, 0x39, 0x6f, 0x89, 0x55, 0xbc, 0x25, 0xdf, 0x9e, 0xb7, - 0x26, 0x40, 0xe4, 0x8c, 0x18, 0x4b, 0x2b, 0xba, 0x8c, 0x74, 0xb1, 0x67, 0x8f, 0x54, 0xe6, 0xc6, - 0x8c, 0xea, 0x7f, 0xd7, 0x20, 0x17, 0xe9, 0xf5, 0x26, 0x14, 0x43, 0xbf, 0xcc, 0x27, 0x0e, 0x19, - 0xa9, 0xdc, 0xb9, 0xbf, 0xd2, 0xb9, 0x4f, 0x1d, 0x32, 0x32, 0xf2, 0xca, 0x1f, 0xf1, 0xb2, 0x3c, - 0x0e, 0x89, 0x15, 0x71, 0x98, 0x0b, 0x7c, 0xf2, 0xed, 0x02, 0x3f, 0x17, 0xa2, 0xd4, 0xcd, 0x10, - 0xfd, 0x31, 0x01, 0xd9, 0x2e, 0x5e, 0x14, 0x88, 0xf3, 0xff, 0xa8, 0x88, 0xbb, 0x90, 0xf3, 0x3d, - 0xc7, 0x94, 0x9a, 0x14, 0x6a, 0xb2, 0xbe, 0xe7, 0x18, 0x0b, 0x61, 0x5f, 0x7f, 0x47, 0xe5, 0x92, - 0x7e, 0x07, 0xac, 0x65, 0x6e, 0xb2, 0x16, 0x40, 0x41, 0x52, 0xa1, 0x2e, 0xee, 0x0f, 0x04, 0x07, - 0xf8, 0x25, 0xa0, 0x2d, 0x7e, 0x68, 0x48, 0xb7, 0x25, 0xd2, 0x50, 0x38, 0x61, 0x21, 0xef, 0xb9, - 0xaa, 0x85, 0x97, 0x57, 0xa5, 0xa5, 0xa1, 0x70, 0xf5, 0xdf, 0x6a, 0x00, 0xb3, 0x11, 0x2c, 0xae, - 0xdc, 0x0c, 0x5d, 0x30, 0xe7, 0x76, 0xae, 0xae, 0x0a, 0x9a, 0xda, 0xbf, 0xc0, 0xe2, 0x7e, 0x1f, - 0x40, 0x71, 0x96, 0x8c, 0x8c, 0x86, 0xce, 0x54, 0x5f, 0x33, 0x89, 0x7b, 0x94, 0x1b, 0x85, 0xf3, - 0xd8, 0x5b, 0xfd, 0xcf, 0x1a, 0xe4, 0xd0, 0xa7, 0x53, 0xca, 0xc9, 0x5c, 0x0c, 0xb5, 0xb7, 0x8f, - 0xe1, 0x7d, 0x00, 0xb9, 0x0c, 0xde, 0x03, 0x65, 0x66, 0xe5, 0x50, 0x82, 0xd7, 0xbf, 0xef, 0x45, - 0x84, 0x27, 0x5f, 0x4f, 0xb8, 0x2a, 0xe9, 0x90, 0xf6, 0x3b, 0x90, 0x71, 0xa7, 0x13, 0x53, 0x5c, - 0x7f, 0xe5, 0x35, 0x21, 0xed, 0x4e, 0x27, 0xfd, 0x0b, 0x56, 0xff, 0x15, 0x64, 0xfa, 0x17, 0xf8, - 0x2d, 0x28, 0x52, 0x34, 0xf0, 0x3c, 0xf5, 0x01, 0x22, 0x87, 0x4a, 0x56, 0x08, 0xf0, 0xbe, 0xbd, - 0x64, 0xa2, 0xe8, 0x8d, 0x37, 0xfc, 0xca, 0x54, 0xdf, 0x97, 0x1f, 0xfc, 0x55, 0x83, 0x7c, 0xac, - 0x3f, 0xe8, 0xdf, 0x81, 0x5b, 0xad, 0x93, 0xb3, 0x83, 0xcf, 0xcc, 0xf6, 0xa1, 0xf9, 0xe9, 0x49, - 0xf3, 0x91, 0xf9, 0x79, 0xe7, 0xb3, 0xce, 0xd9, 0xcf, 0x3b, 0xa5, 0xb5, 0xca, 0xed, 0xab, 0xeb, - 0x9a, 0x1e, 0xc3, 0x7e, 0xee, 0x3e, 0x75, 0xbd, 0x2f, 0x5c, 0x7d, 0x1f, 0xb6, 0xe7, 0x4d, 0x9a, - 0xad, 0xde, 0x51, 0xa7, 0x5f, 0xd2, 0x2a, 0xb7, 0xae, 0xae, 0x6b, 0x5b, 0x31, 0x8b, 0xe6, 0x80, - 0x51, 0x97, 0x2f, 0x1a, 0x1c, 0x9c, 0x9d, 0x9e, 0xb6, 0xfb, 0xa5, 0xc4, 0x82, 0x81, 0x6a, 0xd8, - 0xef, 0xc3, 0xd6, 0xbc, 0x41, 0xa7, 0x7d, 0x52, 0x4a, 0x56, 0xf4, 0xab, 0xeb, 0xda, 0x46, 0x0c, - 0xdd, 0xb1, 0x9d, 0x4a, 0xf6, 0x37, 0xbf, 0xab, 0xae, 0xfd, 0xe1, 0xf7, 0x55, 0x4d, 0x9c, 0xac, - 0x38, 0xd7, 0x23, 0xf4, 0x8f, 0xe0, 0x4e, 0xaf, 0xfd, 0xa8, 0x73, 0x74, 0x68, 0x9e, 0xf6, 0x1e, - 0x99, 0xfd, 0x5f, 0x74, 0x8f, 0x62, 0xa7, 0xdb, 0xbc, 0xba, 0xae, 0xe5, 0xd5, 0x91, 0x56, 0xa1, - 0xbb, 0xc6, 0xd1, 0xe3, 0xb3, 0xfe, 0x51, 0x49, 0x93, 0xe8, 0x6e, 0x40, 0xc5, 0x4d, 0x0b, 0xd1, - 0x0f, 0x60, 0x67, 0x09, 0x3a, 0x3a, 0xd8, 0xd6, 0xd5, 0x75, 0xad, 0xd8, 0x0d, 0xa8, 0xac, 0x1f, - 0xb4, 0x68, 0x40, 0x79, 0xd1, 0xe2, 0xac, 0x7b, 0xd6, 0x6b, 0x9e, 0x94, 0x6a, 0x95, 0xd2, 0xd5, - 0x75, 0xad, 0x10, 0x36, 0x43, 0x81, 0x9f, 0x9d, 0xac, 0xf5, 0xb3, 0x2f, 0x5f, 0x56, 0xb5, 0xaf, - 0x5e, 0x56, 0xb5, 0x7f, 0xbe, 0xac, 0x6a, 0xcf, 0x5f, 0x55, 0xd7, 0xbe, 0x7a, 0x55, 0x5d, 0xfb, - 0xdb, 0xab, 0xea, 0xda, 0x2f, 0xbf, 0x3f, 0xb2, 0xf9, 0x78, 0x3a, 0x68, 0x0c, 0xbd, 0xc9, 0x7e, - 0xfc, 0xff, 0x8f, 0xd9, 0xa3, 0xfc, 0x1f, 0xe6, 0xe6, 0x7f, 0x23, 0x83, 0x34, 0xca, 0x3f, 0xfe, - 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x7a, 0x87, 0x97, 0xdc, 0x11, 0x00, 0x00, + // 1743 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4b, 0x73, 0x1b, 0x59, + 0x15, 0x56, 0xeb, 0xad, 0x23, 0xc9, 0x96, 0x1b, 0x27, 0x91, 0x95, 0x44, 0x16, 0xe2, 0x31, 0x9e, + 0x07, 0x72, 0xc8, 0x50, 0x3c, 0xaa, 0x78, 0x8c, 0x24, 0x7b, 0x62, 0x31, 0xb6, 0x2c, 0x5a, 0x9a, + 0x50, 0xb0, 0xe9, 0xba, 0x52, 0xdf, 0x48, 0x4d, 0x5a, 0xdd, 0x4d, 0xf7, 0x95, 0x47, 0xce, 0x2f, + 0xa0, 0xbc, 0xca, 0x8a, 0x9d, 0x57, 0xb0, 0x60, 0xcf, 0x1f, 0xa0, 0x58, 0xcd, 0x86, 0xaa, 0xd9, + 0xc1, 0x86, 0x40, 0x25, 0x14, 0xc5, 0xcf, 0xa0, 0xee, 0xb9, 0xb7, 0x5b, 0x2d, 0x4b, 0x0a, 0x53, + 0xa9, 0x14, 0x1b, 0x55, 0xf7, 0x39, 0xdf, 0xb9, 0xf7, 0xdc, 0xef, 0xbc, 0x6e, 0x0b, 0xee, 0x31, + 0x6a, 0x1b, 0xd4, 0x9b, 0x9a, 0x36, 0x3b, 0x64, 0x97, 0x2e, 0xf5, 0xc5, 0x6f, 0xc3, 0xf5, 0x1c, + 0xe6, 0xa8, 0xa5, 0x85, 0xb6, 0x81, 0xf2, 0xca, 0xee, 0xd8, 0x19, 0x3b, 0xa8, 0x3c, 0xe4, 0x4f, + 0x02, 0x57, 0xd9, 0x1f, 0x3b, 0xce, 0xd8, 0xa2, 0x87, 0xf8, 0x36, 0x9c, 0x3d, 0x39, 0x64, 0xe6, + 0x94, 0xfa, 0x8c, 0x4c, 0x5d, 0x09, 0xb8, 0x1f, 0xd9, 0x66, 0xe4, 0x5d, 0xba, 0xcc, 0xe1, 0x58, + 0xe7, 0x89, 0x54, 0x57, 0x23, 0xea, 0x0b, 0xea, 0xf9, 0xa6, 0x63, 0x47, 0xfd, 0xa8, 0xd4, 0x56, + 0xbc, 0xbc, 0x20, 0x96, 0x69, 0x10, 0xe6, 0x78, 0x02, 0x51, 0xff, 0x01, 0x14, 0x7b, 0xc4, 0x63, + 0x7d, 0xca, 0x4e, 0x28, 0x31, 0xa8, 0xa7, 0xee, 0x42, 0x8a, 0x39, 0x8c, 0x58, 0x65, 0xa5, 0xa6, + 0x1c, 0x14, 0x35, 0xf1, 0xa2, 0xaa, 0x90, 0x9c, 0x10, 0x7f, 0x52, 0x8e, 0xd7, 0x94, 0x83, 0x82, + 0x86, 0xcf, 0xf5, 0x09, 0x24, 0xb9, 0x29, 0xb7, 0x30, 0x6d, 0x83, 0xce, 0x03, 0x0b, 0x7c, 0xe1, + 0xd2, 0xe1, 0x25, 0xa3, 0xbe, 0x34, 0x11, 0x2f, 0xea, 0x77, 0x20, 0x85, 0xfe, 0x97, 0x13, 0x35, + 0xe5, 0x20, 0xff, 0xb0, 0xdc, 0x88, 0x10, 0x25, 0xce, 0xd7, 0xe8, 0x71, 0x7d, 0x2b, 0xf9, 0xf9, + 0x8b, 0xfd, 0x98, 0x26, 0xc0, 0x75, 0x0b, 0x32, 0x2d, 0xcb, 0x19, 0x3d, 0xed, 0x1c, 0x85, 0x8e, + 0x28, 0x0b, 0x47, 0xd4, 0x33, 0xd8, 0x76, 0x89, 0xc7, 0x74, 0x9f, 0x32, 0x7d, 0x82, 0xa7, 0xc0, + 0x4d, 0xf3, 0x0f, 0xf7, 0x1b, 0x37, 0xe3, 0xd0, 0x58, 0x3a, 0xac, 0xdc, 0xa5, 0xe8, 0x46, 0x85, + 0xf5, 0x7f, 0x27, 0x21, 0x2d, 0xc9, 0xf8, 0x11, 0x64, 0x24, 0xad, 0xb8, 0x61, 0xfe, 0xe1, 0xfd, + 0xe8, 0x8a, 0x52, 0xd5, 0x68, 0x3b, 0xb6, 0x4f, 0x6d, 0x7f, 0xe6, 0xcb, 0xf5, 0x02, 0x1b, 0xf5, + 0x9b, 0x90, 0x1d, 0x4d, 0x88, 0x69, 0xeb, 0xa6, 0x81, 0x1e, 0xe5, 0x5a, 0xf9, 0x97, 0x2f, 0xf6, + 0x33, 0x6d, 0x2e, 0xeb, 0x1c, 0x69, 0x19, 0x54, 0x76, 0x0c, 0xf5, 0x36, 0xa4, 0x27, 0xd4, 0x1c, + 0x4f, 0x18, 0xd2, 0x92, 0xd0, 0xe4, 0x9b, 0xfa, 0x7d, 0x48, 0xf2, 0x84, 0x28, 0x27, 0x71, 0xef, + 0x4a, 0x43, 0x64, 0x4b, 0x23, 0xc8, 0x96, 0xc6, 0x20, 0xc8, 0x96, 0x56, 0x96, 0x6f, 0xfc, 0xfc, + 0x1f, 0xfb, 0x8a, 0x86, 0x16, 0x6a, 0x1b, 0x8a, 0x16, 0xf1, 0x99, 0x3e, 0xe4, 0xb4, 0xf1, 0xed, + 0x53, 0xb8, 0xc4, 0xde, 0x2a, 0x21, 0x92, 0x58, 0xe9, 0x7a, 0x9e, 0x5b, 0x09, 0x91, 0xa1, 0x1e, + 0x40, 0x09, 0x17, 0x19, 0x39, 0xd3, 0xa9, 0xc9, 0x74, 0xe4, 0x3d, 0x8d, 0xbc, 0x6f, 0x71, 0x79, + 0x1b, 0xc5, 0x27, 0x3c, 0x02, 0x77, 0x21, 0x67, 0x10, 0x46, 0x04, 0x24, 0x83, 0x90, 0x2c, 0x17, + 0xa0, 0xf2, 0x1d, 0xd8, 0x0e, 0xb3, 0xce, 0x17, 0x90, 0xac, 0x58, 0x65, 0x21, 0x46, 0xe0, 0x03, + 0xd8, 0xb5, 0xe9, 0x9c, 0xe9, 0x37, 0xd1, 0x39, 0x44, 0xab, 0x5c, 0xf7, 0x78, 0xd9, 0xe2, 0x1b, + 0xb0, 0x35, 0x0a, 0xc8, 0x17, 0x58, 0x40, 0x6c, 0x31, 0x94, 0x22, 0x6c, 0x0f, 0xb2, 0xc4, 0x75, + 0x05, 0x20, 0x8f, 0x80, 0x0c, 0x71, 0x5d, 0x54, 0xbd, 0x07, 0x3b, 0x78, 0x46, 0x8f, 0xfa, 0x33, + 0x8b, 0xc9, 0x45, 0x0a, 0x88, 0xd9, 0xe6, 0x0a, 0x4d, 0xc8, 0x11, 0xfb, 0x35, 0x28, 0xd2, 0x0b, + 0xd3, 0xa0, 0xf6, 0x88, 0x0a, 0x5c, 0x11, 0x71, 0x85, 0x40, 0x88, 0xa0, 0x77, 0xa1, 0xe4, 0x7a, + 0x8e, 0xeb, 0xf8, 0xd4, 0xd3, 0x89, 0x61, 0x78, 0xd4, 0xf7, 0xcb, 0x5b, 0x62, 0xbd, 0x40, 0xde, + 0x14, 0xe2, 0xfa, 0x0b, 0x05, 0x92, 0x47, 0x84, 0x11, 0xb5, 0x04, 0x09, 0x36, 0xf7, 0xcb, 0x4a, + 0x2d, 0x71, 0x50, 0xd0, 0xf8, 0xa3, 0xfa, 0x11, 0x64, 0x83, 0x55, 0x65, 0xa9, 0x54, 0x57, 0x43, + 0x77, 0x2c, 0x11, 0xa7, 0xa6, 0xcf, 0x64, 0xfc, 0x42, 0x2b, 0xf5, 0x87, 0x90, 0x9d, 0x52, 0xdf, + 0x27, 0x63, 0xea, 0x87, 0xf9, 0xb3, 0xb2, 0xc2, 0x99, 0x44, 0x04, 0xd6, 0x81, 0x05, 0x0f, 0x85, + 0xe3, 0x99, 0x63, 0xd3, 0x26, 0x96, 0xee, 0xff, 0x7a, 0x46, 0x3c, 0xaa, 0xfb, 0xe6, 0x33, 0x8a, + 0x69, 0x94, 0xd4, 0xd4, 0x40, 0xd7, 0x47, 0x55, 0xdf, 0x7c, 0x46, 0xc3, 0xc2, 0x4c, 0x47, 0x3a, + 0xc4, 0xf3, 0x38, 0xdc, 0x3a, 0x9a, 0xb9, 0x96, 0x39, 0x22, 0x8c, 0x3e, 0x76, 0x18, 0x0d, 0x3c, + 0x56, 0xbf, 0x05, 0xe9, 0x0b, 0x87, 0x51, 0x9d, 0xc8, 0xba, 0xba, 0xbd, 0xea, 0x1b, 0xc7, 0x6b, + 0x29, 0x8e, 0x6a, 0x86, 0xf0, 0xa1, 0x2c, 0xec, 0xd7, 0xc2, 0x5b, 0xea, 0x07, 0xa0, 0x62, 0xdb, + 0xd2, 0x2f, 0x1c, 0x66, 0xda, 0x63, 0xdd, 0x75, 0x3e, 0xa3, 0x9e, 0xac, 0xad, 0x12, 0x6a, 0x1e, + 0xa3, 0xa2, 0xc7, 0xe5, 0x4b, 0xf9, 0x29, 0xa1, 0x49, 0x84, 0x2e, 0xf2, 0x53, 0x00, 0x5b, 0x90, + 0x0b, 0xfb, 0xb3, 0x2c, 0xa8, 0x2f, 0x57, 0x93, 0x0b, 0xb3, 0xfa, 0x5f, 0xe2, 0xb0, 0x77, 0xca, + 0x8b, 0xbb, 0x6d, 0x99, 0xd4, 0x66, 0x4d, 0xc6, 0xc8, 0xe8, 0x69, 0x48, 0x4b, 0x07, 0x76, 0x46, + 0x8e, 0xfd, 0xc4, 0x32, 0x47, 0xe8, 0x37, 0x56, 0xaf, 0x64, 0xe8, 0xde, 0xea, 0x91, 0x71, 0x1d, + 0x2c, 0x56, 0xad, 0x14, 0x31, 0x43, 0x09, 0x4f, 0x56, 0x5e, 0xb7, 0x8e, 0xad, 0xcb, 0xd6, 0x12, + 0xc7, 0x33, 0x15, 0x84, 0xf0, 0x44, 0x34, 0x98, 0x2e, 0xec, 0x0e, 0x2f, 0x9f, 0x11, 0x9b, 0x99, + 0x36, 0x8d, 0x94, 0x5d, 0x39, 0x51, 0x4b, 0x1c, 0xe4, 0x1f, 0xde, 0x5d, 0xc3, 0x72, 0x80, 0xd1, + 0xbe, 0x12, 0x1a, 0x2e, 0x6a, 0x72, 0x03, 0xf1, 0xc9, 0x0d, 0xc4, 0xbf, 0x0d, 0x3e, 0xff, 0xa5, + 0x40, 0x36, 0xa4, 0x8f, 0xc0, 0x1d, 0x23, 0x48, 0x37, 0x1d, 0x13, 0x26, 0x2c, 0x22, 0x41, 0xe2, + 0x3b, 0xab, 0x27, 0x5a, 0x9b, 0x9f, 0x27, 0x31, 0xed, 0x96, 0xb1, 0x36, 0x71, 0x6d, 0xb8, 0x67, + 0x71, 0xea, 0xf4, 0x11, 0xc6, 0x4f, 0x27, 0x18, 0xc0, 0xc5, 0x3e, 0x22, 0x3f, 0xdf, 0xdf, 0x10, + 0xac, 0x75, 0x41, 0x3f, 0x89, 0x69, 0x7b, 0xd6, 0x26, 0x65, 0x2b, 0x05, 0x09, 0x7f, 0x36, 0xad, + 0x9f, 0x42, 0x21, 0x5a, 0xed, 0xbc, 0xba, 0x23, 0x47, 0x4b, 0xac, 0xaf, 0xee, 0x70, 0x91, 0x1b, + 0xbd, 0xa1, 0xfe, 0x53, 0xc8, 0x06, 0x95, 0xaf, 0xfe, 0x18, 0x8a, 0x41, 0xd5, 0xeb, 0x96, 0xe9, + 0x33, 0xb9, 0xdc, 0xde, 0xc6, 0x66, 0xa1, 0x15, 0x02, 0x3c, 0xf7, 0xa4, 0xfe, 0x11, 0x64, 0xa4, + 0x42, 0xfd, 0x2a, 0x14, 0x6c, 0x32, 0xa5, 0xbe, 0x4b, 0x46, 0x94, 0xcf, 0x1c, 0x31, 0xa3, 0xf3, + 0xa1, 0xac, 0x63, 0xf0, 0x2e, 0xc1, 0xe7, 0x42, 0x70, 0x8f, 0xe0, 0xcf, 0xf5, 0xff, 0xc4, 0x21, + 0xc9, 0x39, 0x56, 0x3f, 0x84, 0x24, 0xdf, 0x09, 0xed, 0xb6, 0xd6, 0x0d, 0xef, 0xbe, 0x39, 0xb6, + 0xa9, 0x71, 0xe6, 0x8f, 0x07, 0x97, 0x2e, 0xd5, 0x10, 0x1c, 0x99, 0x9d, 0xf1, 0xa5, 0xd9, 0xb9, + 0x0b, 0x29, 0xcf, 0x99, 0xd9, 0x06, 0x96, 0x7d, 0x4a, 0x13, 0x2f, 0xea, 0x31, 0x64, 0xc3, 0x91, + 0x98, 0xfc, 0x5f, 0x23, 0x71, 0x9b, 0xd3, 0xc6, 0x07, 0xb6, 0x14, 0x68, 0x99, 0xa1, 0x9c, 0x8c, + 0x6f, 0x21, 0x73, 0xd5, 0xf7, 0x61, 0x67, 0xd1, 0x76, 0x82, 0x49, 0x21, 0xba, 0x67, 0x29, 0x54, + 0xc8, 0x51, 0xb1, 0xdc, 0xa3, 0xc4, 0x6d, 0x2b, 0x83, 0xe7, 0x5a, 0xf4, 0xa8, 0x0e, 0x5e, 0xbb, + 0xee, 0x41, 0xce, 0x37, 0xc7, 0x36, 0x61, 0x33, 0x8f, 0xca, 0x31, 0xbb, 0x10, 0xd4, 0xff, 0xa4, + 0x40, 0x5a, 0x8c, 0xed, 0x08, 0x6f, 0xca, 0x7a, 0xde, 0xe2, 0x9b, 0x78, 0x4b, 0xbc, 0x39, 0x6f, + 0x4d, 0x80, 0xd0, 0x19, 0x3e, 0x96, 0x36, 0x74, 0x19, 0xe1, 0x62, 0xdf, 0x1c, 0xcb, 0xcc, 0x8d, + 0x18, 0xd5, 0xff, 0xae, 0x40, 0x2e, 0xd4, 0xab, 0x4d, 0x28, 0x06, 0x7e, 0xe9, 0x4f, 0x2c, 0x32, + 0x96, 0xb9, 0x73, 0x7f, 0xa3, 0x73, 0x1f, 0x5b, 0x64, 0xac, 0xe5, 0xa5, 0x3f, 0xfc, 0x65, 0x7d, + 0x1c, 0xe2, 0x1b, 0xe2, 0xb0, 0x14, 0xf8, 0xc4, 0x9b, 0x05, 0x7e, 0x29, 0x44, 0xc9, 0x9b, 0x21, + 0xfa, 0x63, 0x1c, 0xb2, 0x3d, 0xbc, 0x28, 0x10, 0xeb, 0xff, 0x51, 0x11, 0x77, 0x21, 0xe7, 0x3a, + 0x96, 0x2e, 0x34, 0x49, 0xd4, 0x64, 0x5d, 0xc7, 0xd2, 0x56, 0xc2, 0x9e, 0x7a, 0x4b, 0xe5, 0x92, + 0x7e, 0x0b, 0xac, 0x65, 0x6e, 0xb2, 0xe6, 0x41, 0x41, 0x50, 0x21, 0x2f, 0xee, 0x0f, 0x38, 0x07, + 0xf8, 0x25, 0xa0, 0xac, 0x7e, 0x68, 0x08, 0xb7, 0x05, 0x52, 0x93, 0x38, 0x6e, 0x21, 0xee, 0xb9, + 0xb2, 0x85, 0x97, 0x37, 0xa5, 0xa5, 0x26, 0x71, 0xf5, 0xdf, 0x2a, 0x00, 0x8b, 0x11, 0xcc, 0xaf, + 0xdc, 0x3e, 0xba, 0xa0, 0x2f, 0xed, 0x5c, 0xdd, 0x14, 0x34, 0xb9, 0x7f, 0xc1, 0x8f, 0xfa, 0xdd, + 0x86, 0xe2, 0x22, 0x19, 0x7d, 0x1a, 0x38, 0x53, 0x7d, 0xcd, 0x24, 0xee, 0x53, 0xa6, 0x15, 0x2e, + 0x22, 0x6f, 0xf5, 0x3f, 0x2b, 0x90, 0x43, 0x9f, 0xce, 0x28, 0x23, 0x4b, 0x31, 0x54, 0xde, 0x3c, + 0x86, 0xf7, 0x01, 0xc4, 0x32, 0x78, 0x0f, 0x14, 0x99, 0x95, 0x43, 0x09, 0x5e, 0xff, 0xbe, 0x1b, + 0x12, 0x9e, 0x78, 0x3d, 0xe1, 0xb2, 0xa4, 0x03, 0xda, 0xef, 0x40, 0xc6, 0x9e, 0x4d, 0x75, 0x7e, + 0xfd, 0x15, 0xd7, 0x84, 0xb4, 0x3d, 0x9b, 0x0e, 0xe6, 0x7e, 0xfd, 0x57, 0x90, 0x19, 0xcc, 0xf1, + 0x5b, 0x90, 0xa7, 0xa8, 0xe7, 0x38, 0xf2, 0x03, 0x44, 0x0c, 0x95, 0x2c, 0x17, 0xe0, 0x7d, 0x7b, + 0xcd, 0x44, 0x51, 0x1b, 0x5f, 0xf2, 0x2b, 0x33, 0xf8, 0xbe, 0xfc, 0x09, 0x64, 0xda, 0x13, 0xd3, + 0x32, 0x06, 0x73, 0xf5, 0xeb, 0xb0, 0xe5, 0x12, 0x8f, 0x4f, 0x76, 0x36, 0x8f, 0x6e, 0x58, 0x10, + 0xd2, 0xc1, 0x1c, 0x37, 0xdd, 0x82, 0x38, 0x9b, 0xcb, 0x2d, 0xe3, 0x6c, 0xfe, 0xde, 0x5f, 0x15, + 0xc8, 0x47, 0x1a, 0x8c, 0xfa, 0x6d, 0xb8, 0xd5, 0x3a, 0x3d, 0x6f, 0x7f, 0xa2, 0x77, 0x8e, 0xf4, + 0x8f, 0x4f, 0x9b, 0x8f, 0xf4, 0x4f, 0xbb, 0x9f, 0x74, 0xcf, 0x7f, 0xde, 0x2d, 0xc5, 0x2a, 0xb7, + 0xaf, 0xae, 0x6b, 0x6a, 0x04, 0xfb, 0xa9, 0xfd, 0xd4, 0x76, 0x3e, 0xb3, 0xd5, 0x43, 0xd8, 0x5d, + 0x36, 0x69, 0xb6, 0xfa, 0xc7, 0xdd, 0x41, 0x49, 0xa9, 0xdc, 0xba, 0xba, 0xae, 0xed, 0x44, 0x2c, + 0x9a, 0x43, 0x9f, 0xda, 0x6c, 0xd5, 0xa0, 0x7d, 0x7e, 0x76, 0xd6, 0x19, 0x94, 0xe2, 0x2b, 0x06, + 0xb2, 0xe3, 0xbf, 0x0b, 0x3b, 0xcb, 0x06, 0xdd, 0xce, 0x69, 0x29, 0x51, 0x51, 0xaf, 0xae, 0x6b, + 0x5b, 0x11, 0x74, 0xd7, 0xb4, 0x2a, 0xd9, 0xdf, 0xfc, 0xae, 0x1a, 0xfb, 0xc3, 0xef, 0xab, 0x0a, + 0x3f, 0x59, 0x71, 0xa9, 0xc9, 0xa8, 0x1f, 0xc0, 0x9d, 0x7e, 0xe7, 0x51, 0xf7, 0xf8, 0x48, 0x3f, + 0xeb, 0x3f, 0xd2, 0x07, 0xbf, 0xe8, 0x1d, 0x47, 0x4e, 0xb7, 0x7d, 0x75, 0x5d, 0xcb, 0xcb, 0x23, + 0x6d, 0x42, 0xf7, 0xb4, 0xe3, 0xc7, 0xe7, 0x83, 0xe3, 0x92, 0x22, 0xd0, 0x3d, 0x8f, 0xf2, 0xab, + 0x1a, 0xa2, 0x1f, 0xc0, 0xde, 0x1a, 0x74, 0x78, 0xb0, 0x9d, 0xab, 0xeb, 0x5a, 0xb1, 0xe7, 0x51, + 0x51, 0x80, 0x68, 0xd1, 0x80, 0xf2, 0xaa, 0xc5, 0x79, 0xef, 0xbc, 0xdf, 0x3c, 0x2d, 0xd5, 0x2a, + 0xa5, 0xab, 0xeb, 0x5a, 0x21, 0xe8, 0xa6, 0x1c, 0xbf, 0x38, 0x59, 0xeb, 0x67, 0x9f, 0xbf, 0xac, + 0x2a, 0x5f, 0xbc, 0xac, 0x2a, 0xff, 0x7c, 0x59, 0x55, 0x9e, 0xbf, 0xaa, 0xc6, 0xbe, 0x78, 0x55, + 0x8d, 0xfd, 0xed, 0x55, 0x35, 0xf6, 0xcb, 0xef, 0x8d, 0x4d, 0x36, 0x99, 0x0d, 0x1b, 0x23, 0x67, + 0x7a, 0x18, 0xfd, 0x03, 0x65, 0xf1, 0x28, 0xfe, 0xc8, 0xb9, 0xf9, 0xe7, 0xca, 0x30, 0x8d, 0xf2, + 0x0f, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x74, 0x3d, 0x85, 0x46, 0x1d, 0x12, 0x00, 0x00, } func (m *PartSetHeader) Marshal() (dAtA []byte, err error) { @@ -2651,6 +2708,43 @@ func (m *TxProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ChildTx) 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 *ChildTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ChildTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Tx) > 0 { + i -= len(m.Tx) + copy(dAtA[i:], m.Tx) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Tx))) + i-- + dAtA[i] = 0x12 + } + if len(m.ParentTxHash) > 0 { + i -= len(m.ParentTxHash) + copy(dAtA[i:], m.ParentTxHash) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ParentTxHash))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { offset -= sovTypes(v) base := offset @@ -3111,6 +3205,23 @@ func (m *TxProof) Size() (n int) { return n } +func (m *ChildTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ParentTxHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Tx) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + func sovTypes(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -6333,6 +6444,124 @@ func (m *TxProof) Unmarshal(dAtA []byte) error { } return nil } +func (m *ChildTx) 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: ChildTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ChildTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ParentTxHash", 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.ParentTxHash = append(m.ParentTxHash[:0], dAtA[iNdEx:postIndex]...) + if m.ParentTxHash == nil { + m.ParentTxHash = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tx", 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.Tx = append(m.Tx[:0], dAtA[iNdEx:postIndex]...) + if m.Tx == nil { + m.Tx = []byte{} + } + 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 skipTypes(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/proto/tendermint/types/types.proto b/proto/tendermint/types/types.proto index 7416e0636d..89b3e21536 100644 --- a/proto/tendermint/types/types.proto +++ b/proto/tendermint/types/types.proto @@ -200,3 +200,10 @@ message TxProof { bytes data = 2; tendermint.crypto.Proof proof = 3; } + +// ChildTx wraps a transaction that was derived from a parent transaction. This +// allows for removal of the parent transaction from the mempool. +message ChildTx { + bytes parent_tx_hash = 1; + bytes tx = 2; +} diff --git a/types/block.go b/types/block.go index abf481a407..97d1bbae0e 100644 --- a/types/block.go +++ b/types/block.go @@ -303,7 +303,10 @@ func MaxDataBytesNoEvidence(maxBytes int64, valsCount int) int64 { // MakeBlock returns a new block with an empty header, except what can be // computed from itself. // It populates the same set of fields validated by ValidateBasic. -func MakeBlock(height int64, txs []Tx, lastCommit *Commit, evidence []Evidence) *Block { +func MakeBlock( + height int64, + txs []Tx, evidence []Evidence, messages []Message, + lastCommit *Commit) *Block { block := &Block{ Header: Header{ Version: version.Consensus{Block: version.BlockProtocol, App: 0}, @@ -312,6 +315,7 @@ func MakeBlock(height int64, txs []Tx, lastCommit *Commit, evidence []Evidence) Data: Data{ Txs: txs, Evidence: EvidenceData{Evidence: evidence}, + Messages: Messages{MessagesList: messages}, }, LastCommit: lastCommit, } diff --git a/types/block_test.go b/types/block_test.go index d026bfa0f1..c5fbcd510d 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -46,7 +46,7 @@ func TestBlockAddEvidence(t *testing.T) { ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain") evList := []Evidence{ev} - block := MakeBlock(h, txs, commit, evList) + block := MakeBlock(h, txs, evList, nil, commit) require.NotNil(t, block) require.Equal(t, 1, len(block.Evidence.Evidence)) require.NotNil(t, block.EvidenceHash) @@ -107,7 +107,7 @@ func TestBlockValidateBasic(t *testing.T) { tc := tc i := i t.Run(tc.testName, func(t *testing.T) { - block := MakeBlock(h, txs, commit, evList) + block := MakeBlock(h, txs, evList, nil, commit) block.ProposerAddress = valSet.GetProposer().Address tc.malleateBlock(block) err = block.ValidateBasic() @@ -119,13 +119,13 @@ func TestBlockValidateBasic(t *testing.T) { func TestBlockHash(t *testing.T) { assert.Nil(t, (*Block)(nil).Hash()) - assert.Nil(t, MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil).Hash()) + assert.Nil(t, MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil, nil).Hash()) } func TestBlockMakePartSet(t *testing.T) { assert.Nil(t, (*Block)(nil).MakePartSet(2)) - partSet := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil).MakePartSet(1024) + partSet := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil, nil).MakePartSet(1024) assert.NotNil(t, partSet) assert.EqualValues(t, 1, partSet.Total()) } @@ -143,7 +143,7 @@ func TestBlockMakePartSetWithEvidence(t *testing.T) { ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain") evList := []Evidence{ev} - partSet := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList).MakePartSet(512) + partSet := MakeBlock(h, []Tx{Tx("Hello World")}, evList, nil, commit).MakePartSet(512) assert.NotNil(t, partSet) assert.EqualValues(t, 4, partSet.Total()) } @@ -160,7 +160,7 @@ func TestBlockHashesTo(t *testing.T) { ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain") evList := []Evidence{ev} - block := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList) + block := MakeBlock(h, []Tx{Tx("Hello World")}, evList, nil, commit) block.ValidatorsHash = valSet.Hash() assert.False(t, block.HashesTo([]byte{})) assert.False(t, block.HashesTo([]byte("something else"))) @@ -168,7 +168,7 @@ func TestBlockHashesTo(t *testing.T) { } func TestBlockSize(t *testing.T) { - size := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil).Size() + size := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil, nil).Size() if size <= 0 { t.Fatal("Size of the block is zero or negative") } @@ -179,7 +179,7 @@ func TestBlockString(t *testing.T) { assert.Equal(t, "nil-Block", (*Block)(nil).StringIndented("")) assert.Equal(t, "nil-Block", (*Block)(nil).StringShort()) - block := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil) + block := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil, nil) assert.NotEqual(t, "nil-Block", block.String()) assert.NotEqual(t, "nil-Block", block.StringIndented("")) assert.NotEqual(t, "nil-Block", block.StringShort()) @@ -636,16 +636,16 @@ func TestBlockIDValidateBasic(t *testing.T) { func TestBlockProtoBuf(t *testing.T) { h := mrand.Int63() c1 := randCommit(time.Now()) - b1 := MakeBlock(h, []Tx{Tx([]byte{1})}, &Commit{Signatures: []CommitSig{}}, []Evidence{}) + b1 := MakeBlock(h, []Tx{Tx([]byte{1})}, []Evidence{}, nil, &Commit{Signatures: []CommitSig{}}) b1.ProposerAddress = tmrand.Bytes(crypto.AddressSize) evidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC) evi := NewMockDuplicateVoteEvidence(h, evidenceTime, "block-test-chain") - b2 := MakeBlock(h, []Tx{Tx([]byte{1})}, c1, []Evidence{evi}) + b2 := MakeBlock(h, []Tx{Tx([]byte{1})}, []Evidence{evi}, nil, c1) b2.ProposerAddress = tmrand.Bytes(crypto.AddressSize) b2.Data.Evidence.ByteSize() - b3 := MakeBlock(h, []Tx{}, c1, []Evidence{}) + b3 := MakeBlock(h, []Tx{}, []Evidence{}, nil, c1) b3.ProposerAddress = tmrand.Bytes(crypto.AddressSize) testCases := []struct { msg string diff --git a/types/event_bus_test.go b/types/event_bus_test.go index 73dc13d0c1..27c2e6f22f 100644 --- a/types/event_bus_test.go +++ b/types/event_bus_test.go @@ -74,7 +74,7 @@ func TestEventBusPublishEventNewBlock(t *testing.T) { } }) - block := MakeBlock(0, []Tx{}, nil, []Evidence{}) + block := MakeBlock(0, []Tx{}, []Evidence{}, nil, nil) blockID := BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(BlockPartSizeBytes).Header()} resultBeginBlock := abci.ResponseBeginBlock{ Events: []abci.Event{ @@ -236,7 +236,7 @@ func TestEventBusPublishEventNewBlockHeader(t *testing.T) { } }) - block := MakeBlock(0, []Tx{}, nil, []Evidence{}) + block := MakeBlock(0, []Tx{}, []Evidence{}, nil, nil) resultBeginBlock := abci.ResponseBeginBlock{ Events: []abci.Event{ {Type: "testType", Attributes: []abci.EventAttribute{{Key: "baz", Value: "1"}}}, diff --git a/types/tx.go b/types/tx.go index 22093bf288..b507351c7e 100644 --- a/types/tx.go +++ b/types/tx.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" + "github.com/gogo/protobuf/proto" "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/crypto/tmhash" tmbytes "github.com/tendermint/tendermint/libs/bytes" @@ -174,3 +175,29 @@ func ToTxs(txs [][]byte) Txs { } return txBzs } + +// DecodeChildTx attempts to unmarshal the provided transaction into a child +// transaction wrapper, if this an be done, then it returns true. A child +// transaction is a normal transaction that has been derived from a different +// parent transaction. The returned hash is that of the parent transaction, +// which allows us to remove the parent transaction from the mempool +func DecodeChildTx(tx Tx) (hash []byte, unwrapped Tx, has bool) { + // attempt to unmarshal into a a child transaction + var childTx tmproto.ChildTx + err := proto.Unmarshal(tx, &childTx) + if err != nil { + return nil, nil, false + } + return childTx.ParentTxHash, childTx.Tx, true +} + +// WrapChildTx creates a wrapped Tx that includes the parent transaction's hash +// so that it can be easily removed from the mempool. note: must be unwrapped to +// be a viable sdk.Tx +func WrapChildTx(parentHash []byte, child Tx) (Tx, error) { + wTx := tmproto.ChildTx{ + ParentTxHash: parentHash, + Tx: child, + } + return proto.Marshal(&wTx) +} From 54f125dcb17f494a2826b5be1e95b62daecedbd2 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 27 Apr 2022 18:58:46 -0500 Subject: [PATCH 10/31] add celestia ADRs --- docs/celestia-architecture/README copy.md | 37 +++ docs/celestia-architecture/README.md | 22 ++ .../adr-001-block-propagation.md | 124 ++++++++ .../adr-002-ipld-da-sampling.md | 280 +++++++++++++++++ .../adr-003-application-data-retrieval.md | 141 +++++++++ .../adr-004-mvp-light-client.md | 292 ++++++++++++++++++ ...-005-decouple-blockid-and-partsetheader.md | 47 +++ .../adr-006-row-propoagation.md | 202 ++++++++++++ .../adr-007-minimal-changes-to-tendermint.md | 234 ++++++++++++++ docs/celestia-architecture/adr-template.md | 72 +++++ .../assets/user-request.png | Bin 0 -> 397363 bytes docs/celestia-architecture/celestia-logo.png | Bin 0 -> 40963 bytes .../img/extended_square.png | Bin 0 -> 13803 bytes 13 files changed, 1451 insertions(+) create mode 100644 docs/celestia-architecture/README copy.md create mode 100644 docs/celestia-architecture/README.md create mode 100644 docs/celestia-architecture/adr-001-block-propagation.md create mode 100644 docs/celestia-architecture/adr-002-ipld-da-sampling.md create mode 100644 docs/celestia-architecture/adr-003-application-data-retrieval.md create mode 100644 docs/celestia-architecture/adr-004-mvp-light-client.md create mode 100644 docs/celestia-architecture/adr-005-decouple-blockid-and-partsetheader.md create mode 100644 docs/celestia-architecture/adr-006-row-propoagation.md create mode 100644 docs/celestia-architecture/adr-007-minimal-changes-to-tendermint.md create mode 100644 docs/celestia-architecture/adr-template.md create mode 100644 docs/celestia-architecture/assets/user-request.png create mode 100644 docs/celestia-architecture/celestia-logo.png create mode 100644 docs/celestia-architecture/img/extended_square.png diff --git a/docs/celestia-architecture/README copy.md b/docs/celestia-architecture/README copy.md new file mode 100644 index 0000000000..f00a22e54e --- /dev/null +++ b/docs/celestia-architecture/README copy.md @@ -0,0 +1,37 @@ +--- +order: 1 +parent: + order: false +--- + +# Architecture Decision Records (ADR) + +This is a location to record all high-level architecture decisions in this repository. + +You can read more about the ADR concept in this [blog post](https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t). + +An ADR should provide: + +- Context on the relevant goals and the current state +- Proposed changes to achieve the goals +- Summary of pros and cons +- References +- Changelog + +Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something +new. The spec is much more compressed and streamlined summary of everything as +it stands today. + +If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match. + +Note the context/background should be written in the present tense. + +To start a new ADR, you can use this template: [adr-template.md](./adr-template.md) + +### Table of Contents: + +- [ADR 001: Erasure Coding Block Propagation](./adr-001-block-propagation.md) +- [ADR 002: Sampling erasure coded Block chunks](./adr-002-ipld-da-sampling.md) +- [ADR 003: Retrieving Application messages](./adr-003-application-data-retrieval.md) +- [ADR 004: Data Availability Sampling Light Client](./adr-004-mvp-light-client.md) diff --git a/docs/celestia-architecture/README.md b/docs/celestia-architecture/README.md new file mode 100644 index 0000000000..ef7a3a24ae --- /dev/null +++ b/docs/celestia-architecture/README.md @@ -0,0 +1,22 @@ +# Tendermint and Celestia + +celestia-core is not meant to be used as a general purpose framework. +Instead, its main purpose is to provide certain components (mainly consensus but also a p2p layer for Tx gossiping) for the Celestia main chain. +Hence, we do not provide any extensive documentation here. + +Instead of keeping a copy of the Tendermint documentation, we refer to the existing extensive and maintained documentation and specification: + + - https://docs.tendermint.com/ + - https://github.com/tendermint/tendermint/tree/master/docs/ + - https://github.com/tendermint/spec + +Reading these will give you a lot of background and context on Tendermint which will also help you understand how celestia-core and [celestia-app](https://github.com/celestiaorg/celestia-app) interact with each other. + +# Celestia + +As mentioned above, celestia-core aims to be more focused on the Celestia use-case than vanilla Tendermint. +Moving forward we might provide a clear overview on the changes we incorporated. +For now, we refer to the Celestia specific [ADRs](./adr) in this repository as well as to the Celestia specification: + + - [celestia-adr](./adr) + - [celestia-specs](https://github.com/celestiaorg/celestia-specs) diff --git a/docs/celestia-architecture/adr-001-block-propagation.md b/docs/celestia-architecture/adr-001-block-propagation.md new file mode 100644 index 0000000000..6f015be391 --- /dev/null +++ b/docs/celestia-architecture/adr-001-block-propagation.md @@ -0,0 +1,124 @@ +# ADR 001: Erasure Coding Block Propagation + +## Changelog + +- 16-2-2021: Created + +## Context + +Block propagation is currently done by splitting the block into arbitrary chunks and gossiping them to validators via a gossip routine. While this does not have downsides it does not meet the needs of the Celestia chain. The celestia chain requires blocks to be encoded in a different way and for the proposer to not propagate the chunks to peers. + +Celestia wants validators to pull the block from a IPFS network. What does this mean? As I touched on earlier the proposer pushes the block to the network, this in turn means that each validator downloads and reconstructs the block each time to verify it. Instead Celestia will encode and split up the block via erasure codes, stored locally in the nodes IPFS daemon. After the proposer has sent the block to IPFS and received the CIDs it will include them into the proposal. This proposal will be gossiped to other validators, once a validator receives the proposal it will begin requesting the CIDs included in the proposal. + +There are two forms of a validator, one that downloads the block and one that samples it. What does sampling mean? Sampling is the act of checking that a portion or entire block is available for download. + +## Detailed Design + +The proposed design is as follows. + +### Types + +The proposal and vote types have a BlockID, this will be replaced with a header hash. The proposal will contain add fields. + +The current proposal will be updated to include required fields. The entirety of the message will be reworked at a later date. To see the extent of the needed changes you can visit the [spec repo](https://github.com/celestiaorg/celestia-specs/blob/master/specs/proto/consensus.proto#L19) + +```proto +message Proposal { + SignedMsgType type = 1; + int64 height = 2; + int32 round = 3; + int32 pol_round = 4; + + +++ + // 32-byte hash + bytes last_header_hash = 5; + // 32-byte hash + bytes last_commit_hash = 6; + // 32-byte hash + bytes consensus_root = 7; + FeeHeader fee_header = 8; + // 32-byte hash + bytes state_commitment = 9; + uint64 available_data_original_shares_used = 10; + AvailableDataHeader available_data_header = 11; + +++ + + google.protobuf.Timestamp timestamp = 12 + [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + bytes signature = 12; +} +``` + +```proto +// Vote represents a prevote, precommit, or commit vote from validators for +// consensus. +message Vote { + SignedMsgType type = 1; + int64 height = 2; + int32 round = 3; + +++ + bytes header_hash = 4; + +++ + google.protobuf.Timestamp timestamp = 5 + [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + bytes validator_address = 6; + int32 validator_index = 7; + bytes signature = 8; +} +``` + +See [specs](https://github.com/celestiaorg/celestia-specs/blob/master/specs/data_structures.md#vote) for more details on the vote. + +### Disk Storage + +Currently celestia-core stores all blocks in its store. Going forward only the headers of the blocks within the unbonding period will be stored. This will drastically reduce the amount of storage required by a celestia-core node. After the unbonding period all headers will have the option of being pruned. + +Proposed amendment to `BlockStore` interface + +```go +type BlockStore interface { + Base() int64 + Height() int64 + Size() int64 + + LoadBlockMeta(height int64) *types.BlockMeta + LoadHeader(height int64) *types.Header + LoadDAHeader(height int64) *types.DataAvailabilityHeader + + SaveHeaders(header *types.Header, daHeader *types.DataAvailabilityHeader, seenCommit *types.Commit) + + PruneHeaders(height int64) (uint64, error) + + LoadBlockCommit(height int64) *types.Commit + LoadSeenCommit(height int64) *types.Commit +} +``` + +Along side these changes the rpc layer will need to change. Instead of querying the LL-core store, the node will redirect the query through IPFS. + +Example: + +When a user requests a block from the LL node, the request will be set to the IPLD plugin. If the IPLD does not have the requested block, it will make a request to the celestia IPFS network for the required CIDs. If the full node does not have the DAheader they will not be able to request the block data. + +![user request flow](./assets/user-request.png) + +The goal is to not change the public interface for RPC's. It is yet to be seen if this possible. This means that CIDs will need to be set and loaded from the store in order to get all the related block information an user requires. + +## Status + +Proposed + + +### Positive + +- Minimal breakage to public interface +- Only store the block in a single place (IPFS) +- Reduce the public interface of the storage within Celestia. + +### Negative + +- User requests may take more time to process + +### Neutral + +## References diff --git a/docs/celestia-architecture/adr-002-ipld-da-sampling.md b/docs/celestia-architecture/adr-002-ipld-da-sampling.md new file mode 100644 index 0000000000..10a642f619 --- /dev/null +++ b/docs/celestia-architecture/adr-002-ipld-da-sampling.md @@ -0,0 +1,280 @@ +# ADR 002: Sampling erasure coded Block chunks + +## Changelog + +- 26-2-2021: Created + +## Context + +In Tendermint's block gossiping each peer gossips random parts of block data to peers. +For Celestia, we need nodes (from light-clients to validators) to be able to sample row-/column-chunks of the erasure coded +block (aka the extended data square) from the network. +This is necessary for Data Availability proofs. + +![extended_square.png](img/extended_square.png) + +A high-level, implementation-independent formalization of above mentioned sampling and Data Availability proofs can be found in: +[_Fraud and Data Availability Proofs: Detecting Invalid Blocks in Light Clients_](https://fc21.ifca.ai/papers/83.pdf). + +For the time being, besides the academic paper, no other formalization or specification of the protocol exists. +Currently, the Celestia specification itself only describes the [erasure coding](https://github.com/celestiaorg/celestia-specs/blob/master/specs/data_structures.md#erasure-coding) +and how to construct the extended data square from the block data. + +This ADR: +- describes the high-level requirements +- defines the API that and how it can be used by different components of Celestia (block gossiping, block sync, DA proofs) +- documents decision on how to implement this. + + +The core data structures and the erasure coding of the block are already implemented in celestia-core ([#17], [#19], [#83]). +While there are no ADRs for these changes, we can refer to the Celestia specification in this case. +For this aspect, the existing implementation and specification should already be on par for the most part. +The exact arrangement of the data as described in this [rationale document](https://github.com/celestiaorg/celestia-specs/blob/master/rationale/message_block_layout.md) +in the specification can happen at app-side of the ABCI boundary. +The latter was implemented in [celestiaorg/celestia-app#21](https://github.com/celestiaorg/celestia-app/pull/21) +leveraging a new ABCI method, added in [#110](https://github.com/celestiaorg/celestia-core/pull/110). +This new method is a sub-set of the proposed ABCI changes aka [ABCI++](https://github.com/tendermint/spec/pull/254). + +Mustafa Al-Bassam (@musalbas) implemented a [prototype](https://github.com/celestiaorg/celestia-prototype) +whose main purpose is to realistically analyse the protocol. +Although the prototype does not make any network requests and only operates locally, it can partly serve as a reference implementation. +It uses the [rsmt2d] library. + +The implementation will essentially use IPFS' APIs. For reading (and writing) chunks it +will use the IPLD [`DagService`](https://github.com/ipfs/go-ipld-format/blob/d2e09424ddee0d7e696d01143318d32d0fb1ae63/merkledag.go#L54), +more precisely the [`NodeGetter`](https://github.com/ipfs/go-ipld-format/blob/d2e09424ddee0d7e696d01143318d32d0fb1ae63/merkledag.go#L18-L27) +and [`NodeAdder`](https://github.com/ipfs/go-ipld-format/blob/d2e09424ddee0d7e696d01143318d32d0fb1ae63/merkledag.go#L29-L39). +As an optimization, we can also use a [`Batch`](https://github.com/ipfs/go-ipld-format/blob/d2e09424ddee0d7e696d01143318d32d0fb1ae63/batch.go#L29) +to batch adding and removing nodes. +This will be achieved by passing around a [CoreAPI](https://github.com/ipfs/interface-go-ipfs-core/blob/b935dfe5375eac7ea3c65b14b3f9a0242861d0b3/coreapi.go#L15) +object, which derive from the IPFS node which is created along a with a tendermint node (see [#152]). +This code snippet does exactly that (see the [go-ipfs documentation] for more examples): +```go +// This constructs an IPFS node instance +node, _ := core.NewNode(ctx, nodeOptions) +// This attaches the Core API to the constructed node +coreApi := coreapi.NewCoreAPI(node) +``` + +The above mentioned IPLD methods operate on so called [ipld.Nodes]. +When computing the data root, we can pass in a [`NodeVisitor`](https://github.com/celestia/nmt/blob/b22170d6f23796a186c07e87e4ef9856282ffd1a/nmt.go#L22) +into the Namespaced Merkle Tree library to create these (each inner- and leaf-node in the tree becomes an ipld node). +As a peer that requests such an IPLD node, the Celestia IPLD plugin provides the [function](https://github.com/celestiaorg/celestia-core/blob/ceb881a177b6a4a7e456c7c4ab1dd0eb2b263066/p2p/ipld/plugin/nodes/nodes.go#L175) +`NmtNodeParser` to transform the retrieved raw data back into an `ipld.Node`. + +A more high-level description on the changes required to rip out the current block gossiping routine, +including changes to block storage-, RPC-layer, and potential changes to reactors is either handled in [ADR 001](./adr-001-block-propagation.md), +and/or in a few smaller, separate followup ADRs. + +## Alternative Approaches + +Instead of creating a full IPFS node object and passing it around as explained above + - use API (http) + - use ipld-light + - use alternative client + +Also, for better performance + - use [graph-sync], [IPLD selectors], e.g. via [ipld-prime] + +Also, there is the idea, that nodes only receive the [Header] with the data root only +and, in an additional step/request, download the DA header using the library, too. +While this feature is not considered here, and we assume each node that uses this library has the DA header, this assumption +is likely to change when flesh out other parts of the system in more detail. +Note that this also means that light clients would still need to validate that the data root and merkelizing the DA header yield the same result. + +## Decision + +> This section records the decision that was made. +> It is best to record as much info as possible from the discussion that happened. This aids in not having to go back to the Pull Request to get the needed information. + +> - TODO: briefly summarize github, discord, and slack discussions (?) +> - also mention Mustafa's prototype and compare both apis briefly (RequestSamples, RespondSamples, ProcessSamplesResponse) +> - mention [ipld experiments] + + + +## Detailed Design + +Add a package to the library that provides the following features: + 1. sample a given number of random row/col indices of extended data square given a DA header and indicate if successful or timeout/other error occurred + 2. store the block in the network by adding it to the peer's local Merkle-DAG whose content is discoverable via a DHT + 3. store the sampled chunks in the network + 4. reconstruct the whole block from a given DA header + 5. get all messages of a particular namespace ID. + +We mention 5. here mostly for completeness. Its details will be described / implemented in a separate ADR / PR. + +Apart from the above mentioned features, we informally collect additional requirements: +- where randomness is needed, the randomness source should be configurable +- all replies by the network should be verified if this is not sufficiently covered by the used libraries already (IPFS) +- where possible, the requests to the network should happen in parallel (without DoSing the proposer for instance). + +This library should be implemented as two new packages: + +First, a sub-package should be added to the layzledger-core [p2p] package +which does not know anything about the core data structures (Block, DA header etc). +It handles the actual network requests to the IPFS network and operates on IPFS/IPLD objects +directly and hence should live under [p2p/ipld]. +To a some extent this part of the stack already exists. + +Second, a high-level API that can "live" closer to the actual types, e.g., in a sub-package in [celestia-core/types] +or in a new sub-package `da`. + +We first describe the high-level library here and describe functions in +more detail inline with their godoc comments below. + +### API that operates on celestia-core types + +As mentioned above this part of the library has knowledge of the core types (and hence depends on them). +It does not deal with IPFS internals. + +```go +// ValidateAvailability implements the protocol described in https://fc21.ifca.ai/papers/83.pdf. +// Specifically all steps of the protocol described in section +// _5.2 Random Sampling and Network Block Recovery_ are carried out. +// +// In more detail it will first create numSamples random unique coordinates. +// Then, it will ask the network for the leaf data corresponding to these coordinates. +// Additionally to the number of requests, the caller can pass in a callback, +// which will be called on for each retrieved leaf with a verified Merkle proof. +// +// Among other use-cases, the callback can be useful to monitoring (progress), or, +// to process the leaf data the moment it was validated. +// The context can be used to provide a timeout. +// TODO: Should there be a constant = lower bound for #samples +func ValidateAvailability( + ctx contex.Context, + dah *DataAvailabilityHeader, + numSamples int, + onLeafValidity func(namespace.PrefixedData8), +) error { /* ... */} + +// RetrieveBlockData can be used to recover the block Data. +// It will carry out a similar protocol as described for ValidateAvailability. +// The key difference is that it will sample enough chunks until it can recover the +// full extended data square, including original data (e.g. by using rsmt2d.RepairExtendedDataSquare). +func RetrieveBlockData( + ctx contex.Context, + dah *DataAvailabilityHeader, + api coreiface.CoreAPI, + codec rsmt2d.Codec, + ) (types.Data, error) {/* ... */} + +// PutBlock operates directly on the Block. +// It first computes the erasure coding, aka the extended data square. +// Row by row ir calls a lower level library which handles adding the +// the row to the Merkle Dag, in our case a Namespaced Merkle Tree. +// Note, that this method could also fill the DA header. +// The data will be pinned by default. +func (b *Block) PutBlock(ctx contex.Context, nodeAdder ipld.NodeAdder) error +``` + +We now describe the lower-level library that will be used by above methods. +Again we provide more details inline in the godoc comments directly. + +`PutBlock` is a method on `Block` as the erasure coding can then be cached, e.g. in a private field +in the block. + +### Changes to the lower level API closer to IPFS (p2p/ipld) + +```go +// GetLeafData takes in a Namespaced Merkle tree root transformed into a Cid +// and the leaf index to retrieve. +// Callers also need to pass in the total number of leaves of that tree. +// Internally, this will be translated to a IPLD path and corresponds to +// an ipfs dag get request, e.g. namespacedCID/0/1/0/0/1. +// The retrieved data should be pinned by default. +func GetLeafData( + ctx context.Context, + rootCid cid.Cid, + leafIndex uint32, + totalLeafs uint32, // this corresponds to the extended square width + api coreiface.CoreAPI, +) ([]byte, error) +``` + +`GetLeafData` can be used by above `ValidateAvailability` and `RetrieveBlock` and +`PutLeaves` by `PutBlock`. + +### A Note on IPFS/IPLD + +In IPFS all data is _content addressed_ which basically means the data is identified by its hash. +Particularly, in the Celestia case, the root CID identifies the Namespaced Merkle tree including all its contents (inner and leaf nodes). +This means that if a `GetLeafData` request succeeds, the retrieved leaf data is in fact the leaf data in the tree. +We do not need to additionally verify Merkle proofs per leaf as this will essentially be done via IPFS on each layer while +resolving and getting to the leaf data. + +> TODO: validate this assumption and link to code that shows how this is done internally + +### Implementation plan + +As fully integrating Data Available proofs into tendermint, is a rather larger change we break up the work into the +following packages (not mentioning the implementation work that was already done): + +1. Flesh out the changes in the consensus messages ([celestia-specs#126], [celestia-specs#127]) +2. Flesh out the changes that would be necessary to replace the current block gossiping ([ADR 001](./adr-001-block-propagation.md)) +3. Add the possibility of storing and retrieving block data (samples or whole block) to celestia-core (this ADR and related PRs). +4. Integrate above API (3.) as an addition into celestia-core without directly replacing the tendermint counterparts (block gossip etc). +5. Rip out each component that will be redundant with above integration in one or even several smaller PRs: + - block gossiping (see ADR 001) + - modify block store (see ADR 001) + - make downloading full Blocks optional (flag/config) + - route some RPC requests to IPFS (see ADR 001) + + +## Status + +Proposed + +## Consequences + +### Positive + +- simplicity & ease of implementation +- can re-use an existing networking and p2p stack (go-ipfs) +- potential support of large, cool, and helpful community +- high-level API definitions independent of the used stack + +### Negative + +- latency +- being connected to the public IPFS network might be overkill if peers should in fact only care about a subset that participates in the Celestia protocol +- dependency on a large code-base with lots of features and options of which we only need a small subset of + +### Neutral +- two different p2p layers exist in celestia-core + +## References + +- https://github.com/celestiaorg/celestia-core/issues/85 +- https://github.com/celestiaorg/celestia-core/issues/167 + +- https://docs.ipld.io/#nodes +- https://arxiv.org/abs/1809.09044 +- https://fc21.ifca.ai/papers/83.pdf +- https://github.com/tendermint/spec/pull/254 + + +[#17]: https://github.com/celestiaorg/celestia-core/pull/17 +[#19]: https://github.com/celestiaorg/celestia-core/pull/19 +[#83]: https://github.com/celestiaorg/celestia-core/pull/83 + +[#152]: https://github.com/celestiaorg/celestia-core/pull/152 + +[celestia-specs#126]: https://github.com/celestiaorg/celestia-specs/issues/126 +[celestia-specs#127]: https://github.com/celestiaorg/celestia-specs/pulls/127 +[Header]: https://github.com/celestiaorg/celestia-specs/blob/master/specs/data_structures.md#header + +[go-ipfs documentation]: https://github.com/ipfs/go-ipfs/tree/master/docs/examples/go-ipfs-as-a-library#use-go-ipfs-as-a-library-to-spawn-a-node-and-add-a-file +[ipld experiments]: https://github.com/celestia/ipld-plugin-experiments +[ipld.Nodes]: https://github.com/ipfs/go-ipld-format/blob/d2e09424ddee0d7e696d01143318d32d0fb1ae63/format.go#L22-L45 +[graph-sync]: https://github.com/ipld/specs/blob/master/block-layer/graphsync/graphsync.md +[IPLD selectors]: https://github.com/ipld/specs/blob/master/selectors/selectors.md +[ipld-prime]: https://github.com/ipld/go-ipld-prime + +[rsmt2d]: https://github.com/celestia/rsmt2d + + +[p2p]: https://github.com/celestiaorg/celestia-core/tree/0eccfb24e2aa1bb9c4428e20dd7828c93f300e60/p2p +[p2p/ipld]: https://github.com/celestiaorg/celestia-core/tree/0eccfb24e2aa1bb9c4428e20dd7828c93f300e60/p2p/ipld +[celestia-core/types]: https://github.com/celestiaorg/celestia-core/tree/0eccfb24e2aa1bb9c4428e20dd7828c93f300e60/types diff --git a/docs/celestia-architecture/adr-003-application-data-retrieval.md b/docs/celestia-architecture/adr-003-application-data-retrieval.md new file mode 100644 index 0000000000..fdefa51cb8 --- /dev/null +++ b/docs/celestia-architecture/adr-003-application-data-retrieval.md @@ -0,0 +1,141 @@ +# ADR 003: Retrieving Application messages + +## Changelog + +- 2021-04-25: initial draft + +## Context + +This ADR builds on top of [ADR 002](adr-002-ipld-da-sampling.md) and will use the implemented APIs described there. +The reader should familiarize themselves at least with the high-level concepts the as well as in the [specs](https://github.com/celestiaorg/celestia-specs/blob/master/specs/data_structures.md#2d-reed-solomon-encoding-scheme). + +The academic [paper](https://arxiv.org/abs/1905.09274) describes the motivation and context for this API. +The main motivation can be quoted from section 3.3 of that paper: + +> (Property1) **Application message retrieval partitioning.** Client nodes must be able to download all of the messages relevant to the applications they use [...], without needing to downloading any messages for other applications. + +> (Property2) **Application message retrieval completeness.** When client nodes download messages relevant to the applications they use [...], they must be able to verify that the messages they received are the complete set of messages relevant to their applications, for specific +blocks, and that there are no omitted messages. + + + +The main data structure that enables above properties is called a Namespaced Merkle Tree (NMT), an ordered binary Merkle tree where: +1. each node in the tree includes the range of namespaces of the messages in all descendants of each node +2. leaves in the tree are ordered by the namespace identifiers of the leaf messages + +A more formal description can be found the [specification](https://github.com/celestiaorg/celestia-specs/blob/de5f4f74f56922e9fa735ef79d9e6e6492a2bad1/specs/data_structures.md#namespace-merkle-tree). +An implementation can be found in [this repository](https://github.com/celestiaorg/nmt). + +This ADR basically describes version of the [`GetWithProof`](https://github.com/celestiaorg/nmt/blob/ddcc72040149c115f83b2199eafabf3127ae12ac/nmt.go#L193-L196) of the NMT that leverages the fact that IPFS uses content addressing and that we have implemented an [IPLD plugin](https://github.com/celestiaorg/celestia-core/tree/37502aac69d755c189df37642b87327772f4ac2a/p2p/ipld) for an NMT. + +**Note**: The APIs defined here will be particularly relevant for Optimistic Rollup (full) nodes that want to download their Rollup's data (see [celestiaorg/optimint#48](https://github.com/celestiaorg/optimint/issues/48)). +Another potential use-case of this API could be for so-called [light validator nodes](https://github.com/celestiaorg/celestia-specs/blob/master/specs/node_types.md#node-type-definitions) that want to download and replay the state-relevant portion of the block data, i.e. transactions with [reserved namespace IDs](https://github.com/celestiaorg/celestia-specs/blob/master/specs/consensus.md#reserved-namespace-ids). + +## Alternative Approaches + +The approach described below will rely on IPFS' block exchange protocol (bitswap) and DHT; IPFS's implementation will be used as a black box to find peers that can serve the requested data. +This will likely be much slower than it potentially could be and for a first implementation we intentionally do not incorporate the optimizations that we could. + +We briefly mention potential optimizations for the future here: +- Use of [graphsync](https://github.com/ipld/specs/blob/5d3a3485c5fe2863d613cd9d6e18f96e5e568d16/block-layer/graphsync/graphsync.md) instead of [bitswap](https://docs.ipfs.io/concepts/bitswap/) and use of [IPLD selectors](https://github.com/ipld/specs/blob/5d3a3485c5fe2863d613cd9d6e18f96e5e568d16/design/history/exploration-reports/2018.10-selectors-design-goals.md) +- expose an API to be able to download application specific data by namespace (including proofs) with the minimal number of round-trips (e.g. finding nodes that expose an RPC endpoint like [`GetWithProof`](https://github.com/celestiaorg/nmt/blob/ddcc72040149c115f83b2199eafabf3127ae12ac/nmt.go#L193-L196)) + +## Decision + +Most discussions on this particular API happened either on calls or on other non-documented way. +We only describe the decision in this section. + +We decide to implement the simplest approach first. +We first describe the protocol informally here and explain why this fulfils (Property1) and (Property2) in the [Context](#context) section above. + +In the case that leaves with the requested namespace exist, this basically boils down to the following: traverse the tree starting from the root until finding first leaf (start) with the namespace in question, then directly request and download all leaves coming after the start until the namespace changes to a greater than the requested one again. +In the case that no leaves with the requested namespace exist in the tree, we traverse the tree to find the leaf in the position in the tree where the namespace would have been and download the neighbouring leaves. + +This is pretty much what the [`ProveNamespace`](https://github.com/celestiaorg/nmt/blob/ddcc72040149c115f83b2199eafabf3127ae12ac/nmt.go#L132-L146) method does but using IPFS we can simply locate and then request the leaves, and the corresponding inner proof nodes will automatically be downloaded on the way, too. + +## Detailed Design + +We define one function that returns all shares of a block belonging to a requested namespace and block (via the block's data availability header). +See [`ComputeShares`](https://github.com/celestiaorg/celestia-core/blob/1a08b430a8885654b6e020ac588b1080e999170c/types/block.go#L1371) for reference how encode the block data into namespace shares. + +```go +// RetrieveShares returns all raw data (raw shares) of the passed-in +// namespace ID nID and included in the block with the DataAvailabilityHeader dah. +func RetrieveShares( + ctx context.Context, + nID namespace.ID, + dah *types.DataAvailabilityHeader, + api coreiface.CoreAPI, +) ([][]byte, error) { + // 1. Find the row root(s) that contains the namespace ID nID + // 2. Traverse the corresponding tree(s) according to the + // above informally described algorithm and get the corresponding + // leaves (if any) + // 3. Return all (raw) shares corresponding to the nID +} + +``` + +Additionally, we define two functions that use the first one above to: +1. return all the parsed (non-padding) data with [reserved namespace IDs](https://github.com/celestiaorg/celestia-specs/blob/de5f4f74f56922e9fa735ef79d9e6e6492a2bad1/specs/consensus.md#reserved-namespace-ids): transactions, intermediate state roots, evidence. +2. return all application specific blobs (shares) belonging to one namespace ID parsed as a slice of Messages ([specification](https://github.com/celestiaorg/celestia-specs/blob/de5f4f74f56922e9fa735ef79d9e6e6492a2bad1/specs/data_structures.md#message) and [code](https://github.com/celestiaorg/celestia-core/blob/1a08b430a8885654b6e020ac588b1080e999170c/types/block.go#L1336)). + +The latter two methods might require moving or exporting a few currently unexported functions that (currently) live in [share_merging.go](https://github.com/celestiaorg/celestia-core/blob/1a08b430a8885654b6e020ac588b1080e999170c/types/share_merging.go#L57-L76) and could be implemented in a separate pull request. + +```go +// RetrieveStateRelevantMessages returns all state-relevant transactions +// (transactions, intermediate state roots, and evidence) included in a block +// with the DataAvailabilityHeader dah. +func RetrieveStateRelevantMessages( + ctx context.Context, + nID namespace.ID, + dah *types.DataAvailabilityHeader, + api coreiface.CoreAPI, +) (Txs, IntermediateStateRoots, EvidenceData, error) { + // like RetrieveShares but for all reserved namespaces + // additionally the shares are parsed (merged) into the + // corresponding types in the return arguments +} +``` + +```go +// RetrieveMessages returns all Messages of the passed-in +// namespace ID and included in the block with the DataAvailabilityHeader dah. +func RetrieveMessages( + ctx context.Context, + nID namespace.ID, + dah *types.DataAvailabilityHeader, + api coreiface.CoreAPI, +) (Messages, error) { + // like RetrieveShares but this additionally parsed the shares + // into the Messages type +} +``` + +## Status + +Proposed + +## Consequences + +This API will most likely be used by Rollups too. +We should document it properly and move it together with relevant parts from ADR 002 into a separate go-package. + +### Positive + +- easy to implement with the existing code (see [ADR 002](https://github.com/celestiaorg/celestia-core/blob/47d6c965704e102ae877b2f4e10aeab782d9c648/docs/adr/adr-002-ipld-da-sampling.md#detailed-design)) +- resilient data retrieval via a p2p network +- dependence on a mature and well-tested code-base with a large and welcoming community + +### Negative + +- with IPFS, we inherit the fact that potentially a lot of round-trips are done until the data is fully downloaded; in other words: this could end up way slower than potentially possible +- anyone interacting with that API needs to run an IPFS node + +### Neutral + +- optimizations can happen incrementally once we have an initial working version + +## References + +We've linked to all references throughout the ADR. diff --git a/docs/celestia-architecture/adr-004-mvp-light-client.md b/docs/celestia-architecture/adr-004-mvp-light-client.md new file mode 100644 index 0000000000..4dac26b890 --- /dev/null +++ b/docs/celestia-architecture/adr-004-mvp-light-client.md @@ -0,0 +1,292 @@ +# ADR 004: Data Availability Sampling Light Client + +## Changelog + +- 2021-05-03: Initial Draft + +## Context + +We decided to augment the existing [RPC-based Tendermint light client](https://github.com/tendermint/tendermint/blob/bc643b19c48495077e0394d3e21e1d2a52c99548/light/doc.go#L2-L126) by adding the possibility to additionally validate blocks by doing Data Availability Sampling (DAS). +In general, DAS gives light clients assurance that the data behind the block header they validated is actually available in the network and hence, that state fraud proofs could be generated. +See [ADR 002](adr-002-ipld-da-sampling.md) for more context on DAS. + +A great introduction on the Tendermint light client (and light clients in general) can be found in this series of [blog posts](https://medium.com/tendermint/everything-you-need-to-know-about-the-tendermint-light-client-f80d03856f98) as well as this [paper](https://arxiv.org/abs/2010.07031). + +This ADR describes the changes necessary to augment the existing Tendermint light client implementation with DAS from a UX as well as from a protocol perspective. + +## Alternative Approaches + +Ideally, the light client should not just request [signed headers](https://github.com/tendermint/tendermint/blob/bc643b19c48495077e0394d3e21e1d2a52c99548/light/doc.go#L35-L52) from [a few pre-configured peers](https://github.com/tendermint/tendermint/blob/bc643b19c48495077e0394d3e21e1d2a52c99548/light/setup.go#L51-L52) but instead also discover peers from a p2p network. +We will eventually implement this. For more context, we refer to this [issue](https://github.com/celestiaorg/celestia-core/issues/86). +This would require that the (signed) headers are provided via other means than the RPC. +See this [abandoned pull request](https://github.com/tendermint/tendermint/pull/4508) and [issue](https://github.com/tendermint/tendermint/issues/4456) in the Tendermint repository and also this [suggestion](https://github.com/celestiaorg/celestia-core/issues/86#issuecomment-831182564) by [@Wondertan](https://github.com/Wondertan) in this repository. + +For some use-cases—like DAS light validator nodes, or the light clients of a Data Availability Layer that are run by full nodes of an Optimistic Rollup—it would even make sense that the light client (passively) participates in the consensus protocol to some extent; i.e. runs a subset of the consensus reactor to Consensus messages ([Votes](https://github.com/tendermint/tendermint/blob/bc643b19c48495077e0394d3e21e1d2a52c99548/types/vote.go#L48-L59) etc.) come in as early as possible. +Then light clients would not need to wait for the canonical commit to be included in the next [block](https://github.com/tendermint/tendermint/blob/bc643b19c48495077e0394d3e21e1d2a52c99548/types/block.go#L48). + +For the RPC-based light client it could also make sense to add a new RPC endpoint to tendermint for clients to retrieve the [`DataAvailabilityHeader`](https://github.com/celestiaorg/celestia-core/blob/50f722a510dd2ba8e3d31931c9d83132d6318d4b/types/block.go#L52-L69) (DAHeader), or embed the DAHeader. +The [Commit](https://github.com/celestiaorg/celestia-core/blob/cbf1f1a4a0472373289a9834b0d33e0918237b7f/rpc/core/routes.go#L25) only contains the [SignedHeader](https://github.com/celestiaorg/celestia-core/blob/cbf1f1a4a0472373289a9834b0d33e0918237b7f/rpc/core/types/responses.go#L32-L36) (Header and Commit signatures). +Not all light clients will need the full DAHeader though (e.g. super-light-clients do not). + + +## Decision + +For our MVP, we [decide](https://github.com/celestiaorg/celestia-core/issues/307) to only modify the existing RPC-endpoint based light client. +This is mostly because we want to ship our MVP as quickly as possible but independently of this it makes sense to provide a familiar experience for engineers coming from the Cosmos ecosystem. + +We will later implement the above mentioned variants. +How exactly will be described in separate ADRs though. + +## Detailed Design + +From a user perspective very little changes: +the existing light client command gets an additional flag that indicates whether to run DAS or not. +Additionally, the light client operator can decide the number of successful samples to make to deem the block available (and hence valid). + +In case DAS is enabled, the light client will need to: +1. retrieve the DAHeader corresponding to the data root in the Header +2. request a parameterizable number of random samples. + +If the all sampling requests succeed, the whole block is available ([with some high enough probability](https://arxiv.org/abs/1809.09044)). + +### UX + +The main change to the light client [command](https://github.com/celestiaorg/celestia-core/blob/master/cmd/tendermint/commands/light.go#L32-L104) is to add in a new flag to indicate if it should run DAS or not. +Additionally, the user can choose the number of succeeding samples required for a block to be considered available. + +```diff +=================================================================== +diff --git a/cmd/tendermint/commands/light.go b/cmd/tendermint/commands/light.go +--- a/cmd/tendermint/commands/light.go (revision 48b043014f0243edd1e8ebad8cd0564ab9100407) ++++ b/cmd/tendermint/commands/light.go (date 1620546761822) +@@ -64,6 +64,8 @@ + dir string + maxOpenConnections int + ++ daSampling bool ++ numSamples uint32 + sequential bool + trustingPeriod time.Duration + trustedHeight int64 +@@ -101,6 +103,10 @@ + LightCmd.Flags().BoolVar(&sequential, "sequential", false, + "sequential verification. Verify all headers sequentially as opposed to using skipping verification", + ) ++ LightCmd.Flags().BoolVar(&daSampling, "da-sampling", false, ++ "data availability sampling. Verify each header (sequential verification), additionally verify data availability via data availability sampling", ++ ) ++ LightCmd.Flags().Uint32Var(&numSamples, "num-samples", 15, "Number of data availability samples until block data deemed available.") + } +``` + +For the Data Availability sampling, the light client will have to run an IPFS node. +It makes sense to make this mostly opaque to the user as everything around IPFS can be [configured](https://github.com/ipfs/go-ipfs/blob/d6322f485af222e319c893eeac51c44a9859e901/docs/config.md) in the `$IPFS_PATH`. +This IPFS path should simply be a sub-directory inside the light client's [directory](https://github.com/celestiaorg/celestia-core/blob/cbf1f1a4a0472373289a9834b0d33e0918237b7f/cmd/tendermint/commands/light.go#L86-L87). +We can later add the ability to let users configure the IPFS setup more granular. + +**Note:** DAS should only be compatible to sequential verification. +In case a light client is parametrized to run DAS and skipping verification, the CLI should return an easy-to-understand warning or even an error explaining why this does not make sense. + +### Light Client Protocol with DAS + +#### Light Store + +The light client stores data in its own [badgerdb instance](https://github.com/celestiaorg/celestia-core/blob/50f722a510dd2ba8e3d31931c9d83132d6318d4b/cmd/tendermint/commands/light.go#L125) in the given directory: + +```go +db, err := badgerdb.NewDB("light-client-db", dir) +``` + +While it is not critical for this feature, we should at least try to re-use that same DB instance for the local ipld store. +Otherwise, we introduce yet another DB instance; something we want to avoid, especially on the long run (see [#283](https://github.com/celestiaorg/celestia-core/issues/283)). +For the first implementation, it might still be simpler to create a separate DB instance and tackle cleaning this up in a separate pull request, e.g. together with other [instances]([#283](https://github.com/celestiaorg/celestia-core/issues/283)). + +#### RPC + +No changes to the RPC endpoints are absolutely required. +Although, for convenience and ease of use, we should either add the `DAHeader` to the existing [Commit](https://github.com/celestiaorg/celestia-core/blob/cbf1f1a4a0472373289a9834b0d33e0918237b7f/rpc/core/routes.go#L25) endpoint, or, introduce a new endpoint to retrieve the `DAHeader` on demand and for a certain height or block hash. + +The first has the downside that not every light client needs the DAHeader. +The second explicitly reveals to full-nodes which clients are doing DAS and which not. + +**Implementation Note:** The additional (or modified) RPC endpoint could work as a simple first step until we implement downloading the DAHeader from a given data root in the header. +Also, the light client uses a so called [`Provider`](https://github.com/tendermint/tendermint/blob/7f30bc96f014b27fbe74a546ea912740eabdda74/light/provider/provider.go#L9-L26) to retrieve [LightBlocks](https://github.com/tendermint/tendermint/blob/7f30bc96f014b27fbe74a546ea912740eabdda74/types/light.go#L11-L16), i.e. signed headers and validator sets. +Currently, only the [`http` provider](https://github.com/tendermint/tendermint/blob/7f30bc96f014b27fbe74a546ea912740eabdda74/light/provider/http/http.go#L1) is implemented. +Hence, as _a first implementation step_, we should augment the `Provider` and the `LightBlock` to optionally include the DAHeader (details below). +In parallel but in a separate pull request, we add a separate RPC endpoint to download the DAHeader for a certain height. + +#### Store DataAvailabilityHeader + +For full nodes to be able to serve the `DataAvailabilityHeader` without having to recompute it each time, it needs to be stored somewhere. +While this is independent of the concrete serving mechanism, it is more so relevant for the RPC endpoint. +There is ongoing work to make the Tendermint Store only store Headers and the DataAvailabilityHeader in [#218](https://github.com/celestiaorg/celestia-core/pull/218/) / [#182](https://github.com/celestiaorg/celestia-core/issues/182). + +At the time writing this ADR, another pull request ([#312](https://github.com/celestiaorg/celestia-core/pull/312)) is in the works with a more isolated change that adds the `DataAvailabilityHeader` to the `BlockID`. +Hence, the DAHeader is [stored](https://github.com/celestiaorg/celestia-core/blob/50f722a510dd2ba8e3d31931c9d83132d6318d4b/store/store.go#L355-L367) along the [`BlockMeta`](https://github.com/celestiaorg/celestia-core/blob/50f722a510dd2ba8e3d31931c9d83132d6318d4b/types/block_meta.go#L11-L17) there. + +For a first implementation, we could first build on top of #312 and adapt to the changed storage API where only headers and the DAHeader are stored inside tendermint's store (as drafted in #218). +A major downside of storing block data inside of tendermint's store as well as in the IPFS' block store is that is not only redundantly stored data but also IO intense work that will slow down full nodes. + + +#### DAS + +The changes for DAS are very simple from a high-level perspective assuming that the light client has the ability to download the DAHeader along with the required data (signed header + validator set) of a given height: + +Every time the light client validates a retrieved light-block, it additionally starts DAS in the background (once). +For a DAS light client it is important to use [sequential](https://github.com/tendermint/tendermint/blob/f366ae3c875a4f4f61f37f4b39383558ac5a58cc/light/client.go#L46-L53) verification and not [skipping](https://github.com/tendermint/tendermint/blob/f366ae3c875a4f4f61f37f4b39383558ac5a58cc/light/client.go#L55-L69) verification. +Skipping verification only works under the assumption that 2/3+1 of voting power is honest. +The whole point of doing DAS (and state fraud proofs) is to remove that assumption. +See also this related issue in the LL specification: [#159](https://github.com/celestiaorg/celestia-specs/issues/159). + +Independent of the existing implementation, there are three ways this could be implemented: +1. the DAS light client only accepts a header as valid and trusts it after DAS succeeds (additionally to the tendermint verification), and it waits until DAS succeeds (or there was an error or timeout on the way) +2. (aka 1.5) the DAS light client stages headers where the tendermint verification passes as valid and spins up DAS sampling rotines in the background; the staged headers are committed as valid iff all routines successfully return in time +3. the DAS light client optimistically accepts a header as valid and trusts it if the regular tendermint verification succeeds; the DAS is run in the background (with potentially much longer timeouts as in 1.) and after the background routine returns (or errs or times out), the already trusted headers are marked as unavailable; this might require rolling back the already trusted headers + +We note that from an implementation point of view 1. is not only the simplest approach, but it would also work best with the currently implemented light client design. +It is the approach that should be implemented first. + +The 2. approach can be seen as an optimization where the higher latency DAS can be conducted in parallel for various heights. +This could speed up catching-up (sequentially) if the light client went offline (shorter than the weak subjectivity time window). + +The 3. approach is the most general of all, but it moves the responsibility to wait or to rollback headers to the caller and hence is undesirable as it offers too much flexibility. + + +#### Data Structures + +##### LightBlock + +As mentioned above the LightBlock should optionally contain the DataAvailabilityHeader. +```diff +Index: types/light.go +=================================================================== +diff --git a/types/light.go b/types/light.go +--- a/types/light.go (revision 64044aa2f2f2266d1476013595aa33bb274ba161) ++++ b/types/light.go (date 1620481205049) +@@ -13,6 +13,9 @@ + type LightBlock struct { + *SignedHeader `json:"signed_header"` + ValidatorSet *ValidatorSet `json:"validator_set"` ++ ++ // DataAvailabilityHeader is only populated for DAS light clients for others it can be nil. ++ DataAvailabilityHeader *DataAvailabilityHeader `json:"data_availability_header"` + } +``` + +Alternatively, we could introduce a `DASLightBlock` that embeds a `LightBlock` and has the `DataAvailabilityHeader` as the only (non-optional) field. +This would be more explict as it is a new type. +Instead, adding a field to the existing `LightBlock`is backwards compatible and does not require any further code changes; the new type requires `To`- and `FromProto` functions at least. + +##### Provider + +The [`Provider`](https://github.com/tendermint/tendermint/blob/7f30bc96f014b27fbe74a546ea912740eabdda74/light/provider/provider.go#L9-L26) should be changed to additionally provide the `DataAvailabilityHeader` to enable DAS light clients. +Implementations of the interface need to additionally retrieve the `DataAvailabilityHeader` for the [modified LightBlock](#lightblock). +Users of the provider need to indicate this to the provider. + +We could either augment the `LightBlock` method with a flag, add a new method solely for providing the `DataAvailabilityHeader`, or, we could introduce a new method for DAS light clients. + +The latter is preferable because it is the most explicit and clear, and it still keeps places where DAS is not used without any code changes. + +Hence: + +```diff +Index: light/provider/provider.go +=================================================================== +diff --git a/light/provider/provider.go b/light/provider/provider.go +--- a/light/provider/provider.go (revision 7d06ae28196e8765c9747aca9db7d2732f56cfc3) ++++ b/light/provider/provider.go (date 1620298115962) +@@ -21,6 +21,14 @@ + // error is returned. + LightBlock(ctx context.Context, height int64) (*types.LightBlock, error) + ++ // DASLightBlock returns the LightBlock containing the DataAvailabilityHeader. ++ // Other than including the DataAvailabilityHeader it behaves exactly the same ++ // as LightBlock. ++ // ++ // It can be used by DAS light clients. ++ DASLightBlock(ctx context.Context, height int64) (*types.LightBlock, error) ++ ++ + // ReportEvidence reports an evidence of misbehavior. + ReportEvidence(context.Context, types.Evidence) error + } +``` +Alternatively, with the exact same result, we could embed the existing `Provider` into a new interface: e.g. `DASProvider` that adds this method. +This is completely equivalent as above and which approach is better will become more clear when we spent more time on the implementation. + +Regular light clients will call `LightBlock` and DAS light clients will call `DASLightBlock`. +In the first case the result will be the same as for vanilla Tendermint and in the second case the returned `LightBlock` will additionally contain the `DataAvailabilityHeader` of the requested height. + +#### Running an IPFS node + +We already have methods to [initialize](https://github.com/celestiaorg/celestia-core/blob/cbf1f1a4a0472373289a9834b0d33e0918237b7f/cmd/tendermint/commands/init.go#L116-L157) and [run](https://github.com/celestiaorg/celestia-core/blob/cbf1f1a4a0472373289a9834b0d33e0918237b7f/node/node.go#L1449-L1488) an IPFS node in place. +These need to be refactored such that they can effectively be for the light client as well. +This means: +1. these methods need to be exported and available in a place that does not introduce interdependence of go packages +2. users should be able to run a light client with a single command and hence most of the initialization logic should be coupled with creating the actual IPFS node and [made independent](https://github.com/celestiaorg/celestia-core/blob/cbf1f1a4a0472373289a9834b0d33e0918237b7f/cmd/tendermint/commands/init.go#L119-L120) of the `tendermint init` command + +An example for 2. can be found in the IPFS [code](https://github.com/ipfs/go-ipfs/blob/cd72589cfd41a5397bb8fc9765392bca904b596a/cmd/ipfs/daemon.go#L239) itself. +We might want to provide a slightly different default initialization though (see how this is [overridable](https://github.com/ipfs/go-ipfs/blob/cd72589cfd41a5397bb8fc9765392bca904b596a/cmd/ipfs/daemon.go#L164-L165) in the ipfs daemon cmd). + +We note that for operating a fully functional light client the IPFS node could be running in client mode [`dht.ModeClient`](https://github.com/libp2p/go-libp2p-kad-dht/blob/09d923fcf68218181b5cd329bf5199e767bd33c3/dht_options.go#L29-L30) but be actually want light clients to also respond to incoming queries, e.g. from other light clients. +Hence, they should by default run in [`dht.ModeServer`](https://github.com/libp2p/go-libp2p-kad-dht/blob/09d923fcf68218181b5cd329bf5199e767bd33c3/dht_options.go#L31-L32). +In an environment were any bandwidth must be saved, or, were the network conditions do not allow the server mode, we make it easy to change the default behavior. + +##### Client + +We add another [`Option`](https://github.com/tendermint/tendermint/blob/a91680efee3653e3de620f24eb8ddca1c95ce8f9/light/client.go#L43-L117) to the [`Client`](https://github.com/tendermint/tendermint/blob/a91680efee3653e3de620f24eb8ddca1c95ce8f9/light/client.go#L173) that indicates that this client does DAS. + +This option indicates: +1. to do sequential verification and +2. to request [`DASLightBlocks`](#lightblock) from the [provider](#provider). + +All other changes should only affect unexported methods only. + +##### ValidateAvailability + +In order for the light clients to perform DAS to validate availability, they do not need to be aware of the fact that an IPFS node is run. +Instead, we can use the existing [`ValidateAvailability`](https://github.com/celestiaorg/celestia-core/blame/master/p2p/ipld/validate.go#L23-L28) function (as defined in [ADR 002](adr-002-ipld-da-sampling.md) and implemented in [#270](https://github.com/celestiaorg/celestia-core/pull/270)). +Note that this expects an ipfs core API object `CoreAPI` to be passed in. +Using that interface has the major benefit that we could even change the requirement that the light client itself runs the IPFS node without changing most of the validation logic. +E.g., the IPFS node (with our custom IPLD plugin) could run in different process (or machine), and we could still just pass in that same `CoreAPI` interface. + +Orthogonal to this ADR, we also note that we could change all IPFS readonly methods to accept the minimal interface they actually use, namely something that implements `ResolveNode` (and maybe additionally a `NodeGetter`). + +`ValidateAvailability` needs to be called each time a header is validated. +A DAS light client will have to request the `DASLightBlock` for this as per above to be able to pass in a `DataAvailabilityHeader`. + +#### Testing + +Ideally, we add the DAS light client to the existing e2e tests. +It might be worth to catch up with some relevant changes from tendermint upstream. +In particular, [tendermint/tendermint#6196](https://github.com/tendermint/tendermint/pull/6196) and previous changes that it depends on. + +Additionally, we should provide a simple example in the documentation that walks through the DAS light client. +It would be good if the light client logs some (info) output related to DAS to provide feedback to the user. + +## Status + +Proposed + +## Consequences + +### Positive + +- simple to implement and understand +- familiar to tendermint / Cosmos devs +- allows trying out the MVP without relying on the [celestia-app](https://github.com/celestiaorg/celestia-app) (instead a simple abci app like a modified [KVStore](https://github.com/celestiaorg/celestia-core/blob/42e4e8b58ebc58ebd663c114d2bcd7ab045b1c55/abci/example/kvstore/README.md) app could be used to demo the DAS light client) + +### Negative + +- light client does not discover peers +- requires the light client that currently runs simple RPC requests only to run an IPFS node +- rpc makes it extremely easy to infer which light clients are doing DAS and which not +- the initial light client implementation might still be confusing to devs familiar to tendermint/Cosmos for the reason that it does DAS (and state fraud proofs) to get rid of the underlying honest majority assumption, but it will still do all checks related to that same honest majority assumption (e.g. download validator sets, Commits and validate that > 2/3 of them signed the header) + +### Neutral + +DAS light clients need to additionally obtain the DAHeader from the data root in the header to be able to actually do DAS. + +## References + +We have linked all references above inside the text already. diff --git a/docs/celestia-architecture/adr-005-decouple-blockid-and-partsetheader.md b/docs/celestia-architecture/adr-005-decouple-blockid-and-partsetheader.md new file mode 100644 index 0000000000..1bf8fa7416 --- /dev/null +++ b/docs/celestia-architecture/adr-005-decouple-blockid-and-partsetheader.md @@ -0,0 +1,47 @@ +# ADR 005: Decouple the PartSetHeader from the BlockID + +## Changelog + +- 2021-08-01: Initial Draft + +## Context + +Celestia has multiple commits to the block data via the `DataHash` and the `PartSetHeader` in the `BlockID`. As stated in the [#184](https://github.com/celestiaorg/lazyledger-core/issues/184), we no longer need the `PartSetHeader` for this additional commitment to the block's data. However, we are still planning to use the `PartSetHeader` for block propagation during consensus in the short-medium term. This means that we will remove the `PartSetHeader` from as many places as possible, but keep it in the `Proposal` struct. + +## Alternative Approaches + +It’s worth noting that there are proposed changes to remove the `PartSetHeader` entirely, and instead use the already existing commitment to block data, the `DataAvailabilityHeader`, to propagate blocks in parallel during consensus. Discussions regarding the detailed differences entailed in each approach are documented in that ADR's PR. The current direction that is described in this ADR is significantly more conservative in its approach, but it is not strictly an alternative to other designs. This is because other designs would also require removal of the `PartSethHeader`, which is a project in and of itself due to the `BlockID` widespread usage throughout tendermint and the bugs that pop up when attempting to remove it. + +## Decision + +While we build other better designs to experiment with, we will continue to implement the design specified here as it is not orthogonal. https://github.com/celestiaorg/lazyledger-core/pull/434#issuecomment-869158788 + +## Detailed Design + +- [X] Decouple the BlockID and the PartSetHeader [#441](https://github.com/celestiaorg/lazyledger-core/pull/441) +- [ ] Remove the BlockID from every possible struct other than the `Proposal` + - [X] Stop signing over the `PartSetHeader` while voting [#457](https://github.com/celestiaorg/lazyledger-core/pull/457) + - [X] Remove the `PartSetHeader` from the Header [#457](https://github.com/celestiaorg/lazyledger-core/pull/457) + - [X] Remove the `PartSetHeader` from `VoteSetBits`, `VoteSetMaj23`, and `state.State` [#479](https://github.com/celestiaorg/lazyledger-core/pull/479) + - [ ] Remove the `PartSetHeader` from other structs + + +## Status + +Proposed + +### Positive + +- Conservative and easy to implement +- Acts as a stepping stone for other better designs +- Allows us to use 64kb sized chunks, which are well tested + +### Negative + +- Not an ideal design as we still have to include an extra commitment to the block's data in the proposal + +## References + +Alternative ADR [#434](https://github.com/celestiaorg/lazyledger-core/pull/434) +Alternative implementation [#427](https://github.com/celestiaorg/lazyledger-core/pull/427) and [#443](https://github.com/celestiaorg/lazyledger-core/pull/443) +[Comment](https://github.com/celestiaorg/lazyledger-core/pull/434#issuecomment-869158788) that summarizes decision \ No newline at end of file diff --git a/docs/celestia-architecture/adr-006-row-propoagation.md b/docs/celestia-architecture/adr-006-row-propoagation.md new file mode 100644 index 0000000000..6fd2f3652e --- /dev/null +++ b/docs/celestia-architecture/adr-006-row-propoagation.md @@ -0,0 +1,202 @@ +# ADR 006: Consensus Block Gossiping with Rows + +## Changelog +* 24.06.2021 - Initial description +* 07.07.2021 - More important details were added +* 18.08.2021 - Mention alternative approaches briefly + +## Context +It's a long story of relations between Celestia, Tendermint, and consensus block gossiping. Celestia's team discussed +multiple ideas, several ADRs were made, and nothing yet was finalized. This ADR is another attempt to bring valuable +changes into block gossiping and hopefully successful. + +Currently, we inherit the following from Tendermint. Our codebase relies on the blocks Parts notion. Each Part is a +piece of an entire serialized block. Those Parts are gossiped between nodes in consensus and committed with +`PartSetHeader` containing a Merkle Root of the Parts. However, Parts gossiping wasn't designed for Celestia blocks. + +Celestia comes with a different block representation from Tendermint. It lays out Blocks as a table of data shares, +where Rows or Columns can be and should be gossiped instead of Parts, keeping only one system-wide commitment to data. + +## Alternative Approaches +### ["nah it works just don't touch it"](https://ahseeit.com//king-include/uploads/2020/11/121269295_375504380484919_2997236194077828589_n-6586327691.jpg) approach + +It turns out that we could fully treat the Tendermint consensus as a black box, keeping two data commitments: one for +consensus with `PartSetHeader` and another for the world outside the consensus with `DAHeader`. + +#### Pros +* Less work + +### Others +* get rid of the PartsHeader from BlockID without changing block propagation at all (see [ADR 005](https://github.com/celestiaorg/celestia-core/blob/58a3901827afbf97852d807de34a2b66f93e0eb6/docs/lazy-adr/adr-005-decouple-blockid-and-partsetheader.md#adr-005-decouple-the-partsetheader-from-the-blockid)) +* change block propagation to fixed-sized chunks but based on the ODS instead of how Parts are built currently (for this we have empirical evidence of how it performs in practice) +* send the block as a whole (only works with smaller blocks) +* block propagation-based on sending the header and Tx-IDs and then requesting the Tx/Messages that are missing from the local mempool of a node on demand + +#### Cons +* Pulls two data commitments to Celestia's specs +* Brings ambiguity to data integrity verification +* Controversial from software design perspective +* Brings DOSing vector for big Blocks. Every Block would need to be represented in two formats in RAM +* Wastes more resources on building and verifying additional + +## Decision +The decision is to still treat Tendermint's consensus as a black box, but with few amendments to gossiping mechanism: +* Introduce `RowSet` that mimics `PartSet`. + + `RowSet` is a helper structure that wraps DAHeader and tracks received Rows with their integrity against DAHeader and + tells its user when the block is complete and/or can be recovered. Mostly it is a helper and is not a high-level + concept. +* Replace `PartSet` with `RowSet` within consensus. +* Keep `DAHeader` in `Proposal` +* Remove `PartSetHeader` from `Proposal` + +The changes above are required to implement the decision. At later point, other changes listed below are +likely to be implemented as a clean-up: +* Entirely removing `PartSetHeader`, as redundant data commitment +* Removing `PartSet` +* Relying on `DAHeader` instead of `PartSetHeader` + +## Detailed Design +The detailed design section demonstrates the design and supporting changes package by package. Fortunately, the +design does not affect any public API and changes are solely internal. + +### `types` +#### RowSet and Row +First and essential part is to implement `RowSet` and `Row`, fully mimicking semantics of `PartSet` and `Part` to +decrease the number of required changes. Below, implementation semantics are presented: + +```go +// Row represents a blob of multiple ExtendedDataSquare shares. +// Practically, it is half of an extended row, as other half can be recomputed. +type Row struct { +// Index is an top-to-bottom index of a Row in ExtendedDataSquare. +// NOTE: Row Index is unnecessary, as we can determine it's Index by hash from DAHeader. However, Index removal +// would bring more changes to Consensus Reactor with arguable pros of less bandwidth usage. +Index int +// The actual share blob. +Data []byte +} + +// NewRow creates new Row from flattened shares and index. +func NewRow(idx int, row [][]byte) *Row + +// RowSet wraps DAHeader and tracks added Rows with their integrity against DAHeader. +// It allows user to check whenever rsmt2d.ExtendedDataSquare can be recovered. +// +// RowSet tracks the whole ExtendedDataSquare, Where Q0 is the original block data: +// ---- ---- +// | Q0 || Q1 | +// ---- ---- +// | Q2 || Q3 | +// ---- ---- +// +// But its AddRow and GetRow methods accepts and returns only half of the Rows - Q0 and Q2. Q1 and Q3 are recomputed. +// ---- +// | Q0 | +// ---- +// | Q2 | +// ---- +// +type RowSet interface { +// NOTE: The RowSet is defined as an interface for simplicity. In practice it should be a struct with one and only +// implementation. + +// AddRow adds a Row to the set. It returns true with nil error in case Row was successfully added. +// The logic for Row is: +// * Check if it was already added +// * Verify its size corresponds to DAHeader +// * Extend it with erasure coding and compute a NMT Root over it +// * Verify that the NMT Root corresponds to DAHeader Root under its Index +// * Finally add it to set and mark as added. +// +AddRow(*Row) (bool, error) + +// GetRow return of a Row by its index, if exist. +GetRow(i int) *Row + +// Square checks if enough rows were added and returns recomputed ExtendedDataSquare if enough +Square() (*rsmt2d.ExtendedDataSquare, error) + +// other helper methods are omitted +} + +// NewRowSet creates full RowSet from rsmt2d.ExtendedDataSquare to gossip it to others through GetRow. +func NewRowSet(eds *rsmt2d.ExtendedDataSquare) *RowSet + +// NewRowSetFromHeader creates empty RowSet from a DAHeader to receive and verify gossiped Rows against the DAHeader +// with AddRow. +func NewRowSetFromHeader(dah *ipld.DataAvailabilityHeader) *RowSet +``` + +#### Vote +`Vote` should include a commitment to data. Previously, it relied on `PartSetHeader` in `BlockId`, instead it relies on +added `DAHeader`. Protobuf schema is updated accordingly. + +#### Proposal +`Proposal` is extended with `NumOriginalDataShares`. This is an optimization that +helps Validators to populate Header without counting original data shares themselves from a block received form a +Proposer. Potentially, that introduce a vulnerability by which a Proposer can send wrong value, leaving the populated +Header of Validators wrong. This part of the decision is optional. + +### `consenSUS` +#### Reactor +##### Messages +The decision affects two messages on consensus reactor: +* `BlockPartMessage` -> `BlockRowMessage` + * Instead of `Part` it carries `Row` defined above. +* `NewValidBlockMessage` + * Instead of `PartSetHeader` it carries `DAHeader` + * `BitArray` of `RowSet` instead of `PartSet` + Protobuf schema for both is updated accordingly. + +##### PeerRoundState +`PeerRoundState` tracks state of each known peer in a round, specifically what commitment it has for a Block and what +chunks peer holds. The decision changes it to track `DAHeader` instead of `PartSetHeader`, along with `BitArray` of +`RowSet` instead of `PartSet`. + +##### BlockCatchup +The Reactor helps its peers to catchup if they go out of sync. Instead of sending random `Part` it now sends random +`Row` by `BlockRowMessage`. Unfortunately, that requires the Reactor to load whole Block from store. As an optimization, +an ability to load Row only from the store could be introduced at later point. + +#### State +##### RoundState +The RoundState keeps Proposal, Valid and Lock Block's data. Along with an entire Block and its Parts, the RoundState +also keeps Rows using `RowSet`. At later point, `PartSet` that tracks part can be removed. + +##### Proposal Stage +Previously, the State in proposal stage waited for all Parts to assemble the entire Block. Instead, the State waits for +the half of all Rows from a proposer and/or peers to recompute the Block's data and notifies them back that no more +needs to be sent. Also, through Rows, only minimally required amount of information is gossiped. Everything else to +assemble the full Block is collected from own chain State and Proposal. + +## Status +Proposed + +## Consequences +### Positive +* Hardening of consensus gossiping with erasure coding +* Blocks exceeding the size limit are immediately rejected on Proposal, without the need to download an entire Block. +* More control over Row message size during consensus, comparing to Part message, as last part of the block always has + unpredictable size. `DAHeader`, on the other hand, allows knowing precisely the size of Row messages. +* Less bandwidth usage + * Only required Block's data is gossiped. + * Merkle proofs of Parts are not sent on the wire +* Only one system-wide block data commitment schema +* We don't abandon the work we were doing for months and taking profits out of it + * PR [#287](https://github.com/celestiaorg/lazyledger-core/pull/287) + * PR [#312](https://github.com/celestiaorg/lazyledger-core/pull/312) + * PR [#427](https://github.com/celestiaorg/lazyledger-core/pull/427) + * and merged others + +### Negative +* We invest some more time(~1.5 weeks). + * Most of the work is done. Only few changes left in the implementation along with peer reviews. + +### Neutral +* Rows vs Parts on the wire + * Previously, parts were propagated with max size of 64KiB. Let's now take a Row of the largest 128x128 block in + comparison. The actual data size in such a case for the Row would be 128x256(shares_per_row*share_size)=32KiB, which + is exactly two times smaller than a Part. +* Gossiped chunks are no longer constant size. Instead, their size is proportional to the size of Block's data. +* Another step back from original Tendermint's codebases \ No newline at end of file diff --git a/docs/celestia-architecture/adr-007-minimal-changes-to-tendermint.md b/docs/celestia-architecture/adr-007-minimal-changes-to-tendermint.md new file mode 100644 index 0000000000..486e25f233 --- /dev/null +++ b/docs/celestia-architecture/adr-007-minimal-changes-to-tendermint.md @@ -0,0 +1,234 @@ +# ADR 007: From Ukraine, with Love + +## Changelog + +- 20-08-2021: Initial Description + +## Context + +Currently, our fork of tendermint includes changes to how to erasure block data, minor changes to the header to commit +to that data, additions to serve data availability sampling, along with some miscellaneous modification to adhere to the +spec. Instead of incorporating all of these changes into our fork of tendermint, we will only make the strictly +necessary changes and the other services and their code to the new celestia-node repo. Notably, we will also refactor +some of the remaining necessary changes to be more isolated from the rest of the tendermint codebase. Both of these +strategies should significantly streamline pulling updates from upstream, and allow us to iterate faster since most +changes will be isolated to celestia-node. + +## Decision + +Treat tendermint more as a "black box". + +## Detailed Design + +### Overview + +We keep the bare-minimum changes to tendermint in our fork, celestia-core. Where necessary and possible we augment the +tendermint node in a separate process, via celestia-node, which communicates with the tendermint node via RPC. All data +availability sampling logic, including all Celestia-specific networking logic not already provided by tendermint, is +moved into celestia node: + +![](./img/core-node-relation.png) + +The detailed design of celestia-node will be defined in the repository itself. + +### Necessary changes to tendermint + +#### Changing the repo import names to celestiaorg + +- Rebrand (https://github.com/celestiaorg/celestia-core/pull/476) + +#### Changes to the README.md other basic things + +- update github templates (https://github.com/celestiaorg/celestia-core/pull/405) +- update README.md (https://github.com/celestiaorg/celestia-core/pull/10) + +#### Adding the extra types of block data + +- Update core data types (https://github.com/celestiaorg/celestia-core/pull/17) + - Create the Message/Messages types + - Proto and the tendermint version + - Create the IntermediateStateRoots type + - Proto and the tendermint version +- Data availability for evidence (https://github.com/celestiaorg/celestia-core/pull/19) + - Add both types to `types.Data` + - Modify proto + - Add `EvidenceData` to `types.Data` + +#### Add the HeaderHash to the Commit + +- Add header hash to commit(https://github.com/celestiaorg/celestia-core/pull/198) + +#### Adding the consts package in types + +#### Remove iavl as a dependency + +- remove iavl as a dependency (https://github.com/celestiaorg/celestia-core/pull/129) + +#### Using the `DataAvailabilityHeader` to calculate the DataHash + +The `DataAvailabilityHeader` struct will be used by celestia-core as well as by the celestia-node. It might make sense +to (eventually) move the struct together with all the DA-related code into a separate repository and go-module. +@Wondertan explored this as part of [#427](https://github.com/celestiaorg/celestia-core/pull/427#issue-674512464). This +way all client implementations can depend on that module without running into circular dependencies. Hence, we only +describe how to hash the block data here: + +- Update core types (https://github.com/celestiaorg/celestia-core/pull/17) + - Replace the `Data.Hash()` with `DAH.Hash()` + - Use DAH to fill DataHash when filling the header + - Fill the DAH when making a block to generate the data hash + +#### Add availableDataOriginalSharesUsed to the header + +- Add availableDataOriginalSharesUsed to the header (https://github.com/celestiaorg/celestia-core/pull/262) + +#### Reap some number of transactions probably using the app or some other mech + +- Enforce a minimum square size (https://github.com/celestiaorg/celestia-core/pull/282) +- Use squares with a width that is a power of two(https://github.com/celestiaorg/celestia-core/pull/331) +- Adopt reamping from the mempool to max square size (https://github.com/celestiaorg/celestia-core/issues/77) +- Proposal: Decide on a mech to pick square size and communicate that to the + app (https://github.com/celestiaorg/celestia-core/issues/454) +- Also see ABCI++ for a less hacky solution + +#### Filling the DAH using share merging and splitting + +- Compute Shares (not merged) (https://github.com/celestiaorg/celestia-core/pull/60) + - part II (not merged) (https://github.com/celestiaorg/celestia-core/pull/63) + - while this was not merged, we will need some function to compute the shares that make up the block data +- Share Splitting (https://github.com/celestiaorg/celestia-core/pull/246) + - Serialize each constituent of block data + - Split into shares + - Txs (contiguous) + - Messages (not contiguous) + - Evidence (contiguous) + - IntermediateStateRoots (contiguous) +- Combine shares into original square +- ExtendBlockData +- Generate nmt root of each row and col +- Use those roots to generate the DataHash +- Share Merging (https://github.com/celestiaorg/celestia-core/pull/261) + - Sort by namespace + - Parse each reserved type + - Parse remaining messages + +#### Add the wrapper around nmt to erasure namespaces + +- Implement rsmt tree wrapper for nmt (https://github.com/celestiaorg/celestia-core/pull/238) + +#### Add PreprocessTxs to ABCI + +- Add PreprocessTxs method to ABCI (https://github.com/celestiaorg/celestia-core/pull/110) +- Add method to ABCI interface +- Create sync and async versions +- Add sync version the the CreateProposalBlock method of BlockExecutor + +#### Fill the DAH while making the block + +- Basic DA functionality (https://github.com/celestiaorg/celestia-core/pull/83) + +#### Only produce blocks on some interval + +- Control block times (https://github.com/tendermint/tendermint/issues/5911) + +#### Stop signing over the PartSetHeader + +- Replace canonical blockID with just a hash in the CononicalVote +- Replace the LastBlockID in the header with just a hash + +#### Optionally remove some unused code + +- Removing misc unsued code (https://github.com/celestiaorg/celestia-core/pull/208) +- Remove docs deployment (https://github.com/celestiaorg/celestia-core/pull/134) +- Start deleting docs (https://github.com/celestiaorg/celestia-core/pull/209) +- Remove tendermint-db in favor of badgerdb (https://github.com/celestiaorg/celestia-core/pull/241) +- Delete blockchain 2 until further notice (https://github.com/celestiaorg/celestia-core/pull/309) +- We don’t need to support using out of process apps + +#### Nice to Haves + +- More efficient hashing (https://github.com/celestiaorg/celestia-core/pull/351) + +We should also take this opportunity to refactor as many additions to tendermint into their own package as possible. +This will hopefully make updating to future versions of tendermint easier. For example, when we fill the data +availability header, instead of using a method on `Block`, it could be handled by a function that takes `types.Data` as +input and returns the DAH, the number of shares used in the square, along with the obligatory error. + +```go +func FillDataAvailabilityHeader(data types.Data) (types.DataAvailabilityHeader, numOrigDataShares, error) +``` + +We could perform a similar treatment to the `splitIntoShares` methods and their helper method `ComputeShares`. Instead +of performing the share splitting logic in those methods, we could keep it in a different package and instead call the +equivalent function to compute the shares. + +Beyond refactoring and some minor additions, we will also have to remove and revert quite a few changes to get to the +minimum desired changes specified above. + +### Changes that will need to be reverted + +#### IPLD Plugin + +- Introduction (https://github.com/celestiaorg/celestia-core/pull/144) +- Initial integration (https://github.com/celestiaorg/celestia-core/pull/152) +- Custom Multihash (https://github.com/celestiaorg/celestia-core/pull/155) +- Puting data during proposal (https://github.com/celestiaorg/celestia-core/pull/178) +- Module name (https://github.com/celestiaorg/celestia-core/pull/151) +- Update rsmt2d (https://github.com/celestiaorg/celestia-core/pull/290) +- Make plugin a package (https://github.com/celestiaorg/celestia-core/pull/294) + +#### Adding DAH to Stuff + +- Adding DAH to Proposal (https://github.com/celestiaorg/celestia-core/pull/248/files) +- Blockmeta (https://github.com/celestiaorg/celestia-core/pull/372) + +#### Embedding DAS + +- GetLeafData (https://github.com/celestiaorg/celestia-core/pull/212) +- RetrieveBlockData (https://github.com/celestiaorg/celestia-core/pull/232) +- ValidateAvailability (https://github.com/celestiaorg/celestia-core/pull/270) +- Prevent double writes to IPFS (https://github.com/celestiaorg/celestia-core/pull/271) +- Stop Pinning (https://github.com/celestiaorg/celestia-core/pull/276) +- Rework IPFS Node (https://github.com/celestiaorg/celestia-core/pull/334) +- Refactor for putting the block (https://github.com/celestiaorg/celestia-core/pull/338) +- Config for IPFS node (https://github.com/celestiaorg/celestia-core/pull/340) +- IPLD Dag instead of CoreAPI (https://github.com/celestiaorg/celestia-core/pull/352) +- Adding the DAG to the blockstore (https://github.com/celestiaorg/celestia-core/pull/356) +- Saving and Loading using IPFS (https://github.com/celestiaorg/celestia-core/pull/374) +- Manual Providing (https://github.com/celestiaorg/celestia-core/pull/375) +- Refactor node provider (https://github.com/celestiaorg/celestia-core/pull/400) +- DAS in light client workaround (https://github.com/celestiaorg/celestia-core/pull/413) + +#### BlockID and PartSetHeader + +- Decouple ParSetHeader from BlockID (https://github.com/celestiaorg/celestia-core/pull/441) +- Stop Signing over the PartSetHeader (https://github.com/celestiaorg/celestia-core/pull/457) +- We still don’t want to sign over the PartSetHeader, but we will not be able to use the same mechanism used in the + linked PR, as that way requires decoupling of the PSH from the BlockID +- Remove PSH from some consensus messages (https://github.com/celestiaorg/celestia-core/pull/479) + +Note: This ADR overrides ADR 005 Decouple BlockID and the PartSetHeader. The PartSetHeader and the BlockID will mostly +remain the same. This will make pulling changes from upstream much easier + +## Status + +Accepted + +## Consequences + +### Positive + +- Pulling changes from upstream is streamlined +- Separation of functionality will help us iterate faster +- Creates a great opportunity for reconsidering past design choices without fully starting from scratch +- Prepare for future designs +- Don’t have to have two p2p stacks in a single repo + +### Negative + +- Perform some computation multiple times +- Running multiple nodes instead of a single node is less convenient for node operators (but only in the case the full + celestia-node wants to participate in the consensus protocol) + +## References + +Tracking Issue #491 \ No newline at end of file diff --git a/docs/celestia-architecture/adr-template.md b/docs/celestia-architecture/adr-template.md new file mode 100644 index 0000000000..c36879bcec --- /dev/null +++ b/docs/celestia-architecture/adr-template.md @@ -0,0 +1,72 @@ +# ADR {ADR-NUMBER}: {TITLE} + +## Changelog + +- {date}: {changelog} + +## Context + +> This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution. + +## Alternative Approaches + +> This section contains information around alternative options that are considered before making a decision. It should contain a explanation on why the alternative approach(es) were not chosen. + +## Decision + +> This section records the decision that was made. +> It is best to record as much info as possible from the discussion that happened. This aids in not having to go back to the Pull Request to get the needed information. + +## Detailed Design + +> This section does not need to be filled in at the start of the ADR, but must be completed prior to the merging of the implementation. +> +> Here are some common questions that get answered as part of the detailed design: +> +> - What are the user requirements? +> +> - What systems will be affected? +> +> - What new data structures are needed, what data structures will be changed? +> +> - What new APIs will be needed, what APIs will be changed? +> +> - What are the efficiency considerations (time/space)? +> +> - What are the expected access patterns (load/throughput)? +> +> - Are there any logging, monitoring or observability needs? +> +> - Are there any security considerations? +> +> - Are there any privacy considerations? +> +> - How will the changes be tested? +> +> - If the change is large, how will the changes be broken up for ease of review? +> +> - Will these changes require a breaking (major) release? +> +> - Does this change require coordination with the Celestia fork of the SDK or celestia-app? + +## Status + +> A decision may be "proposed" if it hasn't been agreed upon yet, or "accepted" once it is agreed upon. Once the ADR has been implemented mark the ADR as "implemented". If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement. + +{Deprecated|Proposed|Accepted|Declined} + +## Consequences + +> This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones. + +### Positive + +### Negative + +### Neutral + +## References + +> Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here! + +- {reference link} diff --git a/docs/celestia-architecture/assets/user-request.png b/docs/celestia-architecture/assets/user-request.png new file mode 100644 index 0000000000000000000000000000000000000000..3d04fad73492780741d547f7280e765742c30cbd GIT binary patch literal 397363 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 z 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ξ3U4p+5JIEGWS#m@k-hvpd!HG(SK&Z&pb4x|aGu=$$IhmI zoXv@MD9g?$mz_I#tUh0wvQKTqM`r)e$cTlys>6z7&t?~@PO^Rsa!E+WJum+^dlWQ2 zJQ}q2)SYGePB@=vc|Lk{$`9mM&0!Js*EdsjiizhFlZofYS}r>&Sx&O?hNX6wi3<~D z1`cv{kNtd{?Rwp7>*oQt&o2j=%HGL3Gq_Db)&H~zy!1Q$M!W9kM6NKW1gLYj7XUO||A+CWtWv2GL zzDCl%v;pwlIyJSA3AW~ct-E2yy*3|nFKo2KA#4B3ZKAKOQ)-GPMi(7(eeU*=QSwPR z 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

9e@by)1D@Qf#^*qa8RgBjGV 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 literal 0 HcmV?d00001 diff --git a/docs/celestia-architecture/img/extended_square.png b/docs/celestia-architecture/img/extended_square.png new file mode 100644 index 0000000000000000000000000000000000000000..8bbf4695053f4f2ca7aa5a46c9869631ebd3ef79 GIT binary patch literal 13803 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 literal 0 HcmV?d00001 From a54e3599a5ef6b2ba8b63f586aed8185a3f59e4d Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Fri, 21 Jan 2022 07:16:36 -0600 Subject: [PATCH 11/31] Index malleated transactions properly (#612) * index malleated transactions properly * linter * fix malleated transaction indexing and event tracking * fix malleated event test * fix test * fix other test * update proto building and formatting to use the latest tendermint specs style generation and formatting * fix app tests linter fix max size tests --- Makefile | 5 +- abci/types/types.pb.go | 394 ++++++++++++---------- internal/mempool/v0/clist_mempool.go | 13 +- internal/mempool/v0/clist_mempool_test.go | 17 +- internal/state/execution.go | 19 +- internal/state/indexer/tx/kv/kv.go | 8 +- internal/state/indexer/tx/kv/kv_test.go | 43 +++ node/node_test.go | 4 +- proto/tendermint/abci/types.proto | 9 +- proto/tendermint/types/block.proto | 6 +- proto/tendermint/types/types.pb.go | 301 +++++++++-------- proto/tendermint/types/types.proto | 11 +- types/block.go | 6 +- types/block_test.go | 16 +- types/event_bus.go | 10 +- types/event_bus_test.go | 52 +++ types/tx.go | 41 ++- 17 files changed, 577 insertions(+), 378 deletions(-) diff --git a/Makefile b/Makefile index c9836956b3..3eff0095e6 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,9 @@ BUILDDIR ?= $(CURDIR)/build BUILD_TAGS?=tendermint +IMAGE := ghcr.io/tendermint/docker-build-proto:latest +DOCKER_PROTO_BUILDER := docker run -v $(shell pwd):/workspace --workdir /workspace $(IMAGE) + # If building a release, please checkout the version tag to get the correct version setting ifneq ($(shell git symbolic-ref -q --short HEAD),) VERSION := unreleased-$(shell git symbolic-ref -q --short HEAD)-$(shell git rev-parse HEAD) @@ -80,7 +83,7 @@ $(BUILDDIR)/: ### Protobuf ### ############################################################################### -proto-all: proto-gen proto-lint proto-check-breaking +proto-all: proto-lint proto-check-breaking .PHONY: proto-all proto-gen: diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 6b00c587a1..4fbebc6acc 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -2529,10 +2529,11 @@ func (m *EventAttribute) GetIndex() bool { // // One usage is indexing transaction results. type TxResult struct { - Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` - Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` - Tx []byte `protobuf:"bytes,3,opt,name=tx,proto3" json:"tx,omitempty"` - Result ResponseDeliverTx `protobuf:"bytes,4,opt,name=result,proto3" json:"result"` + Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` + Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` + Tx []byte `protobuf:"bytes,3,opt,name=tx,proto3" json:"tx,omitempty"` + Result ResponseDeliverTx `protobuf:"bytes,4,opt,name=result,proto3" json:"result"` + OriginalHash []byte `protobuf:"bytes,5,opt,name=original_hash,json=originalHash,proto3" json:"original_hash,omitempty"` } func (m *TxResult) Reset() { *m = TxResult{} } @@ -2596,6 +2597,13 @@ func (m *TxResult) GetResult() ResponseDeliverTx { return ResponseDeliverTx{} } +func (m *TxResult) GetOriginalHash() []byte { + if m != nil { + return m.OriginalHash + } + return nil +} + // Validator type Validator struct { Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` @@ -2964,172 +2972,173 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 2627 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0xcd, 0x73, 0xdb, 0xc6, - 0x15, 0xe7, 0x37, 0x89, 0x47, 0x91, 0xa2, 0xd6, 0x8a, 0x43, 0x33, 0xb6, 0xe4, 0xc0, 0xe3, 0x34, - 0x76, 0x12, 0xa9, 0x91, 0xc7, 0xae, 0x33, 0xe9, 0x47, 0x44, 0x9a, 0x2e, 0x15, 0xab, 0x92, 0xba, - 0xa2, 0x9d, 0x49, 0xdb, 0x18, 0x01, 0x89, 0x15, 0x89, 0x98, 0x04, 0x10, 0x60, 0x29, 0x4b, 0x39, - 0x76, 0xda, 0x8b, 0xa7, 0x07, 0x1f, 0x7b, 0xc9, 0x4c, 0xff, 0x83, 0x5e, 0x7b, 0xea, 0xa9, 0x87, - 0x1c, 0xda, 0x99, 0x1c, 0x7b, 0xe8, 0xa4, 0x1d, 0xfb, 0xd6, 0x7f, 0xa0, 0xa7, 0xce, 0x74, 0xf6, - 0x03, 0x20, 0x40, 0x12, 0x22, 0xd5, 0xf4, 0xd6, 0xdb, 0xee, 0xc3, 0x7b, 0x8f, 0xbb, 0x6f, 0xf7, - 0xfd, 0xf6, 0xb7, 0x6f, 0x09, 0xaf, 0x51, 0x62, 0x19, 0xc4, 0x1d, 0x9a, 0x16, 0xdd, 0xd4, 0x3b, - 0x5d, 0x73, 0x93, 0x9e, 0x3a, 0xc4, 0xdb, 0x70, 0x5c, 0x9b, 0xda, 0x68, 0x79, 0xfc, 0x71, 0x83, - 0x7d, 0xac, 0x5d, 0x09, 0x69, 0x77, 0xdd, 0x53, 0x87, 0xda, 0x9b, 0x8e, 0x6b, 0xdb, 0x47, 0x42, - 0xbf, 0x76, 0x39, 0xf4, 0x99, 0xfb, 0x09, 0x7b, 0x8b, 0x7c, 0x95, 0xc6, 0x4f, 0xc8, 0xa9, 0xff, - 0xf5, 0xca, 0x94, 0xad, 0xa3, 0xbb, 0xfa, 0xd0, 0xff, 0xbc, 0xde, 0xb3, 0xed, 0xde, 0x80, 0x6c, - 0xf2, 0x5e, 0x67, 0x74, 0xb4, 0x49, 0xcd, 0x21, 0xf1, 0xa8, 0x3e, 0x74, 0xa4, 0xc2, 0x6a, 0xcf, - 0xee, 0xd9, 0xbc, 0xb9, 0xc9, 0x5a, 0x42, 0xaa, 0xfe, 0x25, 0x0f, 0x79, 0x4c, 0x3e, 0x1f, 0x11, - 0x8f, 0xa2, 0x2d, 0xc8, 0x90, 0x6e, 0xdf, 0xae, 0x26, 0xaf, 0x26, 0xdf, 0x2c, 0x6e, 0x5d, 0xde, - 0x98, 0x98, 0xdc, 0x86, 0xd4, 0x6b, 0x76, 0xfb, 0x76, 0x2b, 0x81, 0xb9, 0x2e, 0xba, 0x0d, 0xd9, - 0xa3, 0xc1, 0xc8, 0xeb, 0x57, 0x53, 0xdc, 0xe8, 0x4a, 0x9c, 0xd1, 0x7d, 0xa6, 0xd4, 0x4a, 0x60, - 0xa1, 0xcd, 0x7e, 0xca, 0xb4, 0x8e, 0xec, 0x6a, 0xfa, 0xec, 0x9f, 0xda, 0xb1, 0x8e, 0xf8, 0x4f, - 0x31, 0x5d, 0x54, 0x07, 0x30, 0x2d, 0x93, 0x6a, 0xdd, 0xbe, 0x6e, 0x5a, 0xd5, 0x0c, 0xb7, 0x7c, - 0x3d, 0xde, 0xd2, 0xa4, 0x0d, 0xa6, 0xd8, 0x4a, 0x60, 0xc5, 0xf4, 0x3b, 0x6c, 0xb8, 0x9f, 0x8f, - 0x88, 0x7b, 0x5a, 0xcd, 0x9e, 0x3d, 0xdc, 0x9f, 0x32, 0x25, 0x36, 0x5c, 0xae, 0x8d, 0x9a, 0x50, - 0xec, 0x90, 0x9e, 0x69, 0x69, 0x9d, 0x81, 0xdd, 0x7d, 0x52, 0xcd, 0x71, 0x63, 0x35, 0xce, 0xb8, - 0xce, 0x54, 0xeb, 0x4c, 0xb3, 0x95, 0xc0, 0xd0, 0x09, 0x7a, 0xe8, 0xfb, 0x50, 0xe8, 0xf6, 0x49, - 0xf7, 0x89, 0x46, 0x4f, 0xaa, 0x79, 0xee, 0x63, 0x3d, 0xce, 0x47, 0x83, 0xe9, 0xb5, 0x4f, 0x5a, - 0x09, 0x9c, 0xef, 0x8a, 0x26, 0x9b, 0xbf, 0x41, 0x06, 0xe6, 0x31, 0x71, 0x99, 0x7d, 0xe1, 0xec, - 0xf9, 0xdf, 0x13, 0x9a, 0xdc, 0x83, 0x62, 0xf8, 0x1d, 0xf4, 0x23, 0x50, 0x88, 0x65, 0xc8, 0x69, - 0x28, 0xdc, 0xc5, 0xd5, 0xd8, 0x75, 0xb6, 0x0c, 0x7f, 0x12, 0x05, 0x22, 0xdb, 0xe8, 0x2e, 0xe4, - 0xba, 0xf6, 0x70, 0x68, 0xd2, 0x2a, 0x70, 0xeb, 0xb5, 0xd8, 0x09, 0x70, 0xad, 0x56, 0x02, 0x4b, - 0x7d, 0xb4, 0x07, 0xe5, 0x81, 0xe9, 0x51, 0xcd, 0xb3, 0x74, 0xc7, 0xeb, 0xdb, 0xd4, 0xab, 0x16, - 0xb9, 0x87, 0xeb, 0x71, 0x1e, 0x76, 0x4d, 0x8f, 0x1e, 0xfa, 0xca, 0xad, 0x04, 0x2e, 0x0d, 0xc2, - 0x02, 0xe6, 0xcf, 0x3e, 0x3a, 0x22, 0x6e, 0xe0, 0xb0, 0xba, 0x74, 0xb6, 0xbf, 0x7d, 0xa6, 0xed, - 0xdb, 0x33, 0x7f, 0x76, 0x58, 0x80, 0x7e, 0x0e, 0x17, 0x06, 0xb6, 0x6e, 0x04, 0xee, 0xb4, 0x6e, - 0x7f, 0x64, 0x3d, 0xa9, 0x96, 0xb8, 0xd3, 0x1b, 0xb1, 0x83, 0xb4, 0x75, 0xc3, 0x77, 0xd1, 0x60, - 0x06, 0xad, 0x04, 0x5e, 0x19, 0x4c, 0x0a, 0xd1, 0x63, 0x58, 0xd5, 0x1d, 0x67, 0x70, 0x3a, 0xe9, - 0xbd, 0xcc, 0xbd, 0xdf, 0x8c, 0xf3, 0xbe, 0xcd, 0x6c, 0x26, 0xdd, 0x23, 0x7d, 0x4a, 0x5a, 0xcf, - 0x43, 0xf6, 0x58, 0x1f, 0x8c, 0x88, 0xfa, 0x1d, 0x28, 0x86, 0xd2, 0x14, 0x55, 0x21, 0x3f, 0x24, - 0x9e, 0xa7, 0xf7, 0x08, 0xcf, 0x6a, 0x05, 0xfb, 0x5d, 0xb5, 0x0c, 0x4b, 0xe1, 0xd4, 0x54, 0x9f, - 0x27, 0x03, 0x4b, 0x96, 0x75, 0xcc, 0xf2, 0x98, 0xb8, 0x9e, 0x69, 0x5b, 0xbe, 0xa5, 0xec, 0xa2, - 0x6b, 0x50, 0xe2, 0xfb, 0x47, 0xf3, 0xbf, 0xb3, 0xd4, 0xcf, 0xe0, 0x25, 0x2e, 0x7c, 0x24, 0x95, - 0xd6, 0xa1, 0xe8, 0x6c, 0x39, 0x81, 0x4a, 0x9a, 0xab, 0x80, 0xb3, 0xe5, 0xf8, 0x0a, 0xaf, 0xc3, - 0x12, 0x9b, 0x69, 0xa0, 0x91, 0xe1, 0x3f, 0x52, 0x64, 0x32, 0xa9, 0xa2, 0xfe, 0x39, 0x05, 0x95, - 0xc9, 0x74, 0x46, 0x77, 0x21, 0xc3, 0x90, 0x4d, 0x82, 0x54, 0x6d, 0x43, 0xc0, 0xde, 0x86, 0x0f, - 0x7b, 0x1b, 0x6d, 0x1f, 0xf6, 0xea, 0x85, 0xaf, 0xbe, 0x59, 0x4f, 0x3c, 0xff, 0xfb, 0x7a, 0x12, - 0x73, 0x0b, 0x74, 0x89, 0x65, 0x9f, 0x6e, 0x5a, 0x9a, 0x69, 0xf0, 0x21, 0x2b, 0x2c, 0xb5, 0x74, - 0xd3, 0xda, 0x31, 0xd0, 0x2e, 0x54, 0xba, 0xb6, 0xe5, 0x11, 0xcb, 0x1b, 0x79, 0x9a, 0x80, 0x55, - 0x09, 0x4d, 0x91, 0x04, 0x13, 0x60, 0xdd, 0xf0, 0x35, 0x0f, 0xb8, 0x22, 0x5e, 0xee, 0x46, 0x05, - 0xe8, 0x3e, 0xc0, 0xb1, 0x3e, 0x30, 0x0d, 0x9d, 0xda, 0xae, 0x57, 0xcd, 0x5c, 0x4d, 0xcf, 0xcc, - 0xb2, 0x47, 0xbe, 0xca, 0x43, 0xc7, 0xd0, 0x29, 0xa9, 0x67, 0xd8, 0x70, 0x71, 0xc8, 0x12, 0xbd, - 0x01, 0xcb, 0xba, 0xe3, 0x68, 0x1e, 0xd5, 0x29, 0xd1, 0x3a, 0xa7, 0x94, 0x78, 0x1c, 0xb6, 0x96, - 0x70, 0x49, 0x77, 0x9c, 0x43, 0x26, 0xad, 0x33, 0x21, 0xba, 0x0e, 0x65, 0x86, 0x70, 0xa6, 0x3e, - 0xd0, 0xfa, 0xc4, 0xec, 0xf5, 0x29, 0x07, 0xa8, 0x34, 0x2e, 0x49, 0x69, 0x8b, 0x0b, 0x55, 0x23, - 0x58, 0x71, 0x8e, 0x6e, 0x08, 0x41, 0xc6, 0xd0, 0xa9, 0xce, 0x23, 0xb9, 0x84, 0x79, 0x9b, 0xc9, - 0x1c, 0x9d, 0xf6, 0x65, 0x7c, 0x78, 0x1b, 0x5d, 0x84, 0x9c, 0x74, 0x9b, 0xe6, 0x6e, 0x65, 0x0f, - 0xad, 0x42, 0xd6, 0x71, 0xed, 0x63, 0xc2, 0x97, 0xae, 0x80, 0x45, 0x47, 0xfd, 0x55, 0x0a, 0x56, - 0xa6, 0x70, 0x90, 0xf9, 0xed, 0xeb, 0x5e, 0xdf, 0xff, 0x2d, 0xd6, 0x46, 0x77, 0x98, 0x5f, 0xdd, - 0x20, 0xae, 0x3c, 0x3b, 0xaa, 0xd3, 0xa1, 0x6e, 0xf1, 0xef, 0x32, 0x34, 0x52, 0x1b, 0xed, 0x43, - 0x65, 0xa0, 0x7b, 0x54, 0x13, 0xb8, 0xa2, 0x85, 0xce, 0x91, 0x69, 0x34, 0xdd, 0xd5, 0x7d, 0x24, - 0x62, 0x9b, 0x5a, 0x3a, 0x2a, 0x0f, 0x22, 0x52, 0x84, 0x61, 0xb5, 0x73, 0xfa, 0x85, 0x6e, 0x51, - 0xd3, 0x22, 0xda, 0xd4, 0xca, 0x5d, 0x9a, 0x72, 0xda, 0x3c, 0x36, 0x0d, 0x62, 0x75, 0xfd, 0x25, - 0xbb, 0x10, 0x18, 0x07, 0x4b, 0xea, 0xa9, 0x18, 0xca, 0x51, 0x24, 0x47, 0x65, 0x48, 0xd1, 0x13, - 0x19, 0x80, 0x14, 0x3d, 0x41, 0xdf, 0x85, 0x0c, 0x9b, 0x24, 0x9f, 0x7c, 0x79, 0xc6, 0x11, 0x28, - 0xed, 0xda, 0xa7, 0x0e, 0xc1, 0x5c, 0x53, 0x55, 0x83, 0x74, 0x08, 0xd0, 0x7d, 0xd2, 0xab, 0x7a, - 0x03, 0x96, 0x27, 0xe0, 0x3b, 0xb4, 0x7e, 0xc9, 0xf0, 0xfa, 0xa9, 0xcb, 0x50, 0x8a, 0x60, 0xb5, - 0x7a, 0x11, 0x56, 0x67, 0x41, 0xaf, 0xda, 0x0f, 0xe4, 0x11, 0x08, 0x45, 0xb7, 0xa1, 0x10, 0x60, - 0xaf, 0x48, 0xc7, 0xe9, 0x58, 0xf9, 0xca, 0x38, 0x50, 0x65, 0x79, 0xc8, 0xb6, 0x35, 0xdf, 0x0f, - 0x29, 0x3e, 0xf0, 0xbc, 0xee, 0x38, 0x2d, 0xdd, 0xeb, 0xab, 0x9f, 0x42, 0x35, 0x0e, 0x57, 0x27, - 0xa6, 0x91, 0x09, 0xb6, 0xe1, 0x45, 0xc8, 0x1d, 0xd9, 0xee, 0x50, 0xa7, 0xdc, 0x59, 0x09, 0xcb, - 0x1e, 0xdb, 0x9e, 0x02, 0x63, 0xd3, 0x5c, 0x2c, 0x3a, 0xaa, 0x06, 0x97, 0x62, 0xb1, 0x95, 0x99, - 0x98, 0x96, 0x41, 0x44, 0x3c, 0x4b, 0x58, 0x74, 0xc6, 0x8e, 0xc4, 0x60, 0x45, 0x87, 0xfd, 0xac, - 0xc7, 0xe7, 0xca, 0xfd, 0x2b, 0x58, 0xf6, 0xd4, 0xdf, 0x15, 0xa0, 0x80, 0x89, 0xe7, 0x30, 0x4c, - 0x40, 0x75, 0x50, 0xc8, 0x49, 0x97, 0x38, 0xd4, 0x87, 0xd1, 0xd9, 0xac, 0x41, 0x68, 0x37, 0x7d, - 0x4d, 0x76, 0x64, 0x07, 0x66, 0xe8, 0x96, 0x64, 0x65, 0xf1, 0x04, 0x4b, 0x9a, 0x87, 0x69, 0xd9, - 0x1d, 0x9f, 0x96, 0xa5, 0x63, 0x4f, 0x69, 0x61, 0x35, 0xc1, 0xcb, 0x6e, 0x49, 0x5e, 0x96, 0x99, - 0xf3, 0x63, 0x11, 0x62, 0xd6, 0x88, 0x10, 0xb3, 0xec, 0x9c, 0x69, 0xc6, 0x30, 0xb3, 0x3b, 0x3e, - 0x33, 0xcb, 0xcd, 0x19, 0xf1, 0x04, 0x35, 0xbb, 0x1f, 0xa5, 0x66, 0x82, 0x56, 0x5d, 0x8b, 0xb5, - 0x8e, 0xe5, 0x66, 0x3f, 0x08, 0x71, 0xb3, 0x42, 0x2c, 0x31, 0x12, 0x4e, 0x66, 0x90, 0xb3, 0x46, - 0x84, 0x9c, 0x29, 0x73, 0x62, 0x10, 0xc3, 0xce, 0x3e, 0x08, 0xb3, 0x33, 0x88, 0x25, 0x78, 0x72, - 0xbd, 0x67, 0xd1, 0xb3, 0xf7, 0x02, 0x7a, 0x56, 0x8c, 0xe5, 0x97, 0x72, 0x0e, 0x93, 0xfc, 0x6c, - 0x7f, 0x8a, 0x9f, 0x09, 0x3e, 0xf5, 0x46, 0xac, 0x8b, 0x39, 0x04, 0x6d, 0x7f, 0x8a, 0xa0, 0x95, - 0xe6, 0x38, 0x9c, 0xc3, 0xd0, 0x7e, 0x31, 0x9b, 0xa1, 0xc5, 0x73, 0x28, 0x39, 0xcc, 0xc5, 0x28, - 0x9a, 0x16, 0x43, 0xd1, 0x96, 0xb9, 0xfb, 0xb7, 0x62, 0xdd, 0x9f, 0x9f, 0xa3, 0xdd, 0x60, 0x27, - 0xe4, 0x44, 0xce, 0x33, 0x94, 0x21, 0xae, 0x6b, 0xbb, 0x92, 0x6d, 0x89, 0x8e, 0xfa, 0x26, 0x3b, - 0xb3, 0xc7, 0xf9, 0x7d, 0x06, 0x9f, 0xe3, 0x68, 0x1e, 0xca, 0x69, 0xf5, 0x0f, 0xc9, 0xb1, 0x2d, - 0x3f, 0xe6, 0xc2, 0xe7, 0xbd, 0x22, 0xcf, 0xfb, 0x10, 0xcb, 0x4b, 0x45, 0x59, 0xde, 0x3a, 0x14, - 0x19, 0x4a, 0x4f, 0x10, 0x38, 0xdd, 0x09, 0x08, 0xdc, 0x4d, 0x58, 0xe1, 0xc7, 0xb0, 0xe0, 0x82, - 0x12, 0x9a, 0x33, 0xfc, 0x84, 0x59, 0x66, 0x1f, 0xc4, 0xe6, 0x14, 0x18, 0xfd, 0x0e, 0x5c, 0x08, - 0xe9, 0x06, 0xe8, 0x2f, 0xd8, 0x4c, 0x25, 0xd0, 0xde, 0x96, 0xc7, 0xc0, 0x9f, 0x92, 0xe3, 0x08, - 0x8d, 0x99, 0xdf, 0x2c, 0x92, 0x96, 0xfc, 0x1f, 0x91, 0xb4, 0xd4, 0x7f, 0x4d, 0xd2, 0xc2, 0xa7, - 0x59, 0x3a, 0x7a, 0x9a, 0xfd, 0x2b, 0x39, 0x5e, 0x93, 0x80, 0x72, 0x75, 0x6d, 0x83, 0xc8, 0xf3, - 0x85, 0xb7, 0x51, 0x05, 0xd2, 0x03, 0xbb, 0x27, 0x4f, 0x11, 0xd6, 0x64, 0x5a, 0x01, 0x08, 0x2b, - 0x12, 0x63, 0x83, 0xa3, 0x29, 0xcb, 0x23, 0x2c, 0x8f, 0xa6, 0x0a, 0xa4, 0x9f, 0x10, 0x01, 0x99, - 0x4b, 0x98, 0x35, 0x99, 0x1e, 0xdf, 0x64, 0x1c, 0x08, 0x97, 0xb0, 0xe8, 0xa0, 0xbb, 0xa0, 0xf0, - 0x32, 0x84, 0x66, 0x3b, 0x9e, 0x44, 0xb7, 0xd7, 0xc2, 0x73, 0x15, 0xd5, 0x86, 0x8d, 0x03, 0xa6, - 0xb3, 0xef, 0x78, 0xb8, 0xe0, 0xc8, 0x56, 0xe8, 0xd4, 0x55, 0x22, 0xe4, 0xef, 0x32, 0x28, 0x6c, - 0xf4, 0x9e, 0xa3, 0x77, 0x09, 0x87, 0x2a, 0x05, 0x8f, 0x05, 0xea, 0x63, 0x40, 0xd3, 0x80, 0x8b, - 0x5a, 0x90, 0x23, 0xc7, 0xc4, 0xa2, 0x6c, 0xd9, 0x58, 0xb8, 0x2f, 0xce, 0x60, 0x56, 0xc4, 0xa2, - 0xf5, 0x2a, 0x0b, 0xf2, 0x3f, 0xbf, 0x59, 0xaf, 0x08, 0xed, 0xb7, 0xed, 0xa1, 0x49, 0xc9, 0xd0, - 0xa1, 0xa7, 0x58, 0xda, 0xab, 0x7f, 0x4b, 0x31, 0x9a, 0x13, 0x01, 0xe3, 0x99, 0xb1, 0xf5, 0xb7, - 0x7c, 0x2a, 0x44, 0x71, 0x17, 0x8b, 0xf7, 0x1a, 0x40, 0x4f, 0xf7, 0xb4, 0xa7, 0xba, 0x45, 0x89, - 0x21, 0x83, 0x1e, 0x92, 0xa0, 0x1a, 0x14, 0x58, 0x6f, 0xe4, 0x11, 0x43, 0xb2, 0xed, 0xa0, 0x1f, - 0x9a, 0x67, 0xfe, 0xdb, 0xcd, 0x33, 0x1a, 0xe5, 0xc2, 0x44, 0x94, 0x43, 0x14, 0x44, 0x09, 0x53, - 0x10, 0x36, 0x36, 0xc7, 0x35, 0x6d, 0xd7, 0xa4, 0xa7, 0x7c, 0x69, 0xd2, 0x38, 0xe8, 0xb3, 0xcb, - 0xdb, 0x90, 0x0c, 0x1d, 0xdb, 0x1e, 0x68, 0x02, 0x6e, 0x8a, 0xdc, 0x74, 0x49, 0x0a, 0x9b, 0x1c, - 0x75, 0x7e, 0x9d, 0x1a, 0xe7, 0xdf, 0x98, 0x6a, 0xfe, 0xdf, 0x05, 0x58, 0xfd, 0x0d, 0xbf, 0x80, - 0x46, 0x8f, 0x5b, 0x74, 0x08, 0x2b, 0x41, 0xfa, 0x6b, 0x23, 0x0e, 0x0b, 0xfe, 0x86, 0x5e, 0x14, - 0x3f, 0x2a, 0xc7, 0x51, 0xb1, 0x87, 0x3e, 0x86, 0x57, 0x27, 0xb0, 0x2d, 0x70, 0x9d, 0x5a, 0x14, - 0xe2, 0x5e, 0x89, 0x42, 0x9c, 0xef, 0x7a, 0x1c, 0xac, 0xf4, 0xb7, 0xcc, 0xba, 0x1d, 0x76, 0xa7, - 0x09, 0xb3, 0x87, 0x99, 0xcb, 0x7f, 0x0d, 0x4a, 0x2e, 0xa1, 0xec, 0x9e, 0x1d, 0xb9, 0x35, 0x2e, - 0x09, 0xa1, 0xbc, 0x8b, 0x1e, 0xc0, 0x2b, 0x33, 0x59, 0x04, 0xfa, 0x1e, 0x28, 0x63, 0x02, 0x92, - 0x8c, 0xb9, 0x80, 0x05, 0x97, 0x8a, 0xb1, 0xae, 0xfa, 0xc7, 0xe4, 0xd8, 0x65, 0xf4, 0x9a, 0xd2, - 0x84, 0x9c, 0x4b, 0xbc, 0xd1, 0x40, 0x5c, 0x1c, 0xca, 0x5b, 0xef, 0x2c, 0xc6, 0x3f, 0x98, 0x74, - 0x34, 0xa0, 0x58, 0x1a, 0xab, 0x8f, 0x21, 0x27, 0x24, 0xa8, 0x08, 0xf9, 0x87, 0x7b, 0x0f, 0xf6, - 0xf6, 0x3f, 0xda, 0xab, 0x24, 0x10, 0x40, 0x6e, 0xbb, 0xd1, 0x68, 0x1e, 0xb4, 0x2b, 0x49, 0xa4, - 0x40, 0x76, 0xbb, 0xbe, 0x8f, 0xdb, 0x95, 0x14, 0x13, 0xe3, 0xe6, 0x87, 0xcd, 0x46, 0xbb, 0x92, - 0x46, 0x2b, 0x50, 0x12, 0x6d, 0xed, 0xfe, 0x3e, 0xfe, 0xc9, 0x76, 0xbb, 0x92, 0x09, 0x89, 0x0e, - 0x9b, 0x7b, 0xf7, 0x9a, 0xb8, 0x92, 0x55, 0xdf, 0x65, 0x37, 0x93, 0x18, 0xc6, 0x32, 0xbe, 0x83, - 0x24, 0x43, 0x77, 0x10, 0xf5, 0xb7, 0x29, 0xa8, 0xc5, 0xd3, 0x10, 0xf4, 0xe1, 0xc4, 0xc4, 0xb7, - 0xce, 0xc1, 0x61, 0x26, 0x66, 0x8f, 0xae, 0x43, 0xd9, 0x25, 0x47, 0x84, 0x76, 0xfb, 0x82, 0x16, - 0x89, 0x23, 0xb3, 0x84, 0x4b, 0x52, 0xca, 0x8d, 0x3c, 0xa1, 0xf6, 0x19, 0xe9, 0x52, 0x4d, 0x60, - 0x91, 0xd8, 0x74, 0x0a, 0x53, 0x63, 0xd2, 0x43, 0x21, 0x54, 0x3f, 0x3d, 0x57, 0x2c, 0x15, 0xc8, - 0xe2, 0x66, 0x1b, 0x7f, 0x5c, 0x49, 0x23, 0x04, 0x65, 0xde, 0xd4, 0x0e, 0xf7, 0xb6, 0x0f, 0x0e, - 0x5b, 0xfb, 0x2c, 0x96, 0x17, 0x60, 0xd9, 0x8f, 0xa5, 0x2f, 0xcc, 0xaa, 0x9f, 0x40, 0x39, 0x7a, - 0xf7, 0x67, 0x21, 0x74, 0xed, 0x91, 0x65, 0xf0, 0x60, 0x64, 0xb1, 0xe8, 0xa0, 0xdb, 0x90, 0x3d, - 0xb6, 0x45, 0x9a, 0xcd, 0xde, 0x6b, 0x8f, 0x6c, 0x4a, 0x42, 0xb5, 0x03, 0xa1, 0xad, 0x7e, 0x01, - 0x59, 0x9e, 0x35, 0x2c, 0x03, 0xf8, 0x2d, 0x5e, 0x92, 0x2a, 0xd6, 0x46, 0x9f, 0x00, 0xe8, 0x94, - 0xba, 0x66, 0x67, 0x34, 0x76, 0xbc, 0x3e, 0x3b, 0xeb, 0xb6, 0x7d, 0xbd, 0xfa, 0x65, 0x99, 0x7e, - 0xab, 0x63, 0xd3, 0x50, 0x0a, 0x86, 0x1c, 0xaa, 0x7b, 0x50, 0x8e, 0xda, 0xfa, 0x34, 0x40, 0x8c, - 0x21, 0x4a, 0x03, 0x04, 0xab, 0x93, 0x34, 0x20, 0x20, 0x11, 0x69, 0x51, 0xb1, 0xe1, 0x1d, 0xf5, - 0x59, 0x12, 0x0a, 0xed, 0x13, 0xb9, 0x1e, 0x31, 0xc5, 0x82, 0xb1, 0x69, 0x2a, 0x7c, 0x35, 0x16, - 0xd5, 0x87, 0x74, 0x50, 0xd3, 0xf8, 0x20, 0xd8, 0x71, 0x99, 0x45, 0x6f, 0x40, 0x7e, 0x71, 0x47, - 0x66, 0xd9, 0xfb, 0xa0, 0x04, 0x98, 0xc9, 0xd8, 0xa9, 0x6e, 0x18, 0x2e, 0xf1, 0x3c, 0xb9, 0xef, - 0xfd, 0x2e, 0xaf, 0x3d, 0xd9, 0x4f, 0xe5, 0xe5, 0x3b, 0x8d, 0x45, 0x47, 0x35, 0x60, 0x79, 0x02, - 0x70, 0xd1, 0xfb, 0x90, 0x77, 0x46, 0x1d, 0xcd, 0x0f, 0xcf, 0xc4, 0x5b, 0x83, 0xcf, 0x7b, 0x46, - 0x9d, 0x81, 0xd9, 0x7d, 0x40, 0x4e, 0xfd, 0xc1, 0x38, 0xa3, 0xce, 0x03, 0x11, 0x45, 0xf1, 0x2b, - 0xa9, 0xf0, 0xaf, 0x1c, 0x43, 0xc1, 0xdf, 0x14, 0xe8, 0x87, 0xa0, 0x04, 0x58, 0x1e, 0x94, 0x24, - 0x63, 0x0f, 0x01, 0xe9, 0x7e, 0x6c, 0xc2, 0x48, 0xb4, 0x67, 0xf6, 0x2c, 0x62, 0x68, 0x63, 0x7e, - 0xcc, 0x7f, 0xad, 0x80, 0x97, 0xc5, 0x87, 0x5d, 0x9f, 0x1c, 0xab, 0xff, 0x4e, 0x42, 0xc1, 0x2f, - 0x3d, 0xa1, 0x77, 0x43, 0xfb, 0xae, 0x3c, 0xe3, 0xa2, 0xee, 0x2b, 0x8e, 0xcb, 0x47, 0xd1, 0xb1, - 0xa6, 0xce, 0x3f, 0xd6, 0xb8, 0x3a, 0xa0, 0x5f, 0x91, 0xcd, 0x9c, 0xbb, 0x22, 0xfb, 0x36, 0x20, - 0x6a, 0x53, 0x7d, 0xa0, 0x1d, 0xdb, 0xd4, 0xb4, 0x7a, 0x9a, 0x08, 0xb6, 0xe0, 0x02, 0x15, 0xfe, - 0xe5, 0x11, 0xff, 0x70, 0xc0, 0xe3, 0xfe, 0xcb, 0x24, 0x14, 0x02, 0x50, 0x3f, 0x6f, 0x35, 0xe8, - 0x22, 0xe4, 0x24, 0x6e, 0x89, 0x72, 0x90, 0xec, 0x05, 0x85, 0xc9, 0x4c, 0xa8, 0x30, 0x59, 0x83, - 0xc2, 0x90, 0x50, 0x9d, 0x9f, 0x6c, 0xe2, 0x8a, 0x12, 0xf4, 0x6f, 0xbe, 0x07, 0xc5, 0x50, 0x61, - 0x8e, 0x65, 0xde, 0x5e, 0xf3, 0xa3, 0x4a, 0xa2, 0x96, 0x7f, 0xf6, 0xe5, 0xd5, 0xf4, 0x1e, 0x79, - 0xca, 0xf6, 0x2c, 0x6e, 0x36, 0x5a, 0xcd, 0xc6, 0x83, 0x4a, 0xb2, 0x56, 0x7c, 0xf6, 0xe5, 0xd5, - 0x3c, 0x26, 0xbc, 0x48, 0x70, 0xb3, 0x05, 0x4b, 0xe1, 0x55, 0x89, 0x42, 0x1f, 0x82, 0xf2, 0xbd, - 0x87, 0x07, 0xbb, 0x3b, 0x8d, 0xed, 0x76, 0x53, 0x7b, 0xb4, 0xdf, 0x6e, 0x56, 0x92, 0xe8, 0x55, - 0xb8, 0xb0, 0xbb, 0xf3, 0xe3, 0x56, 0x5b, 0x6b, 0xec, 0xee, 0x34, 0xf7, 0xda, 0xda, 0x76, 0xbb, - 0xbd, 0xdd, 0x78, 0x50, 0x49, 0x6d, 0xfd, 0x5e, 0x81, 0xe5, 0xed, 0x7a, 0x63, 0x87, 0xc1, 0xb6, - 0xd9, 0xd5, 0xf9, 0xfd, 0xb1, 0x01, 0x19, 0x7e, 0x43, 0x3c, 0xf3, 0xd9, 0xae, 0x76, 0x76, 0xf9, - 0x08, 0xdd, 0x87, 0x2c, 0xbf, 0x3c, 0xa2, 0xb3, 0xdf, 0xf1, 0x6a, 0x73, 0xea, 0x49, 0x6c, 0x30, - 0x3c, 0x3d, 0xce, 0x7c, 0xd8, 0xab, 0x9d, 0x5d, 0x5e, 0x42, 0x18, 0x94, 0x31, 0xf9, 0x9c, 0xff, - 0xd0, 0x55, 0x5b, 0x00, 0x6c, 0xd0, 0x2e, 0xe4, 0xfd, 0xfb, 0xc2, 0xbc, 0xa7, 0xb7, 0xda, 0xdc, - 0xfa, 0x0f, 0x0b, 0x97, 0xb8, 0xd7, 0x9d, 0xfd, 0x8e, 0x58, 0x9b, 0x53, 0xcc, 0x42, 0x3b, 0x90, - 0x93, 0x84, 0x6a, 0xce, 0x73, 0x5a, 0x6d, 0x5e, 0x3d, 0x87, 0x05, 0x6d, 0x7c, 0x63, 0x9e, 0xff, - 0x3a, 0x5a, 0x5b, 0xa0, 0x4e, 0x87, 0x1e, 0x02, 0x84, 0x6e, 0x71, 0x0b, 0x3c, 0x7b, 0xd6, 0x16, - 0xa9, 0xbf, 0xa1, 0x7d, 0x28, 0x04, 0xa4, 0x7a, 0xee, 0x23, 0x64, 0x6d, 0x7e, 0x21, 0x0c, 0x3d, - 0x86, 0x52, 0x94, 0x4c, 0x2e, 0xf6, 0xb4, 0x58, 0x5b, 0xb0, 0xc2, 0xc5, 0xfc, 0x47, 0x99, 0xe5, - 0x62, 0x4f, 0x8d, 0xb5, 0x05, 0x0b, 0x5e, 0xe8, 0x33, 0x58, 0x99, 0x66, 0x7e, 0x8b, 0xbf, 0x3c, - 0xd6, 0xce, 0x51, 0x02, 0x43, 0x43, 0x40, 0x33, 0x18, 0xe3, 0x39, 0x1e, 0x22, 0x6b, 0xe7, 0xa9, - 0x88, 0xd5, 0x9b, 0x5f, 0xbd, 0x58, 0x4b, 0x7e, 0xfd, 0x62, 0x2d, 0xf9, 0x8f, 0x17, 0x6b, 0xc9, - 0xe7, 0x2f, 0xd7, 0x12, 0x5f, 0xbf, 0x5c, 0x4b, 0xfc, 0xf5, 0xe5, 0x5a, 0xe2, 0x67, 0x6f, 0xf5, - 0x4c, 0xda, 0x1f, 0x75, 0x36, 0xba, 0xf6, 0x70, 0x33, 0xfc, 0x0f, 0x87, 0x59, 0xff, 0xba, 0xe8, - 0xe4, 0xf8, 0xa1, 0x72, 0xeb, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x92, 0xa5, 0x39, 0xcc, 0x95, - 0x21, 0x00, 0x00, + // 2644 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0x4b, 0x73, 0x1b, 0xc7, + 0xf1, 0xc7, 0x1b, 0xd8, 0xc6, 0x83, 0xe0, 0x88, 0x96, 0x61, 0x58, 0x26, 0xe5, 0x55, 0xd9, 0x7f, + 0x4b, 0xb6, 0xc9, 0xbf, 0xa9, 0x92, 0x22, 0x97, 0xf3, 0x30, 0x01, 0x41, 0x01, 0x2d, 0x86, 0x64, + 0x86, 0x90, 0x5c, 0x4e, 0x62, 0xad, 0x17, 0xd8, 0x21, 0xb0, 0x16, 0xb0, 0xbb, 0xde, 0x1d, 0x50, + 0xa4, 0x8f, 0xa9, 0xe4, 0xe2, 0xca, 0x41, 0xc7, 0x5c, 0x5c, 0x95, 0x6f, 0xe0, 0x6b, 0x4e, 0x39, + 0xe5, 0xe0, 0x43, 0x52, 0xe5, 0x63, 0x0e, 0x29, 0x27, 0x25, 0xdd, 0xf2, 0x05, 0x72, 0x4a, 0x55, + 0x6a, 0x1e, 0xbb, 0xd8, 0x05, 0xb0, 0x04, 0x18, 0xe7, 0x96, 0xdb, 0x4c, 0x6f, 0x77, 0x63, 0xa6, + 0x67, 0xfa, 0x37, 0xbf, 0xe9, 0x01, 0xbc, 0x4c, 0x89, 0x65, 0x10, 0x77, 0x64, 0x5a, 0x74, 0x4b, + 0xef, 0xf6, 0xcc, 0x2d, 0x7a, 0xe6, 0x10, 0x6f, 0xd3, 0x71, 0x6d, 0x6a, 0xa3, 0x95, 0xc9, 0xc7, + 0x4d, 0xf6, 0xb1, 0xfe, 0x4a, 0x48, 0xbb, 0xe7, 0x9e, 0x39, 0xd4, 0xde, 0x72, 0x5c, 0xdb, 0x3e, + 0x16, 0xfa, 0xf5, 0x2b, 0xa1, 0xcf, 0xdc, 0x4f, 0xd8, 0x5b, 0xe4, 0xab, 0x34, 0x7e, 0x4c, 0xce, + 0xfc, 0xaf, 0xaf, 0xcc, 0xd8, 0x3a, 0xba, 0xab, 0x8f, 0xfc, 0xcf, 0x1b, 0x7d, 0xdb, 0xee, 0x0f, + 0xc9, 0x16, 0xef, 0x75, 0xc7, 0xc7, 0x5b, 0xd4, 0x1c, 0x11, 0x8f, 0xea, 0x23, 0x47, 0x2a, 0xac, + 0xf5, 0xed, 0xbe, 0xcd, 0x9b, 0x5b, 0xac, 0x25, 0xa4, 0xea, 0x9f, 0xf3, 0x90, 0xc7, 0xe4, 0xb3, + 0x31, 0xf1, 0x28, 0xda, 0x86, 0x0c, 0xe9, 0x0d, 0xec, 0x5a, 0xf2, 0x6a, 0xf2, 0x8d, 0xe2, 0xf6, + 0x95, 0xcd, 0xa9, 0xc9, 0x6d, 0x4a, 0xbd, 0x56, 0x6f, 0x60, 0xb7, 0x13, 0x98, 0xeb, 0xa2, 0x5b, + 0x90, 0x3d, 0x1e, 0x8e, 0xbd, 0x41, 0x2d, 0xc5, 0x8d, 0x5e, 0x89, 0x33, 0xba, 0xc7, 0x94, 0xda, + 0x09, 0x2c, 0xb4, 0xd9, 0x4f, 0x99, 0xd6, 0xb1, 0x5d, 0x4b, 0x9f, 0xff, 0x53, 0xbb, 0xd6, 0x31, + 0xff, 0x29, 0xa6, 0x8b, 0x1a, 0x00, 0xa6, 0x65, 0x52, 0xad, 0x37, 0xd0, 0x4d, 0xab, 0x96, 0xe1, + 0x96, 0xaf, 0xc6, 0x5b, 0x9a, 0xb4, 0xc9, 0x14, 0xdb, 0x09, 0xac, 0x98, 0x7e, 0x87, 0x0d, 0xf7, + 0xb3, 0x31, 0x71, 0xcf, 0x6a, 0xd9, 0xf3, 0x87, 0xfb, 0x53, 0xa6, 0xc4, 0x86, 0xcb, 0xb5, 0x51, + 0x0b, 0x8a, 0x5d, 0xd2, 0x37, 0x2d, 0xad, 0x3b, 0xb4, 0x7b, 0x8f, 0x6b, 0x39, 0x6e, 0xac, 0xc6, + 0x19, 0x37, 0x98, 0x6a, 0x83, 0x69, 0xb6, 0x13, 0x18, 0xba, 0x41, 0x0f, 0x7d, 0x1f, 0x0a, 0xbd, + 0x01, 0xe9, 0x3d, 0xd6, 0xe8, 0x69, 0x2d, 0xcf, 0x7d, 0x6c, 0xc4, 0xf9, 0x68, 0x32, 0xbd, 0xce, + 0x69, 0x3b, 0x81, 0xf3, 0x3d, 0xd1, 0x64, 0xf3, 0x37, 0xc8, 0xd0, 0x3c, 0x21, 0x2e, 0xb3, 0x2f, + 0x9c, 0x3f, 0xff, 0xbb, 0x42, 0x93, 0x7b, 0x50, 0x0c, 0xbf, 0x83, 0x7e, 0x04, 0x0a, 0xb1, 0x0c, + 0x39, 0x0d, 0x85, 0xbb, 0xb8, 0x1a, 0xbb, 0xce, 0x96, 0xe1, 0x4f, 0xa2, 0x40, 0x64, 0x1b, 0xdd, + 0x81, 0x5c, 0xcf, 0x1e, 0x8d, 0x4c, 0x5a, 0x03, 0x6e, 0xbd, 0x1e, 0x3b, 0x01, 0xae, 0xd5, 0x4e, + 0x60, 0xa9, 0x8f, 0xf6, 0xa1, 0x32, 0x34, 0x3d, 0xaa, 0x79, 0x96, 0xee, 0x78, 0x03, 0x9b, 0x7a, + 0xb5, 0x22, 0xf7, 0xf0, 0x5a, 0x9c, 0x87, 0x3d, 0xd3, 0xa3, 0x47, 0xbe, 0x72, 0x3b, 0x81, 0xcb, + 0xc3, 0xb0, 0x80, 0xf9, 0xb3, 0x8f, 0x8f, 0x89, 0x1b, 0x38, 0xac, 0x95, 0xce, 0xf7, 0x77, 0xc0, + 0xb4, 0x7d, 0x7b, 0xe6, 0xcf, 0x0e, 0x0b, 0xd0, 0xcf, 0xe1, 0xd2, 0xd0, 0xd6, 0x8d, 0xc0, 0x9d, + 0xd6, 0x1b, 0x8c, 0xad, 0xc7, 0xb5, 0x32, 0x77, 0x7a, 0x3d, 0x76, 0x90, 0xb6, 0x6e, 0xf8, 0x2e, + 0x9a, 0xcc, 0xa0, 0x9d, 0xc0, 0xab, 0xc3, 0x69, 0x21, 0x7a, 0x04, 0x6b, 0xba, 0xe3, 0x0c, 0xcf, + 0xa6, 0xbd, 0x57, 0xb8, 0xf7, 0x1b, 0x71, 0xde, 0x77, 0x98, 0xcd, 0xb4, 0x7b, 0xa4, 0xcf, 0x48, + 0x1b, 0x79, 0xc8, 0x9e, 0xe8, 0xc3, 0x31, 0x51, 0xff, 0x0f, 0x8a, 0xa1, 0x34, 0x45, 0x35, 0xc8, + 0x8f, 0x88, 0xe7, 0xe9, 0x7d, 0xc2, 0xb3, 0x5a, 0xc1, 0x7e, 0x57, 0xad, 0x40, 0x29, 0x9c, 0x9a, + 0xea, 0xd3, 0x64, 0x60, 0xc9, 0xb2, 0x8e, 0x59, 0x9e, 0x10, 0xd7, 0x33, 0x6d, 0xcb, 0xb7, 0x94, + 0x5d, 0x74, 0x0d, 0xca, 0x7c, 0xff, 0x68, 0xfe, 0x77, 0x96, 0xfa, 0x19, 0x5c, 0xe2, 0xc2, 0x87, + 0x52, 0x69, 0x03, 0x8a, 0xce, 0xb6, 0x13, 0xa8, 0xa4, 0xb9, 0x0a, 0x38, 0xdb, 0x8e, 0xaf, 0xf0, + 0x2a, 0x94, 0xd8, 0x4c, 0x03, 0x8d, 0x0c, 0xff, 0x91, 0x22, 0x93, 0x49, 0x15, 0xf5, 0x4f, 0x29, + 0xa8, 0x4e, 0xa7, 0x33, 0xba, 0x03, 0x19, 0x86, 0x6c, 0x12, 0xa4, 0xea, 0x9b, 0x02, 0xf6, 0x36, + 0x7d, 0xd8, 0xdb, 0xec, 0xf8, 0xb0, 0xd7, 0x28, 0x7c, 0xfd, 0xed, 0x46, 0xe2, 0xe9, 0xdf, 0x36, + 0x92, 0x98, 0x5b, 0xa0, 0x97, 0x58, 0xf6, 0xe9, 0xa6, 0xa5, 0x99, 0x06, 0x1f, 0xb2, 0xc2, 0x52, + 0x4b, 0x37, 0xad, 0x5d, 0x03, 0xed, 0x41, 0xb5, 0x67, 0x5b, 0x1e, 0xb1, 0xbc, 0xb1, 0xa7, 0x09, + 0x58, 0x95, 0xd0, 0x14, 0x49, 0x30, 0x01, 0xd6, 0x4d, 0x5f, 0xf3, 0x90, 0x2b, 0xe2, 0x95, 0x5e, + 0x54, 0x80, 0xee, 0x01, 0x9c, 0xe8, 0x43, 0xd3, 0xd0, 0xa9, 0xed, 0x7a, 0xb5, 0xcc, 0xd5, 0xf4, + 0xdc, 0x2c, 0x7b, 0xe8, 0xab, 0x3c, 0x70, 0x0c, 0x9d, 0x92, 0x46, 0x86, 0x0d, 0x17, 0x87, 0x2c, + 0xd1, 0xeb, 0xb0, 0xa2, 0x3b, 0x8e, 0xe6, 0x51, 0x9d, 0x12, 0xad, 0x7b, 0x46, 0x89, 0xc7, 0x61, + 0xab, 0x84, 0xcb, 0xba, 0xe3, 0x1c, 0x31, 0x69, 0x83, 0x09, 0xd1, 0x6b, 0x50, 0x61, 0x08, 0x67, + 0xea, 0x43, 0x6d, 0x40, 0xcc, 0xfe, 0x80, 0x72, 0x80, 0x4a, 0xe3, 0xb2, 0x94, 0xb6, 0xb9, 0x50, + 0x35, 0x82, 0x15, 0xe7, 0xe8, 0x86, 0x10, 0x64, 0x0c, 0x9d, 0xea, 0x3c, 0x92, 0x25, 0xcc, 0xdb, + 0x4c, 0xe6, 0xe8, 0x74, 0x20, 0xe3, 0xc3, 0xdb, 0xe8, 0x32, 0xe4, 0xa4, 0xdb, 0x34, 0x77, 0x2b, + 0x7b, 0x68, 0x0d, 0xb2, 0x8e, 0x6b, 0x9f, 0x10, 0xbe, 0x74, 0x05, 0x2c, 0x3a, 0xea, 0xaf, 0x52, + 0xb0, 0x3a, 0x83, 0x83, 0xcc, 0xef, 0x40, 0xf7, 0x06, 0xfe, 0x6f, 0xb1, 0x36, 0xba, 0xcd, 0xfc, + 0xea, 0x06, 0x71, 0xe5, 0xd9, 0x51, 0x9b, 0x0d, 0x75, 0x9b, 0x7f, 0x97, 0xa1, 0x91, 0xda, 0xe8, + 0x00, 0xaa, 0x43, 0xdd, 0xa3, 0x9a, 0xc0, 0x15, 0x2d, 0x74, 0x8e, 0xcc, 0xa2, 0xe9, 0x9e, 0xee, + 0x23, 0x11, 0xdb, 0xd4, 0xd2, 0x51, 0x65, 0x18, 0x91, 0x22, 0x0c, 0x6b, 0xdd, 0xb3, 0xcf, 0x75, + 0x8b, 0x9a, 0x16, 0xd1, 0x66, 0x56, 0xee, 0xa5, 0x19, 0xa7, 0xad, 0x13, 0xd3, 0x20, 0x56, 0xcf, + 0x5f, 0xb2, 0x4b, 0x81, 0x71, 0xb0, 0xa4, 0x9e, 0x8a, 0xa1, 0x12, 0x45, 0x72, 0x54, 0x81, 0x14, + 0x3d, 0x95, 0x01, 0x48, 0xd1, 0x53, 0xf4, 0xff, 0x90, 0x61, 0x93, 0xe4, 0x93, 0xaf, 0xcc, 0x39, + 0x02, 0xa5, 0x5d, 0xe7, 0xcc, 0x21, 0x98, 0x6b, 0xaa, 0x6a, 0x90, 0x0e, 0x01, 0xba, 0x4f, 0x7b, + 0x55, 0xaf, 0xc3, 0xca, 0x14, 0x7c, 0x87, 0xd6, 0x2f, 0x19, 0x5e, 0x3f, 0x75, 0x05, 0xca, 0x11, + 0xac, 0x56, 0x2f, 0xc3, 0xda, 0x3c, 0xe8, 0x55, 0x07, 0x81, 0x3c, 0x02, 0xa1, 0xe8, 0x16, 0x14, + 0x02, 0xec, 0x15, 0xe9, 0x38, 0x1b, 0x2b, 0x5f, 0x19, 0x07, 0xaa, 0x2c, 0x0f, 0xd9, 0xb6, 0xe6, + 0xfb, 0x21, 0xc5, 0x07, 0x9e, 0xd7, 0x1d, 0xa7, 0xad, 0x7b, 0x03, 0xf5, 0x13, 0xa8, 0xc5, 0xe1, + 0xea, 0xd4, 0x34, 0x32, 0xc1, 0x36, 0xbc, 0x0c, 0xb9, 0x63, 0xdb, 0x1d, 0xe9, 0x94, 0x3b, 0x2b, + 0x63, 0xd9, 0x63, 0xdb, 0x53, 0x60, 0x6c, 0x9a, 0x8b, 0x45, 0x47, 0xd5, 0xe0, 0xa5, 0x58, 0x6c, + 0x65, 0x26, 0xa6, 0x65, 0x10, 0x11, 0xcf, 0x32, 0x16, 0x9d, 0x89, 0x23, 0x31, 0x58, 0xd1, 0x61, + 0x3f, 0xeb, 0xf1, 0xb9, 0x72, 0xff, 0x0a, 0x96, 0x3d, 0xf5, 0x77, 0x05, 0x28, 0x60, 0xe2, 0x39, + 0x0c, 0x13, 0x50, 0x03, 0x14, 0x72, 0xda, 0x23, 0x0e, 0xf5, 0x61, 0x74, 0x3e, 0x6b, 0x10, 0xda, + 0x2d, 0x5f, 0x93, 0x1d, 0xd9, 0x81, 0x19, 0xba, 0x29, 0x59, 0x59, 0x3c, 0xc1, 0x92, 0xe6, 0x61, + 0x5a, 0x76, 0xdb, 0xa7, 0x65, 0xe9, 0xd8, 0x53, 0x5a, 0x58, 0x4d, 0xf1, 0xb2, 0x9b, 0x92, 0x97, + 0x65, 0x16, 0xfc, 0x58, 0x84, 0x98, 0x35, 0x23, 0xc4, 0x2c, 0xbb, 0x60, 0x9a, 0x31, 0xcc, 0xec, + 0xb6, 0xcf, 0xcc, 0x72, 0x0b, 0x46, 0x3c, 0x45, 0xcd, 0xee, 0x45, 0xa9, 0x99, 0xa0, 0x55, 0xd7, + 0x62, 0xad, 0x63, 0xb9, 0xd9, 0x0f, 0x42, 0xdc, 0xac, 0x10, 0x4b, 0x8c, 0x84, 0x93, 0x39, 0xe4, + 0xac, 0x19, 0x21, 0x67, 0xca, 0x82, 0x18, 0xc4, 0xb0, 0xb3, 0xf7, 0xc3, 0xec, 0x0c, 0x62, 0x09, + 0x9e, 0x5c, 0xef, 0x79, 0xf4, 0xec, 0xdd, 0x80, 0x9e, 0x15, 0x63, 0xf9, 0xa5, 0x9c, 0xc3, 0x34, + 0x3f, 0x3b, 0x98, 0xe1, 0x67, 0x82, 0x4f, 0xbd, 0x1e, 0xeb, 0x62, 0x01, 0x41, 0x3b, 0x98, 0x21, + 0x68, 0xe5, 0x05, 0x0e, 0x17, 0x30, 0xb4, 0x5f, 0xcc, 0x67, 0x68, 0xf1, 0x1c, 0x4a, 0x0e, 0x73, + 0x39, 0x8a, 0xa6, 0xc5, 0x50, 0xb4, 0x15, 0xee, 0xfe, 0xcd, 0x58, 0xf7, 0x17, 0xe7, 0x68, 0xd7, + 0xd9, 0x09, 0x39, 0x95, 0xf3, 0x0c, 0x65, 0x88, 0xeb, 0xda, 0xae, 0x64, 0x5b, 0xa2, 0xa3, 0xbe, + 0xc1, 0xce, 0xec, 0x49, 0x7e, 0x9f, 0xc3, 0xe7, 0x38, 0x9a, 0x87, 0x72, 0x5a, 0xfd, 0x7d, 0x72, + 0x62, 0xcb, 0x8f, 0xb9, 0xf0, 0x79, 0xaf, 0xc8, 0xf3, 0x3e, 0xc4, 0xf2, 0x52, 0x51, 0x96, 0xb7, + 0x01, 0x45, 0x86, 0xd2, 0x53, 0x04, 0x4e, 0x77, 0x02, 0x02, 0x77, 0x03, 0x56, 0xf9, 0x31, 0x2c, + 0xb8, 0xa0, 0x84, 0xe6, 0x0c, 0x3f, 0x61, 0x56, 0xd8, 0x07, 0xb1, 0x39, 0x05, 0x46, 0xbf, 0x0d, + 0x97, 0x42, 0xba, 0x01, 0xfa, 0x0b, 0x36, 0x53, 0x0d, 0xb4, 0x77, 0xe4, 0x31, 0xf0, 0xc7, 0xe4, + 0x24, 0x42, 0x13, 0xe6, 0x37, 0x8f, 0xa4, 0x25, 0xff, 0x4b, 0x24, 0x2d, 0xf5, 0x1f, 0x93, 0xb4, + 0xf0, 0x69, 0x96, 0x8e, 0x9e, 0x66, 0xff, 0x4c, 0x4e, 0xd6, 0x24, 0xa0, 0x5c, 0x3d, 0xdb, 0x20, + 0xf2, 0x7c, 0xe1, 0x6d, 0x54, 0x85, 0xf4, 0xd0, 0xee, 0xcb, 0x53, 0x84, 0x35, 0x99, 0x56, 0x00, + 0xc2, 0x8a, 0xc4, 0xd8, 0xe0, 0x68, 0xca, 0xf2, 0x08, 0xcb, 0xa3, 0xa9, 0x0a, 0xe9, 0xc7, 0x44, + 0x40, 0x66, 0x09, 0xb3, 0x26, 0xd3, 0xe3, 0x9b, 0x8c, 0x03, 0x61, 0x09, 0x8b, 0x0e, 0xba, 0x03, + 0x0a, 0x2f, 0x43, 0x68, 0xb6, 0xe3, 0x49, 0x74, 0x7b, 0x39, 0x3c, 0x57, 0x51, 0x6d, 0xd8, 0x3c, + 0x64, 0x3a, 0x07, 0x8e, 0x87, 0x0b, 0x8e, 0x6c, 0x85, 0x4e, 0x5d, 0x25, 0x42, 0xfe, 0xae, 0x80, + 0xc2, 0x46, 0xef, 0x39, 0x7a, 0x8f, 0x70, 0xa8, 0x52, 0xf0, 0x44, 0xa0, 0x3e, 0x02, 0x34, 0x0b, + 0xb8, 0xa8, 0x0d, 0x39, 0x72, 0x42, 0x2c, 0xca, 0x96, 0x8d, 0x85, 0xfb, 0xf2, 0x1c, 0x66, 0x45, + 0x2c, 0xda, 0xa8, 0xb1, 0x20, 0xff, 0xe3, 0xdb, 0x8d, 0xaa, 0xd0, 0x7e, 0xcb, 0x1e, 0x99, 0x94, + 0x8c, 0x1c, 0x7a, 0x86, 0xa5, 0xbd, 0xfa, 0xd7, 0x14, 0xa3, 0x39, 0x11, 0x30, 0x9e, 0x1b, 0x5b, + 0x7f, 0xcb, 0xa7, 0x42, 0x14, 0x77, 0xb9, 0x78, 0xaf, 0x03, 0xf4, 0x75, 0x4f, 0x7b, 0xa2, 0x5b, + 0x94, 0x18, 0x32, 0xe8, 0x21, 0x09, 0xaa, 0x43, 0x81, 0xf5, 0xc6, 0x1e, 0x31, 0x24, 0xdb, 0x0e, + 0xfa, 0xa1, 0x79, 0xe6, 0xbf, 0xdb, 0x3c, 0xa3, 0x51, 0x2e, 0x4c, 0x45, 0x39, 0x44, 0x41, 0x94, + 0x30, 0x05, 0x61, 0x63, 0x73, 0x5c, 0xd3, 0x76, 0x4d, 0x7a, 0xc6, 0x97, 0x26, 0x8d, 0x83, 0x3e, + 0xbb, 0xbc, 0x8d, 0xc8, 0xc8, 0xb1, 0xed, 0xa1, 0x26, 0xe0, 0xa6, 0xc8, 0x4d, 0x4b, 0x52, 0xd8, + 0xe2, 0xa8, 0xf3, 0xeb, 0xd4, 0x24, 0xff, 0x26, 0x54, 0xf3, 0x7f, 0x2e, 0xc0, 0xea, 0x6f, 0xf8, + 0x05, 0x34, 0x7a, 0xdc, 0xa2, 0x23, 0x58, 0x0d, 0xd2, 0x5f, 0x1b, 0x73, 0x58, 0xf0, 0x37, 0xf4, + 0xb2, 0xf8, 0x51, 0x3d, 0x89, 0x8a, 0x3d, 0xf4, 0x11, 0xbc, 0x38, 0x85, 0x6d, 0x81, 0xeb, 0xd4, + 0xb2, 0x10, 0xf7, 0x42, 0x14, 0xe2, 0x7c, 0xd7, 0x93, 0x60, 0xa5, 0xbf, 0x63, 0xd6, 0xed, 0xb2, + 0x3b, 0x4d, 0x98, 0x3d, 0xcc, 0x5d, 0xfe, 0x6b, 0x50, 0x76, 0x09, 0x65, 0xf7, 0xec, 0xc8, 0xad, + 0xb1, 0x24, 0x84, 0xf2, 0x2e, 0x7a, 0x08, 0x2f, 0xcc, 0x65, 0x11, 0xe8, 0x7b, 0xa0, 0x4c, 0x08, + 0x48, 0x32, 0xe6, 0x02, 0x16, 0x5c, 0x2a, 0x26, 0xba, 0xea, 0x1f, 0x92, 0x13, 0x97, 0xd1, 0x6b, + 0x4a, 0x0b, 0x72, 0x2e, 0xf1, 0xc6, 0x43, 0x71, 0x71, 0xa8, 0x6c, 0xbf, 0xbd, 0x1c, 0xff, 0x60, + 0xd2, 0xf1, 0x90, 0x62, 0x69, 0xac, 0x3e, 0x82, 0x9c, 0x90, 0xa0, 0x22, 0xe4, 0x1f, 0xec, 0xdf, + 0xdf, 0x3f, 0xf8, 0x70, 0xbf, 0x9a, 0x40, 0x00, 0xb9, 0x9d, 0x66, 0xb3, 0x75, 0xd8, 0xa9, 0x26, + 0x91, 0x02, 0xd9, 0x9d, 0xc6, 0x01, 0xee, 0x54, 0x53, 0x4c, 0x8c, 0x5b, 0x1f, 0xb4, 0x9a, 0x9d, + 0x6a, 0x1a, 0xad, 0x42, 0x59, 0xb4, 0xb5, 0x7b, 0x07, 0xf8, 0x27, 0x3b, 0x9d, 0x6a, 0x26, 0x24, + 0x3a, 0x6a, 0xed, 0xdf, 0x6d, 0xe1, 0x6a, 0x56, 0x7d, 0x87, 0xdd, 0x4c, 0x62, 0x18, 0xcb, 0xe4, + 0x0e, 0x92, 0x0c, 0xdd, 0x41, 0xd4, 0xdf, 0xa6, 0xa0, 0x1e, 0x4f, 0x43, 0xd0, 0x07, 0x53, 0x13, + 0xdf, 0xbe, 0x00, 0x87, 0x99, 0x9a, 0x3d, 0x7a, 0x0d, 0x2a, 0x2e, 0x39, 0x26, 0xb4, 0x37, 0x10, + 0xb4, 0x48, 0x1c, 0x99, 0x65, 0x5c, 0x96, 0x52, 0x6e, 0xe4, 0x09, 0xb5, 0x4f, 0x49, 0x8f, 0x6a, + 0x02, 0x8b, 0xc4, 0xa6, 0x53, 0x98, 0x1a, 0x93, 0x1e, 0x09, 0xa1, 0xfa, 0xc9, 0x85, 0x62, 0xa9, + 0x40, 0x16, 0xb7, 0x3a, 0xf8, 0xa3, 0x6a, 0x1a, 0x21, 0xa8, 0xf0, 0xa6, 0x76, 0xb4, 0xbf, 0x73, + 0x78, 0xd4, 0x3e, 0x60, 0xb1, 0xbc, 0x04, 0x2b, 0x7e, 0x2c, 0x7d, 0x61, 0x56, 0xfd, 0x18, 0x2a, + 0xd1, 0xbb, 0x3f, 0x0b, 0xa1, 0x6b, 0x8f, 0x2d, 0x83, 0x07, 0x23, 0x8b, 0x45, 0x07, 0xdd, 0x82, + 0xec, 0x89, 0x2d, 0xd2, 0x6c, 0xfe, 0x5e, 0x7b, 0x68, 0x53, 0x12, 0xaa, 0x1d, 0x08, 0x6d, 0xf5, + 0x73, 0xc8, 0xf2, 0xac, 0x61, 0x19, 0xc0, 0x6f, 0xf1, 0x92, 0x54, 0xb1, 0x36, 0xfa, 0x18, 0x40, + 0xa7, 0xd4, 0x35, 0xbb, 0xe3, 0x89, 0xe3, 0x8d, 0xf9, 0x59, 0xb7, 0xe3, 0xeb, 0x35, 0xae, 0xc8, + 0xf4, 0x5b, 0x9b, 0x98, 0x86, 0x52, 0x30, 0xe4, 0x50, 0xdd, 0x87, 0x4a, 0xd4, 0xd6, 0xa7, 0x01, + 0x62, 0x0c, 0x51, 0x1a, 0x20, 0x58, 0x9d, 0xa4, 0x01, 0x01, 0x89, 0x48, 0x8b, 0x8a, 0x0d, 0xef, + 0xa8, 0x5f, 0x25, 0xa1, 0xd0, 0x39, 0x95, 0xeb, 0x11, 0x53, 0x2c, 0x98, 0x98, 0xa6, 0xc2, 0x57, + 0x63, 0x51, 0x7d, 0x48, 0x07, 0x35, 0x8d, 0xf7, 0x83, 0x1d, 0x97, 0x59, 0xf6, 0x06, 0xe4, 0x17, + 0x77, 0xe4, 0x3e, 0xbb, 0x06, 0x65, 0xdb, 0x35, 0xfb, 0xa6, 0xa5, 0x0f, 0xc3, 0x1c, 0xb1, 0xe4, + 0x0b, 0x39, 0xb1, 0x7a, 0x0f, 0x94, 0x00, 0x58, 0x19, 0x85, 0xd5, 0x0d, 0xc3, 0x25, 0x9e, 0x27, + 0x93, 0xc3, 0xef, 0xf2, 0x02, 0x95, 0xfd, 0x44, 0xde, 0xd0, 0xd3, 0x58, 0x74, 0x54, 0x03, 0x56, + 0xa6, 0x50, 0x19, 0xbd, 0x07, 0x79, 0x67, 0xdc, 0xd5, 0xfc, 0x18, 0x4e, 0x3d, 0x48, 0xf8, 0xe4, + 0x68, 0xdc, 0x1d, 0x9a, 0xbd, 0xfb, 0xe4, 0xcc, 0x1f, 0xb1, 0x33, 0xee, 0xde, 0x17, 0xa1, 0x16, + 0xbf, 0x92, 0x0a, 0xff, 0xca, 0x09, 0x14, 0xfc, 0x9d, 0x83, 0x7e, 0x08, 0x4a, 0x00, 0xf8, 0x41, + 0xdd, 0x32, 0xf6, 0xa4, 0x90, 0xee, 0x27, 0x26, 0x8c, 0x69, 0x7b, 0x66, 0xdf, 0x22, 0x86, 0x36, + 0x21, 0xd1, 0xfc, 0xd7, 0x0a, 0x78, 0x45, 0x7c, 0xd8, 0xf3, 0x19, 0xb4, 0xfa, 0xaf, 0x24, 0x14, + 0xfc, 0xfa, 0x14, 0x7a, 0x27, 0xb4, 0x39, 0x2b, 0x73, 0x6e, 0xf3, 0xbe, 0xe2, 0xa4, 0xc6, 0x14, + 0x1d, 0x6b, 0xea, 0xe2, 0x63, 0x8d, 0x2b, 0x16, 0xfa, 0x65, 0xdb, 0xcc, 0x85, 0xcb, 0xb6, 0x6f, + 0x01, 0xa2, 0x36, 0xd5, 0x87, 0xda, 0x89, 0x4d, 0x4d, 0xab, 0xaf, 0x89, 0x60, 0x0b, 0xc2, 0x50, + 0xe5, 0x5f, 0x1e, 0xf2, 0x0f, 0x87, 0x3c, 0xee, 0xbf, 0x4c, 0x42, 0x21, 0x40, 0xfe, 0x8b, 0x96, + 0x8c, 0x2e, 0x43, 0x4e, 0x82, 0x9b, 0xa8, 0x19, 0xc9, 0x5e, 0x50, 0xbd, 0xcc, 0x84, 0xaa, 0x97, + 0x75, 0x28, 0x8c, 0x08, 0xd5, 0xf9, 0xf1, 0x27, 0xf6, 0x68, 0xd0, 0xbf, 0xf1, 0x2e, 0x14, 0x43, + 0xd5, 0x3b, 0x96, 0x9e, 0xfb, 0xad, 0x0f, 0xab, 0x89, 0x7a, 0xfe, 0x8b, 0x2f, 0xaf, 0xa6, 0xf7, + 0xc9, 0x13, 0xb6, 0x67, 0x71, 0xab, 0xd9, 0x6e, 0x35, 0xef, 0x57, 0x93, 0xf5, 0xe2, 0x17, 0x5f, + 0x5e, 0xcd, 0x63, 0xc2, 0x2b, 0x09, 0x37, 0xda, 0x50, 0x0a, 0xaf, 0x4a, 0x14, 0x1f, 0x11, 0x54, + 0xee, 0x3e, 0x38, 0xdc, 0xdb, 0x6d, 0xee, 0x74, 0x5a, 0xda, 0xc3, 0x83, 0x4e, 0xab, 0x9a, 0x44, + 0x2f, 0xc2, 0xa5, 0xbd, 0xdd, 0x1f, 0xb7, 0x3b, 0x5a, 0x73, 0x6f, 0xb7, 0xb5, 0xdf, 0xd1, 0x76, + 0x3a, 0x9d, 0x9d, 0xe6, 0xfd, 0x6a, 0x6a, 0xfb, 0x2b, 0x05, 0x56, 0x76, 0x1a, 0xcd, 0x5d, 0x86, + 0xed, 0x66, 0x4f, 0xe7, 0x97, 0xcc, 0x26, 0x64, 0xf8, 0x35, 0xf2, 0xdc, 0xb7, 0xbd, 0xfa, 0xf9, + 0x35, 0x26, 0x74, 0x0f, 0xb2, 0xfc, 0x86, 0x89, 0xce, 0x7f, 0xec, 0xab, 0x2f, 0x28, 0x3a, 0xb1, + 0xc1, 0xf0, 0xf4, 0x38, 0xf7, 0xf5, 0xaf, 0x7e, 0x7e, 0x0d, 0x0a, 0x61, 0x50, 0x26, 0x0c, 0x75, + 0xf1, 0x6b, 0x58, 0x7d, 0x09, 0x44, 0x42, 0x7b, 0x90, 0xf7, 0x2f, 0x15, 0x8b, 0xde, 0xe7, 0xea, + 0x0b, 0x8b, 0x44, 0x2c, 0x5c, 0xe2, 0xf2, 0x77, 0xfe, 0x63, 0x63, 0x7d, 0x41, 0xc5, 0x0b, 0xed, + 0x42, 0x4e, 0xb2, 0xae, 0x05, 0x6f, 0x6e, 0xf5, 0x45, 0x45, 0x1f, 0x16, 0xb4, 0xc9, 0xb5, 0x7a, + 0xf1, 0x13, 0x6a, 0x7d, 0x89, 0x62, 0x1e, 0x7a, 0x00, 0x10, 0xba, 0xea, 0x2d, 0xf1, 0x36, 0x5a, + 0x5f, 0xa6, 0x48, 0x87, 0x0e, 0xa0, 0x10, 0x30, 0xef, 0x85, 0x2f, 0x95, 0xf5, 0xc5, 0xd5, 0x32, + 0xf4, 0x08, 0xca, 0x51, 0xc6, 0xb9, 0xdc, 0xfb, 0x63, 0x7d, 0xc9, 0x32, 0x18, 0xf3, 0x1f, 0xa5, + 0x9f, 0xcb, 0xbd, 0x47, 0xd6, 0x97, 0xac, 0x8a, 0xa1, 0x4f, 0x61, 0x75, 0x96, 0x1e, 0x2e, 0xff, + 0x3c, 0x59, 0xbf, 0x40, 0x9d, 0x0c, 0x8d, 0x00, 0xcd, 0xa1, 0x95, 0x17, 0x78, 0xad, 0xac, 0x5f, + 0xa4, 0x6c, 0xd6, 0x68, 0x7d, 0xfd, 0x6c, 0x3d, 0xf9, 0xcd, 0xb3, 0xf5, 0xe4, 0xdf, 0x9f, 0xad, + 0x27, 0x9f, 0x3e, 0x5f, 0x4f, 0x7c, 0xf3, 0x7c, 0x3d, 0xf1, 0x97, 0xe7, 0xeb, 0x89, 0x9f, 0xbd, + 0xd9, 0x37, 0xe9, 0x60, 0xdc, 0xdd, 0xec, 0xd9, 0xa3, 0xad, 0xf0, 0xdf, 0x20, 0xe6, 0xfd, 0x35, + 0xa3, 0x9b, 0xe3, 0x87, 0xca, 0xcd, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0xbd, 0x86, 0x4c, 0x97, + 0xba, 0x21, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -5801,6 +5810,13 @@ func (m *TxResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.OriginalHash) > 0 { + i -= len(m.OriginalHash) + copy(dAtA[i:], m.OriginalHash) + i = encodeVarintTypes(dAtA, i, uint64(len(m.OriginalHash))) + i-- + dAtA[i] = 0x2a + } { size, err := m.Result.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -7089,6 +7105,10 @@ func (m *TxResult) Size() (n int) { } l = m.Result.Size() n += 1 + l + sovTypes(uint64(l)) + l = len(m.OriginalHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } return n } @@ -12612,6 +12632,40 @@ func (m *TxResult) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OriginalHash", 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.OriginalHash = append(m.OriginalHash[:0], dAtA[iNdEx:postIndex]...) + if m.OriginalHash == nil { + m.OriginalHash = []byte{} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) diff --git a/internal/mempool/v0/clist_mempool.go b/internal/mempool/v0/clist_mempool.go index eb82817a74..f25f5718ca 100644 --- a/internal/mempool/v0/clist_mempool.go +++ b/internal/mempool/v0/clist_mempool.go @@ -7,6 +7,8 @@ import ( "sync" "sync/atomic" + "crypto/sha256" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/internal/libs/clist" @@ -628,10 +630,13 @@ func (mem *CListMempool) Update( mem.removeTx(tx, e.(*clist.CElement), false) // see if the transaction is a child transaction of a some parent // transaction that exists in the mempool - } else if parentHash, _, isChild := types.DecodeChildTx(tx); isChild { - var parentKey [TxKeySize]byte - copy(parentKey[:], parentHash) - mem.RemoveTxByKey(parentKey, false) + } else if originalHash, _, isMalleated := types.UnwrapMalleatedTx(tx); isMalleated { + var origianlKey [sha256.Size]byte + copy(origianlKey[:], originalHash) + err := mem.RemoveTxByKey(origianlKey) + if err != nil { + return err + } } } diff --git a/internal/mempool/v0/clist_mempool_test.go b/internal/mempool/v0/clist_mempool_test.go index bc8c584cd7..b0b5a0ef11 100644 --- a/internal/mempool/v0/clist_mempool_test.go +++ b/internal/mempool/v0/clist_mempool_test.go @@ -3,6 +3,7 @@ package v0 import ( "context" "crypto/rand" + "crypto/sha256" "encoding/binary" "fmt" mrand "math/rand" @@ -226,24 +227,24 @@ func TestMempoolUpdate(t *testing.T) { // 4. Removes a parent transaction after receiving a child transaction in the update { - mempool.Flush() - parentTx := []byte{1, 2, 3, 4} - childTx := []byte{1, 2} - parentHash := sha256.Sum256(parentTx) + mp.Flush() + originalTx := []byte{1, 2, 3, 4} + malleatedTx := []byte{1, 2} + originalHash := sha256.Sum256(originalTx) // create the wrapped child transaction - wTx, err := types.WrapChildTx(parentHash[:], childTx) + wTx, err := types.WrapMalleatedTx(originalHash[:], malleatedTx) require.NoError(t, err) // add the parent transaction to the mempool - err = mempool.CheckTx(parentTx, nil, TxInfo{}) + err = mp.CheckTx(context.Background(), originalTx, nil, mempool.TxInfo{}) require.NoError(t, err) // remove the parent from the mempool using the wrapped child tx - err = mempool.Update(1, []types.Tx{wTx}, abciResponses(1, abci.CodeTypeOK), nil, nil) + err = mp.Update(1, []types.Tx{wTx}, abciResponses(1, abci.CodeTypeOK), nil, nil) require.NoError(t, err) - assert.Zero(t, mempool.Size()) + assert.Zero(t, mp.Size()) } } diff --git a/internal/state/execution.go b/internal/state/execution.go index 69851c19bc..2108c9b94e 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -544,11 +544,22 @@ func fireEvents( } for i, tx := range block.Data.Txs { + var txHash []byte + var rawTx []byte + if originalHash, malleatedTx, ismalleated := types.UnwrapMalleatedTx(tx); ismalleated { + txHash = originalHash + rawTx = malleatedTx + } else { + txHash = tx.Hash() + rawTx = tx + } + if err := eventBus.PublishEventTx(types.EventDataTx{TxResult: abci.TxResult{ - Height: block.Height, - Index: uint32(i), - Tx: tx, - Result: *(abciResponses.DeliverTxs[i]), + Height: block.Height, + Index: uint32(i), + Tx: rawTx, + Result: *(abciResponses.DeliverTxs[i]), + OriginalHash: txHash, }}); err != nil { logger.Error("failed publishing event TX", "err", err) } diff --git a/internal/state/indexer/tx/kv/kv.go b/internal/state/indexer/tx/kv/kv.go index 4bcff958b0..0cb916c142 100644 --- a/internal/state/indexer/tx/kv/kv.go +++ b/internal/state/indexer/tx/kv/kv.go @@ -12,6 +12,7 @@ import ( dbm "github.com/tendermint/tm-db" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/tmhash" indexer "github.com/tendermint/tendermint/internal/state/indexer" "github.com/tendermint/tendermint/libs/pubsub/query" "github.com/tendermint/tendermint/libs/pubsub/query/syntax" @@ -68,7 +69,12 @@ func (txi *TxIndex) Index(results []*abci.TxResult) error { defer b.Close() for _, result := range results { - hash := types.Tx(result.Tx).Hash() + var hash []byte + if len(result.OriginalHash) == tmhash.Size { + hash = result.OriginalHash + } else { + hash = types.Tx(result.Tx).Hash() + } // index tx by events err := txi.indexEvents(result, hash, b) diff --git a/internal/state/indexer/tx/kv/kv_test.go b/internal/state/indexer/tx/kv/kv_test.go index 9bb8bfb7bb..59c93e7304 100644 --- a/internal/state/indexer/tx/kv/kv_test.go +++ b/internal/state/indexer/tx/kv/kv_test.go @@ -65,6 +65,49 @@ func TestTxIndex(t *testing.T) { assert.True(t, proto.Equal(txResult2, loadedTxResult2)) } +func TestMalleatedTxIndex(t *testing.T) { + type test struct { + tx types.Tx + originalHash []byte + expectedTx []byte + } + originalTx1 := types.Tx([]byte("ORIGINAL_TX")) + malleatedTx1 := types.Tx([]byte("MALLEATED_TX")) + + tests := []test{ + // we expect to get the malleated tx returned when searching using the original hash + { + tx: malleatedTx1, + originalHash: originalTx1.Hash(), + expectedTx: malleatedTx1, + }, + } + + indexer := NewTxIndex(dbm.NewMemDB()) + + for i, tt := range tests { + + txResult := &abci.TxResult{ + Height: int64(i), + Index: 0, + Tx: tt.tx, + Result: abci.ResponseDeliverTx{ + Data: []byte{0}, + Code: abci.CodeTypeOK, Log: "", Events: nil, + }, + OriginalHash: tt.originalHash, + } + + err := indexer.Index([]*abci.TxResult{txResult}) + require.NoError(t, err) + + loadedTxResult, err := indexer.Get(tt.originalHash) + require.NoError(t, err) + require.NotNil(t, loadedTxResult) + assert.Equal(t, tt.expectedTx, loadedTxResult.Tx) + } +} + func TestTxSearch(t *testing.T) { indexer := NewTxIndex(dbm.NewMemDB()) diff --git a/node/node_test.go b/node/node_test.go index cb1edc1b3a..735a094344 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -406,7 +406,7 @@ func TestMaxProposalBlockSize(t *testing.T) { // fill the mempool with one txs just below the maximum size txLength := int(types.MaxDataBytesNoEvidence(maxBytes, types.MaxVotesCount)) - tx := tmrand.Bytes(txLength - 6 - 4) // to account for the varint + tx := tmrand.Bytes(txLength - 9) // to account for the varint err = mp.CheckTx(context.Background(), tx, nil, mempool.TxInfo{}) assert.NoError(t, err) // now produce more txs than what a normal block can hold with 10 smaller txs @@ -483,7 +483,7 @@ func TestMaxProposalBlockSize(t *testing.T) { require.Equal(t, int64(pb.Header.Size()), types.MaxHeaderBytes) require.Equal(t, int64(pb.LastCommit.Size()), types.MaxCommitBytes(types.MaxVotesCount)) // make sure that the block is less than the max possible size - assert.Equal(t, int64(pb.Size()), maxBytes) + assert.LessOrEqual(t, int64(pb.Size()), maxBytes) // because of the proto overhead we expect the part set bytes to be equal or // less than the pb block size assert.LessOrEqual(t, partSet.ByteSize(), int64(pb.Size())) diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 7126488d0a..8d1392bd40 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -289,10 +289,11 @@ message EventAttribute { // // One usage is indexing transaction results. message TxResult { - int64 height = 1; - uint32 index = 2; - bytes tx = 3; - ResponseDeliverTx result = 4 [(gogoproto.nullable) = false]; + int64 height = 1; + uint32 index = 2; + bytes tx = 3; + ResponseDeliverTx result = 4 [(gogoproto.nullable) = false]; + bytes original_hash = 5; } //---------------------------------------- diff --git a/proto/tendermint/types/block.proto b/proto/tendermint/types/block.proto index bf4b35664f..d395501f5f 100644 --- a/proto/tendermint/types/block.proto +++ b/proto/tendermint/types/block.proto @@ -7,7 +7,7 @@ import "gogoproto/gogo.proto"; import "tendermint/types/types.proto"; message Block { - Header header = 1 [(gogoproto.nullable) = false]; - Data data = 2 [(gogoproto.nullable) = false]; - Commit last_commit = 4; + Header header = 1 [(gogoproto.nullable) = false]; + Data data = 2 [(gogoproto.nullable) = false]; + Commit last_commit = 4; } diff --git a/proto/tendermint/types/types.pb.go b/proto/tendermint/types/types.pb.go index f31dd6aef8..1613a0a5e2 100644 --- a/proto/tendermint/types/types.pb.go +++ b/proto/tendermint/types/types.pb.go @@ -1441,25 +1441,26 @@ func (m *TxProof) GetProof() *crypto.Proof { return nil } -// ChildTx wraps a transaction that was derived from a parent transaction. This -// allows for removal of the parent transaction from the mempool. -type ChildTx struct { - ParentTxHash []byte `protobuf:"bytes,1,opt,name=parent_tx_hash,json=parentTxHash,proto3" json:"parent_tx_hash,omitempty"` - Tx []byte `protobuf:"bytes,2,opt,name=tx,proto3" json:"tx,omitempty"` -} - -func (m *ChildTx) Reset() { *m = ChildTx{} } -func (m *ChildTx) String() string { return proto.CompactTextString(m) } -func (*ChildTx) ProtoMessage() {} -func (*ChildTx) Descriptor() ([]byte, []int) { +// MalleatedTx wraps a transaction that was derived from a different original +// transaction. This allows for tendermint to track malleated and original +// transactions +type MalleatedTx struct { + OriginalTxHash []byte `protobuf:"bytes,1,opt,name=original_tx_hash,json=originalTxHash,proto3" json:"original_tx_hash,omitempty"` + Tx []byte `protobuf:"bytes,2,opt,name=tx,proto3" json:"tx,omitempty"` +} + +func (m *MalleatedTx) Reset() { *m = MalleatedTx{} } +func (m *MalleatedTx) String() string { return proto.CompactTextString(m) } +func (*MalleatedTx) ProtoMessage() {} +func (*MalleatedTx) Descriptor() ([]byte, []int) { return fileDescriptor_d3a6e55e2345de56, []int{19} } -func (m *ChildTx) XXX_Unmarshal(b []byte) error { +func (m *MalleatedTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *ChildTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MalleatedTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_ChildTx.Marshal(b, m, deterministic) + return xxx_messageInfo_MalleatedTx.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -1469,26 +1470,26 @@ func (m *ChildTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return b[:n], nil } } -func (m *ChildTx) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChildTx.Merge(m, src) +func (m *MalleatedTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_MalleatedTx.Merge(m, src) } -func (m *ChildTx) XXX_Size() int { +func (m *MalleatedTx) XXX_Size() int { return m.Size() } -func (m *ChildTx) XXX_DiscardUnknown() { - xxx_messageInfo_ChildTx.DiscardUnknown(m) +func (m *MalleatedTx) XXX_DiscardUnknown() { + xxx_messageInfo_MalleatedTx.DiscardUnknown(m) } -var xxx_messageInfo_ChildTx proto.InternalMessageInfo +var xxx_messageInfo_MalleatedTx proto.InternalMessageInfo -func (m *ChildTx) GetParentTxHash() []byte { +func (m *MalleatedTx) GetOriginalTxHash() []byte { if m != nil { - return m.ParentTxHash + return m.OriginalTxHash } return nil } -func (m *ChildTx) GetTx() []byte { +func (m *MalleatedTx) GetTx() []byte { if m != nil { return m.Tx } @@ -1517,122 +1518,122 @@ func init() { proto.RegisterType((*LightBlock)(nil), "tendermint.types.LightBlock") proto.RegisterType((*BlockMeta)(nil), "tendermint.types.BlockMeta") proto.RegisterType((*TxProof)(nil), "tendermint.types.TxProof") - proto.RegisterType((*ChildTx)(nil), "tendermint.types.ChildTx") + proto.RegisterType((*MalleatedTx)(nil), "tendermint.types.MalleatedTx") } func init() { proto.RegisterFile("tendermint/types/types.proto", fileDescriptor_d3a6e55e2345de56) } var fileDescriptor_d3a6e55e2345de56 = []byte{ - // 1743 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4b, 0x73, 0x1b, 0x59, - 0x15, 0x56, 0xeb, 0xad, 0x23, 0xc9, 0x96, 0x1b, 0x27, 0x91, 0x95, 0x44, 0x16, 0xe2, 0x31, 0x9e, - 0x07, 0x72, 0xc8, 0x50, 0x3c, 0xaa, 0x78, 0x8c, 0x24, 0x7b, 0x62, 0x31, 0xb6, 0x2c, 0x5a, 0x9a, - 0x50, 0xb0, 0xe9, 0xba, 0x52, 0xdf, 0x48, 0x4d, 0x5a, 0xdd, 0x4d, 0xf7, 0x95, 0x47, 0xce, 0x2f, - 0xa0, 0xbc, 0xca, 0x8a, 0x9d, 0x57, 0xb0, 0x60, 0xcf, 0x1f, 0xa0, 0x58, 0xcd, 0x86, 0xaa, 0xd9, - 0xc1, 0x86, 0x40, 0x25, 0x14, 0xc5, 0xcf, 0xa0, 0xee, 0xb9, 0xb7, 0x5b, 0x2d, 0x4b, 0x0a, 0x53, - 0xa9, 0x14, 0x1b, 0x55, 0xf7, 0x39, 0xdf, 0xb9, 0xf7, 0xdc, 0xef, 0xbc, 0x6e, 0x0b, 0xee, 0x31, - 0x6a, 0x1b, 0xd4, 0x9b, 0x9a, 0x36, 0x3b, 0x64, 0x97, 0x2e, 0xf5, 0xc5, 0x6f, 0xc3, 0xf5, 0x1c, - 0xe6, 0xa8, 0xa5, 0x85, 0xb6, 0x81, 0xf2, 0xca, 0xee, 0xd8, 0x19, 0x3b, 0xa8, 0x3c, 0xe4, 0x4f, - 0x02, 0x57, 0xd9, 0x1f, 0x3b, 0xce, 0xd8, 0xa2, 0x87, 0xf8, 0x36, 0x9c, 0x3d, 0x39, 0x64, 0xe6, - 0x94, 0xfa, 0x8c, 0x4c, 0x5d, 0x09, 0xb8, 0x1f, 0xd9, 0x66, 0xe4, 0x5d, 0xba, 0xcc, 0xe1, 0x58, - 0xe7, 0x89, 0x54, 0x57, 0x23, 0xea, 0x0b, 0xea, 0xf9, 0xa6, 0x63, 0x47, 0xfd, 0xa8, 0xd4, 0x56, - 0xbc, 0xbc, 0x20, 0x96, 0x69, 0x10, 0xe6, 0x78, 0x02, 0x51, 0xff, 0x01, 0x14, 0x7b, 0xc4, 0x63, - 0x7d, 0xca, 0x4e, 0x28, 0x31, 0xa8, 0xa7, 0xee, 0x42, 0x8a, 0x39, 0x8c, 0x58, 0x65, 0xa5, 0xa6, - 0x1c, 0x14, 0x35, 0xf1, 0xa2, 0xaa, 0x90, 0x9c, 0x10, 0x7f, 0x52, 0x8e, 0xd7, 0x94, 0x83, 0x82, - 0x86, 0xcf, 0xf5, 0x09, 0x24, 0xb9, 0x29, 0xb7, 0x30, 0x6d, 0x83, 0xce, 0x03, 0x0b, 0x7c, 0xe1, - 0xd2, 0xe1, 0x25, 0xa3, 0xbe, 0x34, 0x11, 0x2f, 0xea, 0x77, 0x20, 0x85, 0xfe, 0x97, 0x13, 0x35, - 0xe5, 0x20, 0xff, 0xb0, 0xdc, 0x88, 0x10, 0x25, 0xce, 0xd7, 0xe8, 0x71, 0x7d, 0x2b, 0xf9, 0xf9, - 0x8b, 0xfd, 0x98, 0x26, 0xc0, 0x75, 0x0b, 0x32, 0x2d, 0xcb, 0x19, 0x3d, 0xed, 0x1c, 0x85, 0x8e, - 0x28, 0x0b, 0x47, 0xd4, 0x33, 0xd8, 0x76, 0x89, 0xc7, 0x74, 0x9f, 0x32, 0x7d, 0x82, 0xa7, 0xc0, - 0x4d, 0xf3, 0x0f, 0xf7, 0x1b, 0x37, 0xe3, 0xd0, 0x58, 0x3a, 0xac, 0xdc, 0xa5, 0xe8, 0x46, 0x85, - 0xf5, 0x7f, 0x27, 0x21, 0x2d, 0xc9, 0xf8, 0x11, 0x64, 0x24, 0xad, 0xb8, 0x61, 0xfe, 0xe1, 0xfd, - 0xe8, 0x8a, 0x52, 0xd5, 0x68, 0x3b, 0xb6, 0x4f, 0x6d, 0x7f, 0xe6, 0xcb, 0xf5, 0x02, 0x1b, 0xf5, - 0x9b, 0x90, 0x1d, 0x4d, 0x88, 0x69, 0xeb, 0xa6, 0x81, 0x1e, 0xe5, 0x5a, 0xf9, 0x97, 0x2f, 0xf6, - 0x33, 0x6d, 0x2e, 0xeb, 0x1c, 0x69, 0x19, 0x54, 0x76, 0x0c, 0xf5, 0x36, 0xa4, 0x27, 0xd4, 0x1c, - 0x4f, 0x18, 0xd2, 0x92, 0xd0, 0xe4, 0x9b, 0xfa, 0x7d, 0x48, 0xf2, 0x84, 0x28, 0x27, 0x71, 0xef, - 0x4a, 0x43, 0x64, 0x4b, 0x23, 0xc8, 0x96, 0xc6, 0x20, 0xc8, 0x96, 0x56, 0x96, 0x6f, 0xfc, 0xfc, - 0x1f, 0xfb, 0x8a, 0x86, 0x16, 0x6a, 0x1b, 0x8a, 0x16, 0xf1, 0x99, 0x3e, 0xe4, 0xb4, 0xf1, 0xed, - 0x53, 0xb8, 0xc4, 0xde, 0x2a, 0x21, 0x92, 0x58, 0xe9, 0x7a, 0x9e, 0x5b, 0x09, 0x91, 0xa1, 0x1e, - 0x40, 0x09, 0x17, 0x19, 0x39, 0xd3, 0xa9, 0xc9, 0x74, 0xe4, 0x3d, 0x8d, 0xbc, 0x6f, 0x71, 0x79, - 0x1b, 0xc5, 0x27, 0x3c, 0x02, 0x77, 0x21, 0x67, 0x10, 0x46, 0x04, 0x24, 0x83, 0x90, 0x2c, 0x17, - 0xa0, 0xf2, 0x1d, 0xd8, 0x0e, 0xb3, 0xce, 0x17, 0x90, 0xac, 0x58, 0x65, 0x21, 0x46, 0xe0, 0x03, - 0xd8, 0xb5, 0xe9, 0x9c, 0xe9, 0x37, 0xd1, 0x39, 0x44, 0xab, 0x5c, 0xf7, 0x78, 0xd9, 0xe2, 0x1b, - 0xb0, 0x35, 0x0a, 0xc8, 0x17, 0x58, 0x40, 0x6c, 0x31, 0x94, 0x22, 0x6c, 0x0f, 0xb2, 0xc4, 0x75, - 0x05, 0x20, 0x8f, 0x80, 0x0c, 0x71, 0x5d, 0x54, 0xbd, 0x07, 0x3b, 0x78, 0x46, 0x8f, 0xfa, 0x33, - 0x8b, 0xc9, 0x45, 0x0a, 0x88, 0xd9, 0xe6, 0x0a, 0x4d, 0xc8, 0x11, 0xfb, 0x35, 0x28, 0xd2, 0x0b, - 0xd3, 0xa0, 0xf6, 0x88, 0x0a, 0x5c, 0x11, 0x71, 0x85, 0x40, 0x88, 0xa0, 0x77, 0xa1, 0xe4, 0x7a, - 0x8e, 0xeb, 0xf8, 0xd4, 0xd3, 0x89, 0x61, 0x78, 0xd4, 0xf7, 0xcb, 0x5b, 0x62, 0xbd, 0x40, 0xde, - 0x14, 0xe2, 0xfa, 0x0b, 0x05, 0x92, 0x47, 0x84, 0x11, 0xb5, 0x04, 0x09, 0x36, 0xf7, 0xcb, 0x4a, - 0x2d, 0x71, 0x50, 0xd0, 0xf8, 0xa3, 0xfa, 0x11, 0x64, 0x83, 0x55, 0x65, 0xa9, 0x54, 0x57, 0x43, - 0x77, 0x2c, 0x11, 0xa7, 0xa6, 0xcf, 0x64, 0xfc, 0x42, 0x2b, 0xf5, 0x87, 0x90, 0x9d, 0x52, 0xdf, - 0x27, 0x63, 0xea, 0x87, 0xf9, 0xb3, 0xb2, 0xc2, 0x99, 0x44, 0x04, 0xd6, 0x81, 0x05, 0x0f, 0x85, - 0xe3, 0x99, 0x63, 0xd3, 0x26, 0x96, 0xee, 0xff, 0x7a, 0x46, 0x3c, 0xaa, 0xfb, 0xe6, 0x33, 0x8a, - 0x69, 0x94, 0xd4, 0xd4, 0x40, 0xd7, 0x47, 0x55, 0xdf, 0x7c, 0x46, 0xc3, 0xc2, 0x4c, 0x47, 0x3a, - 0xc4, 0xf3, 0x38, 0xdc, 0x3a, 0x9a, 0xb9, 0x96, 0x39, 0x22, 0x8c, 0x3e, 0x76, 0x18, 0x0d, 0x3c, - 0x56, 0xbf, 0x05, 0xe9, 0x0b, 0x87, 0x51, 0x9d, 0xc8, 0xba, 0xba, 0xbd, 0xea, 0x1b, 0xc7, 0x6b, - 0x29, 0x8e, 0x6a, 0x86, 0xf0, 0xa1, 0x2c, 0xec, 0xd7, 0xc2, 0x5b, 0xea, 0x07, 0xa0, 0x62, 0xdb, - 0xd2, 0x2f, 0x1c, 0x66, 0xda, 0x63, 0xdd, 0x75, 0x3e, 0xa3, 0x9e, 0xac, 0xad, 0x12, 0x6a, 0x1e, - 0xa3, 0xa2, 0xc7, 0xe5, 0x4b, 0xf9, 0x29, 0xa1, 0x49, 0x84, 0x2e, 0xf2, 0x53, 0x00, 0x5b, 0x90, - 0x0b, 0xfb, 0xb3, 0x2c, 0xa8, 0x2f, 0x57, 0x93, 0x0b, 0xb3, 0xfa, 0x5f, 0xe2, 0xb0, 0x77, 0xca, - 0x8b, 0xbb, 0x6d, 0x99, 0xd4, 0x66, 0x4d, 0xc6, 0xc8, 0xe8, 0x69, 0x48, 0x4b, 0x07, 0x76, 0x46, - 0x8e, 0xfd, 0xc4, 0x32, 0x47, 0xe8, 0x37, 0x56, 0xaf, 0x64, 0xe8, 0xde, 0xea, 0x91, 0x71, 0x1d, - 0x2c, 0x56, 0xad, 0x14, 0x31, 0x43, 0x09, 0x4f, 0x56, 0x5e, 0xb7, 0x8e, 0xad, 0xcb, 0xd6, 0x12, - 0xc7, 0x33, 0x15, 0x84, 0xf0, 0x44, 0x34, 0x98, 0x2e, 0xec, 0x0e, 0x2f, 0x9f, 0x11, 0x9b, 0x99, - 0x36, 0x8d, 0x94, 0x5d, 0x39, 0x51, 0x4b, 0x1c, 0xe4, 0x1f, 0xde, 0x5d, 0xc3, 0x72, 0x80, 0xd1, - 0xbe, 0x12, 0x1a, 0x2e, 0x6a, 0x72, 0x03, 0xf1, 0xc9, 0x0d, 0xc4, 0xbf, 0x0d, 0x3e, 0xff, 0xa5, - 0x40, 0x36, 0xa4, 0x8f, 0xc0, 0x1d, 0x23, 0x48, 0x37, 0x1d, 0x13, 0x26, 0x2c, 0x22, 0x41, 0xe2, - 0x3b, 0xab, 0x27, 0x5a, 0x9b, 0x9f, 0x27, 0x31, 0xed, 0x96, 0xb1, 0x36, 0x71, 0x6d, 0xb8, 0x67, - 0x71, 0xea, 0xf4, 0x11, 0xc6, 0x4f, 0x27, 0x18, 0xc0, 0xc5, 0x3e, 0x22, 0x3f, 0xdf, 0xdf, 0x10, - 0xac, 0x75, 0x41, 0x3f, 0x89, 0x69, 0x7b, 0xd6, 0x26, 0x65, 0x2b, 0x05, 0x09, 0x7f, 0x36, 0xad, - 0x9f, 0x42, 0x21, 0x5a, 0xed, 0xbc, 0xba, 0x23, 0x47, 0x4b, 0xac, 0xaf, 0xee, 0x70, 0x91, 0x1b, - 0xbd, 0xa1, 0xfe, 0x53, 0xc8, 0x06, 0x95, 0xaf, 0xfe, 0x18, 0x8a, 0x41, 0xd5, 0xeb, 0x96, 0xe9, - 0x33, 0xb9, 0xdc, 0xde, 0xc6, 0x66, 0xa1, 0x15, 0x02, 0x3c, 0xf7, 0xa4, 0xfe, 0x11, 0x64, 0xa4, - 0x42, 0xfd, 0x2a, 0x14, 0x6c, 0x32, 0xa5, 0xbe, 0x4b, 0x46, 0x94, 0xcf, 0x1c, 0x31, 0xa3, 0xf3, - 0xa1, 0xac, 0x63, 0xf0, 0x2e, 0xc1, 0xe7, 0x42, 0x70, 0x8f, 0xe0, 0xcf, 0xf5, 0xff, 0xc4, 0x21, - 0xc9, 0x39, 0x56, 0x3f, 0x84, 0x24, 0xdf, 0x09, 0xed, 0xb6, 0xd6, 0x0d, 0xef, 0xbe, 0x39, 0xb6, - 0xa9, 0x71, 0xe6, 0x8f, 0x07, 0x97, 0x2e, 0xd5, 0x10, 0x1c, 0x99, 0x9d, 0xf1, 0xa5, 0xd9, 0xb9, - 0x0b, 0x29, 0xcf, 0x99, 0xd9, 0x06, 0x96, 0x7d, 0x4a, 0x13, 0x2f, 0xea, 0x31, 0x64, 0xc3, 0x91, - 0x98, 0xfc, 0x5f, 0x23, 0x71, 0x9b, 0xd3, 0xc6, 0x07, 0xb6, 0x14, 0x68, 0x99, 0xa1, 0x9c, 0x8c, - 0x6f, 0x21, 0x73, 0xd5, 0xf7, 0x61, 0x67, 0xd1, 0x76, 0x82, 0x49, 0x21, 0xba, 0x67, 0x29, 0x54, - 0xc8, 0x51, 0xb1, 0xdc, 0xa3, 0xc4, 0x6d, 0x2b, 0x83, 0xe7, 0x5a, 0xf4, 0xa8, 0x0e, 0x5e, 0xbb, - 0xee, 0x41, 0xce, 0x37, 0xc7, 0x36, 0x61, 0x33, 0x8f, 0xca, 0x31, 0xbb, 0x10, 0xd4, 0xff, 0xa4, - 0x40, 0x5a, 0x8c, 0xed, 0x08, 0x6f, 0xca, 0x7a, 0xde, 0xe2, 0x9b, 0x78, 0x4b, 0xbc, 0x39, 0x6f, - 0x4d, 0x80, 0xd0, 0x19, 0x3e, 0x96, 0x36, 0x74, 0x19, 0xe1, 0x62, 0xdf, 0x1c, 0xcb, 0xcc, 0x8d, - 0x18, 0xd5, 0xff, 0xae, 0x40, 0x2e, 0xd4, 0xab, 0x4d, 0x28, 0x06, 0x7e, 0xe9, 0x4f, 0x2c, 0x32, - 0x96, 0xb9, 0x73, 0x7f, 0xa3, 0x73, 0x1f, 0x5b, 0x64, 0xac, 0xe5, 0xa5, 0x3f, 0xfc, 0x65, 0x7d, - 0x1c, 0xe2, 0x1b, 0xe2, 0xb0, 0x14, 0xf8, 0xc4, 0x9b, 0x05, 0x7e, 0x29, 0x44, 0xc9, 0x9b, 0x21, - 0xfa, 0x63, 0x1c, 0xb2, 0x3d, 0xbc, 0x28, 0x10, 0xeb, 0xff, 0x51, 0x11, 0x77, 0x21, 0xe7, 0x3a, - 0x96, 0x2e, 0x34, 0x49, 0xd4, 0x64, 0x5d, 0xc7, 0xd2, 0x56, 0xc2, 0x9e, 0x7a, 0x4b, 0xe5, 0x92, - 0x7e, 0x0b, 0xac, 0x65, 0x6e, 0xb2, 0xe6, 0x41, 0x41, 0x50, 0x21, 0x2f, 0xee, 0x0f, 0x38, 0x07, - 0xf8, 0x25, 0xa0, 0xac, 0x7e, 0x68, 0x08, 0xb7, 0x05, 0x52, 0x93, 0x38, 0x6e, 0x21, 0xee, 0xb9, - 0xb2, 0x85, 0x97, 0x37, 0xa5, 0xa5, 0x26, 0x71, 0xf5, 0xdf, 0x2a, 0x00, 0x8b, 0x11, 0xcc, 0xaf, - 0xdc, 0x3e, 0xba, 0xa0, 0x2f, 0xed, 0x5c, 0xdd, 0x14, 0x34, 0xb9, 0x7f, 0xc1, 0x8f, 0xfa, 0xdd, - 0x86, 0xe2, 0x22, 0x19, 0x7d, 0x1a, 0x38, 0x53, 0x7d, 0xcd, 0x24, 0xee, 0x53, 0xa6, 0x15, 0x2e, - 0x22, 0x6f, 0xf5, 0x3f, 0x2b, 0x90, 0x43, 0x9f, 0xce, 0x28, 0x23, 0x4b, 0x31, 0x54, 0xde, 0x3c, - 0x86, 0xf7, 0x01, 0xc4, 0x32, 0x78, 0x0f, 0x14, 0x99, 0x95, 0x43, 0x09, 0x5e, 0xff, 0xbe, 0x1b, - 0x12, 0x9e, 0x78, 0x3d, 0xe1, 0xb2, 0xa4, 0x03, 0xda, 0xef, 0x40, 0xc6, 0x9e, 0x4d, 0x75, 0x7e, - 0xfd, 0x15, 0xd7, 0x84, 0xb4, 0x3d, 0x9b, 0x0e, 0xe6, 0x7e, 0xfd, 0x57, 0x90, 0x19, 0xcc, 0xf1, - 0x5b, 0x90, 0xa7, 0xa8, 0xe7, 0x38, 0xf2, 0x03, 0x44, 0x0c, 0x95, 0x2c, 0x17, 0xe0, 0x7d, 0x7b, - 0xcd, 0x44, 0x51, 0x1b, 0x5f, 0xf2, 0x2b, 0x33, 0xf8, 0xbe, 0xfc, 0x09, 0x64, 0xda, 0x13, 0xd3, - 0x32, 0x06, 0x73, 0xf5, 0xeb, 0xb0, 0xe5, 0x12, 0x8f, 0x4f, 0x76, 0x36, 0x8f, 0x6e, 0x58, 0x10, - 0xd2, 0xc1, 0x1c, 0x37, 0xdd, 0x82, 0x38, 0x9b, 0xcb, 0x2d, 0xe3, 0x6c, 0xfe, 0xde, 0x5f, 0x15, - 0xc8, 0x47, 0x1a, 0x8c, 0xfa, 0x6d, 0xb8, 0xd5, 0x3a, 0x3d, 0x6f, 0x7f, 0xa2, 0x77, 0x8e, 0xf4, - 0x8f, 0x4f, 0x9b, 0x8f, 0xf4, 0x4f, 0xbb, 0x9f, 0x74, 0xcf, 0x7f, 0xde, 0x2d, 0xc5, 0x2a, 0xb7, - 0xaf, 0xae, 0x6b, 0x6a, 0x04, 0xfb, 0xa9, 0xfd, 0xd4, 0x76, 0x3e, 0xb3, 0xd5, 0x43, 0xd8, 0x5d, - 0x36, 0x69, 0xb6, 0xfa, 0xc7, 0xdd, 0x41, 0x49, 0xa9, 0xdc, 0xba, 0xba, 0xae, 0xed, 0x44, 0x2c, - 0x9a, 0x43, 0x9f, 0xda, 0x6c, 0xd5, 0xa0, 0x7d, 0x7e, 0x76, 0xd6, 0x19, 0x94, 0xe2, 0x2b, 0x06, - 0xb2, 0xe3, 0xbf, 0x0b, 0x3b, 0xcb, 0x06, 0xdd, 0xce, 0x69, 0x29, 0x51, 0x51, 0xaf, 0xae, 0x6b, - 0x5b, 0x11, 0x74, 0xd7, 0xb4, 0x2a, 0xd9, 0xdf, 0xfc, 0xae, 0x1a, 0xfb, 0xc3, 0xef, 0xab, 0x0a, - 0x3f, 0x59, 0x71, 0xa9, 0xc9, 0xa8, 0x1f, 0xc0, 0x9d, 0x7e, 0xe7, 0x51, 0xf7, 0xf8, 0x48, 0x3f, - 0xeb, 0x3f, 0xd2, 0x07, 0xbf, 0xe8, 0x1d, 0x47, 0x4e, 0xb7, 0x7d, 0x75, 0x5d, 0xcb, 0xcb, 0x23, - 0x6d, 0x42, 0xf7, 0xb4, 0xe3, 0xc7, 0xe7, 0x83, 0xe3, 0x92, 0x22, 0xd0, 0x3d, 0x8f, 0xf2, 0xab, - 0x1a, 0xa2, 0x1f, 0xc0, 0xde, 0x1a, 0x74, 0x78, 0xb0, 0x9d, 0xab, 0xeb, 0x5a, 0xb1, 0xe7, 0x51, - 0x51, 0x80, 0x68, 0xd1, 0x80, 0xf2, 0xaa, 0xc5, 0x79, 0xef, 0xbc, 0xdf, 0x3c, 0x2d, 0xd5, 0x2a, - 0xa5, 0xab, 0xeb, 0x5a, 0x21, 0xe8, 0xa6, 0x1c, 0xbf, 0x38, 0x59, 0xeb, 0x67, 0x9f, 0xbf, 0xac, - 0x2a, 0x5f, 0xbc, 0xac, 0x2a, 0xff, 0x7c, 0x59, 0x55, 0x9e, 0xbf, 0xaa, 0xc6, 0xbe, 0x78, 0x55, - 0x8d, 0xfd, 0xed, 0x55, 0x35, 0xf6, 0xcb, 0xef, 0x8d, 0x4d, 0x36, 0x99, 0x0d, 0x1b, 0x23, 0x67, - 0x7a, 0x18, 0xfd, 0x03, 0x65, 0xf1, 0x28, 0xfe, 0xc8, 0xb9, 0xf9, 0xe7, 0xca, 0x30, 0x8d, 0xf2, - 0x0f, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x74, 0x3d, 0x85, 0x46, 0x1d, 0x12, 0x00, 0x00, + // 1744 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcd, 0x73, 0x1b, 0x49, + 0x15, 0xf7, 0x48, 0xb2, 0x3e, 0x9e, 0x24, 0x5b, 0x1e, 0x9c, 0x44, 0x56, 0x12, 0x59, 0x88, 0x82, + 0xf5, 0x7e, 0x20, 0x87, 0x2c, 0xc5, 0x47, 0x15, 0x50, 0x2b, 0xd9, 0xde, 0x58, 0xac, 0x3f, 0xc4, + 0x48, 0x1b, 0x0a, 0x2e, 0x53, 0x2d, 0x4d, 0x47, 0x1a, 0x32, 0x9a, 0x19, 0xa6, 0x5b, 0x5e, 0x39, + 0x7f, 0x01, 0xe5, 0x53, 0x4e, 0xdc, 0x7c, 0x82, 0x03, 0x77, 0xfe, 0x01, 0x8a, 0xd3, 0x5e, 0xa8, + 0xda, 0x1b, 0x5c, 0x08, 0x54, 0x42, 0x51, 0xfc, 0x19, 0x54, 0xbf, 0xee, 0x19, 0x8d, 0x2c, 0x29, + 0xa4, 0x52, 0x29, 0x2e, 0xaa, 0x99, 0xf7, 0x7e, 0xaf, 0xfb, 0xf5, 0xef, 0x7d, 0xf5, 0x08, 0xee, + 0x71, 0xea, 0x5a, 0x34, 0x18, 0xdb, 0x2e, 0xdf, 0xe7, 0x97, 0x3e, 0x65, 0xf2, 0xb7, 0xe1, 0x07, + 0x1e, 0xf7, 0xf4, 0xd2, 0x4c, 0xdb, 0x40, 0x79, 0x65, 0x7b, 0xe8, 0x0d, 0x3d, 0x54, 0xee, 0x8b, + 0x27, 0x89, 0xab, 0xec, 0x0e, 0x3d, 0x6f, 0xe8, 0xd0, 0x7d, 0x7c, 0xeb, 0x4f, 0x9e, 0xec, 0x73, + 0x7b, 0x4c, 0x19, 0x27, 0x63, 0x5f, 0x01, 0xee, 0xc7, 0xb6, 0x19, 0x04, 0x97, 0x3e, 0xf7, 0x04, + 0xd6, 0x7b, 0xa2, 0xd4, 0xd5, 0x98, 0xfa, 0x82, 0x06, 0xcc, 0xf6, 0xdc, 0xb8, 0x1f, 0x95, 0xda, + 0x82, 0x97, 0x17, 0xc4, 0xb1, 0x2d, 0xc2, 0xbd, 0x40, 0x22, 0xea, 0x3f, 0x84, 0x62, 0x87, 0x04, + 0xbc, 0x4b, 0xf9, 0x31, 0x25, 0x16, 0x0d, 0xf4, 0x6d, 0x58, 0xe7, 0x1e, 0x27, 0x4e, 0x59, 0xab, + 0x69, 0x7b, 0x45, 0x43, 0xbe, 0xe8, 0x3a, 0xa4, 0x46, 0x84, 0x8d, 0xca, 0x89, 0x9a, 0xb6, 0x57, + 0x30, 0xf0, 0xb9, 0x3e, 0x82, 0x94, 0x30, 0x15, 0x16, 0xb6, 0x6b, 0xd1, 0x69, 0x68, 0x81, 0x2f, + 0x42, 0xda, 0xbf, 0xe4, 0x94, 0x29, 0x13, 0xf9, 0xa2, 0x7f, 0x17, 0xd6, 0xd1, 0xff, 0x72, 0xb2, + 0xa6, 0xed, 0xe5, 0x1f, 0x96, 0x1b, 0x31, 0xa2, 0xe4, 0xf9, 0x1a, 0x1d, 0xa1, 0x6f, 0xa5, 0xbe, + 0x7c, 0xb1, 0xbb, 0x66, 0x48, 0x70, 0xdd, 0x81, 0x4c, 0xcb, 0xf1, 0x06, 0x4f, 0xdb, 0x87, 0x91, + 0x23, 0xda, 0xcc, 0x11, 0xfd, 0x14, 0x36, 0x7d, 0x12, 0x70, 0x93, 0x51, 0x6e, 0x8e, 0xf0, 0x14, + 0xb8, 0x69, 0xfe, 0xe1, 0x6e, 0xe3, 0x66, 0x1c, 0x1a, 0x73, 0x87, 0x55, 0xbb, 0x14, 0xfd, 0xb8, + 0xb0, 0xfe, 0xef, 0x14, 0xa4, 0x15, 0x19, 0x3f, 0x86, 0x8c, 0xa2, 0x15, 0x37, 0xcc, 0x3f, 0xbc, + 0x1f, 0x5f, 0x51, 0xa9, 0x1a, 0x07, 0x9e, 0xcb, 0xa8, 0xcb, 0x26, 0x4c, 0xad, 0x17, 0xda, 0xe8, + 0xdf, 0x82, 0xec, 0x60, 0x44, 0x6c, 0xd7, 0xb4, 0x2d, 0xf4, 0x28, 0xd7, 0xca, 0xbf, 0x7c, 0xb1, + 0x9b, 0x39, 0x10, 0xb2, 0xf6, 0xa1, 0x91, 0x41, 0x65, 0xdb, 0xd2, 0x6f, 0x43, 0x7a, 0x44, 0xed, + 0xe1, 0x88, 0x23, 0x2d, 0x49, 0x43, 0xbd, 0xe9, 0x3f, 0x80, 0x94, 0x48, 0x88, 0x72, 0x0a, 0xf7, + 0xae, 0x34, 0x64, 0xb6, 0x34, 0xc2, 0x6c, 0x69, 0xf4, 0xc2, 0x6c, 0x69, 0x65, 0xc5, 0xc6, 0xcf, + 0xff, 0xb1, 0xab, 0x19, 0x68, 0xa1, 0x1f, 0x40, 0xd1, 0x21, 0x8c, 0x9b, 0x7d, 0x41, 0x9b, 0xd8, + 0x7e, 0x1d, 0x97, 0xd8, 0x59, 0x24, 0x44, 0x11, 0xab, 0x5c, 0xcf, 0x0b, 0x2b, 0x29, 0xb2, 0xf4, + 0x3d, 0x28, 0xe1, 0x22, 0x03, 0x6f, 0x3c, 0xb6, 0xb9, 0x89, 0xbc, 0xa7, 0x91, 0xf7, 0x0d, 0x21, + 0x3f, 0x40, 0xf1, 0xb1, 0x88, 0xc0, 0x5d, 0xc8, 0x59, 0x84, 0x13, 0x09, 0xc9, 0x20, 0x24, 0x2b, + 0x04, 0xa8, 0x7c, 0x0f, 0x36, 0xa3, 0xac, 0x63, 0x12, 0x92, 0x95, 0xab, 0xcc, 0xc4, 0x08, 0x7c, + 0x00, 0xdb, 0x2e, 0x9d, 0x72, 0xf3, 0x26, 0x3a, 0x87, 0x68, 0x5d, 0xe8, 0x1e, 0xcf, 0x5b, 0x7c, + 0x13, 0x36, 0x06, 0x21, 0xf9, 0x12, 0x0b, 0x88, 0x2d, 0x46, 0x52, 0x84, 0xed, 0x40, 0x96, 0xf8, + 0xbe, 0x04, 0xe4, 0x11, 0x90, 0x21, 0xbe, 0x8f, 0xaa, 0x0f, 0x60, 0x0b, 0xcf, 0x18, 0x50, 0x36, + 0x71, 0xb8, 0x5a, 0xa4, 0x80, 0x98, 0x4d, 0xa1, 0x30, 0xa4, 0x1c, 0xb1, 0xdf, 0x80, 0x22, 0xbd, + 0xb0, 0x2d, 0xea, 0x0e, 0xa8, 0xc4, 0x15, 0x11, 0x57, 0x08, 0x85, 0x08, 0x7a, 0x1f, 0x4a, 0x7e, + 0xe0, 0xf9, 0x1e, 0xa3, 0x81, 0x49, 0x2c, 0x2b, 0xa0, 0x8c, 0x95, 0x37, 0xe4, 0x7a, 0xa1, 0xbc, + 0x29, 0xc5, 0xf5, 0x17, 0x1a, 0xa4, 0x0e, 0x09, 0x27, 0x7a, 0x09, 0x92, 0x7c, 0xca, 0xca, 0x5a, + 0x2d, 0xb9, 0x57, 0x30, 0xc4, 0xa3, 0xfe, 0x09, 0x64, 0xc3, 0x55, 0x55, 0xa9, 0x54, 0x17, 0x43, + 0x77, 0xa4, 0x10, 0x27, 0x36, 0xe3, 0x2a, 0x7e, 0x91, 0x95, 0xfe, 0x23, 0xc8, 0x8e, 0x29, 0x63, + 0x64, 0x48, 0x59, 0x94, 0x3f, 0x0b, 0x2b, 0x9c, 0x2a, 0x44, 0x68, 0x1d, 0x5a, 0x88, 0x50, 0x78, + 0x81, 0x3d, 0xb4, 0x5d, 0xe2, 0x98, 0xec, 0xd7, 0x13, 0x12, 0x50, 0x93, 0xd9, 0xcf, 0x28, 0xa6, + 0x51, 0xca, 0xd0, 0x43, 0x5d, 0x17, 0x55, 0x5d, 0xfb, 0x19, 0x8d, 0x0a, 0x33, 0x1d, 0xeb, 0x10, + 0xcf, 0x13, 0x70, 0xeb, 0x70, 0xe2, 0x3b, 0xf6, 0x80, 0x70, 0xfa, 0xd8, 0xe3, 0x34, 0xf4, 0x58, + 0xff, 0x36, 0xa4, 0x2f, 0x3c, 0x4e, 0x4d, 0xa2, 0xea, 0xea, 0xf6, 0xa2, 0x6f, 0x02, 0x6f, 0xac, + 0x0b, 0x54, 0x33, 0x82, 0xf7, 0x55, 0x61, 0xbf, 0x16, 0xde, 0xd2, 0x3f, 0x02, 0x1d, 0xdb, 0x96, + 0x79, 0xe1, 0x71, 0xdb, 0x1d, 0x9a, 0xbe, 0xf7, 0x05, 0x0d, 0x54, 0x6d, 0x95, 0x50, 0xf3, 0x18, + 0x15, 0x1d, 0x21, 0x9f, 0xcb, 0x4f, 0x05, 0x4d, 0x21, 0x74, 0x96, 0x9f, 0x12, 0xd8, 0x82, 0x5c, + 0xd4, 0x9f, 0x55, 0x41, 0xbd, 0x59, 0x4d, 0xce, 0xcc, 0xea, 0x7f, 0x49, 0xc0, 0xce, 0x89, 0x28, + 0xee, 0x03, 0xc7, 0xa6, 0x2e, 0x6f, 0x72, 0x4e, 0x06, 0x4f, 0x23, 0x5a, 0xda, 0xb0, 0x35, 0xf0, + 0xdc, 0x27, 0x8e, 0x3d, 0x40, 0xbf, 0xb1, 0x7a, 0x15, 0x43, 0xf7, 0x16, 0x8f, 0x8c, 0xeb, 0x60, + 0xb1, 0x1a, 0xa5, 0x98, 0x19, 0x4a, 0x44, 0xb2, 0x8a, 0xba, 0xf5, 0x5c, 0x53, 0xb5, 0x96, 0x04, + 0x9e, 0xa9, 0x20, 0x85, 0xc7, 0xb2, 0xc1, 0x9c, 0xc1, 0x76, 0xff, 0xf2, 0x19, 0x71, 0xb9, 0xed, + 0xd2, 0x58, 0xd9, 0x95, 0x93, 0xb5, 0xe4, 0x5e, 0xfe, 0xe1, 0xdd, 0x25, 0x2c, 0x87, 0x18, 0xe3, + 0x6b, 0x91, 0xe1, 0xac, 0x26, 0x57, 0x10, 0x9f, 0x5a, 0x41, 0xfc, 0xbb, 0xe0, 0xf3, 0x5f, 0x1a, + 0x64, 0x23, 0xfa, 0x08, 0xdc, 0xb1, 0xc2, 0x74, 0x33, 0x31, 0x61, 0xa2, 0x22, 0x92, 0x24, 0xbe, + 0xb7, 0x78, 0xa2, 0xa5, 0xf9, 0x79, 0xbc, 0x66, 0xdc, 0xb2, 0x96, 0x26, 0xae, 0x0b, 0xf7, 0x1c, + 0x41, 0x9d, 0x39, 0xc0, 0xf8, 0x99, 0x04, 0x03, 0x38, 0xdb, 0x47, 0xe6, 0xe7, 0x87, 0x2b, 0x82, + 0xb5, 0x2c, 0xe8, 0xc7, 0x6b, 0xc6, 0x8e, 0xb3, 0x4a, 0xd9, 0x5a, 0x87, 0x24, 0x9b, 0x8c, 0xeb, + 0x27, 0x50, 0x88, 0x57, 0xbb, 0xa8, 0xee, 0xd8, 0xd1, 0x92, 0xcb, 0xab, 0x3b, 0x5a, 0xe4, 0x46, + 0x6f, 0xa8, 0xff, 0x14, 0xb2, 0x61, 0xe5, 0xeb, 0x3f, 0x81, 0x62, 0x58, 0xf5, 0xa6, 0x63, 0x33, + 0xae, 0x96, 0xdb, 0x59, 0xd9, 0x2c, 0x8c, 0x42, 0x88, 0x17, 0x9e, 0xd4, 0x3f, 0x81, 0x8c, 0x52, + 0xe8, 0x5f, 0x87, 0x82, 0x4b, 0xc6, 0x94, 0xf9, 0x64, 0x40, 0xc5, 0xcc, 0x91, 0x33, 0x3a, 0x1f, + 0xc9, 0xda, 0x96, 0xe8, 0x12, 0x62, 0x2e, 0x84, 0xf7, 0x08, 0xf1, 0x5c, 0xff, 0x4f, 0x02, 0x52, + 0x82, 0x63, 0xfd, 0x63, 0x48, 0x89, 0x9d, 0xd0, 0x6e, 0x63, 0xd9, 0xf0, 0xee, 0xda, 0x43, 0x97, + 0x5a, 0xa7, 0x6c, 0xd8, 0xbb, 0xf4, 0xa9, 0x81, 0xe0, 0xd8, 0xec, 0x4c, 0xcc, 0xcd, 0xce, 0x6d, + 0x58, 0x0f, 0xbc, 0x89, 0x6b, 0x61, 0xd9, 0xaf, 0x1b, 0xf2, 0x45, 0x3f, 0x82, 0x6c, 0x34, 0x12, + 0x53, 0xff, 0x6b, 0x24, 0x6e, 0x0a, 0xda, 0xc4, 0xc0, 0x56, 0x02, 0x23, 0xd3, 0x57, 0x93, 0xf1, + 0x1d, 0x64, 0xae, 0xfe, 0x21, 0x6c, 0xcd, 0xda, 0x4e, 0x38, 0x29, 0x64, 0xf7, 0x2c, 0x45, 0x0a, + 0x35, 0x2a, 0xe6, 0x7b, 0x94, 0xbc, 0x6d, 0x65, 0xf0, 0x5c, 0xb3, 0x1e, 0xd5, 0xc6, 0x6b, 0xd7, + 0x3d, 0xc8, 0x31, 0x7b, 0xe8, 0x12, 0x3e, 0x09, 0xa8, 0x1a, 0xb3, 0x33, 0x41, 0xfd, 0x4f, 0x1a, + 0xa4, 0xe5, 0xd8, 0x8e, 0xf1, 0xa6, 0x2d, 0xe7, 0x2d, 0xb1, 0x8a, 0xb7, 0xe4, 0xdb, 0xf3, 0xd6, + 0x04, 0x88, 0x9c, 0x11, 0x63, 0x69, 0x45, 0x97, 0x91, 0x2e, 0x76, 0xed, 0xa1, 0xca, 0xdc, 0x98, + 0x51, 0xfd, 0xef, 0x1a, 0xe4, 0x22, 0xbd, 0xde, 0x84, 0x62, 0xe8, 0x97, 0xf9, 0xc4, 0x21, 0x43, + 0x95, 0x3b, 0xf7, 0x57, 0x3a, 0xf7, 0xa9, 0x43, 0x86, 0x46, 0x5e, 0xf9, 0x23, 0x5e, 0x96, 0xc7, + 0x21, 0xb1, 0x22, 0x0e, 0x73, 0x81, 0x4f, 0xbe, 0x5d, 0xe0, 0xe7, 0x42, 0x94, 0xba, 0x19, 0xa2, + 0x3f, 0x26, 0x20, 0xdb, 0xc1, 0x8b, 0x02, 0x71, 0xfe, 0x1f, 0x15, 0x71, 0x17, 0x72, 0xbe, 0xe7, + 0x98, 0x52, 0x93, 0x42, 0x4d, 0xd6, 0xf7, 0x1c, 0x63, 0x21, 0xec, 0xeb, 0xef, 0xa8, 0x5c, 0xd2, + 0xef, 0x80, 0xb5, 0xcc, 0x4d, 0xd6, 0x02, 0x28, 0x48, 0x2a, 0xd4, 0xc5, 0xfd, 0x81, 0xe0, 0x00, + 0xbf, 0x04, 0xb4, 0xc5, 0x0f, 0x0d, 0xe9, 0xb6, 0x44, 0x1a, 0x0a, 0x27, 0x2c, 0xe4, 0x3d, 0x57, + 0xb5, 0xf0, 0xf2, 0xaa, 0xb4, 0x34, 0x14, 0xae, 0xfe, 0x5b, 0x0d, 0x60, 0x36, 0x82, 0xc5, 0x95, + 0x9b, 0xa1, 0x0b, 0xe6, 0xdc, 0xce, 0xd5, 0x55, 0x41, 0x53, 0xfb, 0x17, 0x58, 0xdc, 0xef, 0x03, + 0x28, 0xce, 0x92, 0x91, 0xd1, 0xd0, 0x99, 0xea, 0x6b, 0x26, 0x71, 0x97, 0x72, 0xa3, 0x70, 0x11, + 0x7b, 0xab, 0xff, 0x59, 0x83, 0x1c, 0xfa, 0x74, 0x4a, 0x39, 0x99, 0x8b, 0xa1, 0xf6, 0xf6, 0x31, + 0xbc, 0x0f, 0x20, 0x97, 0xc1, 0x7b, 0xa0, 0xcc, 0xac, 0x1c, 0x4a, 0xf0, 0xfa, 0xf7, 0xbd, 0x88, + 0xf0, 0xe4, 0xeb, 0x09, 0x57, 0x25, 0x1d, 0xd2, 0x7e, 0x07, 0x32, 0xee, 0x64, 0x6c, 0x8a, 0xeb, + 0xaf, 0xbc, 0x26, 0xa4, 0xdd, 0xc9, 0xb8, 0x37, 0x65, 0xf5, 0x5f, 0x41, 0xa6, 0x37, 0xc5, 0x6f, + 0x41, 0x91, 0xa2, 0x81, 0xe7, 0xa9, 0x0f, 0x10, 0x39, 0x54, 0xb2, 0x42, 0x80, 0xf7, 0xed, 0x25, + 0x13, 0x45, 0x6f, 0xbc, 0xe1, 0x57, 0x66, 0xf8, 0x7d, 0xf9, 0x08, 0xf2, 0xa7, 0xc4, 0x71, 0x28, + 0xe1, 0xd4, 0xea, 0x4d, 0xc5, 0x77, 0x4f, 0x74, 0xf9, 0xe5, 0xd3, 0xf8, 0xb6, 0x1b, 0xa1, 0xbc, + 0x37, 0xc5, 0xcd, 0x37, 0x20, 0xc1, 0xa7, 0x6a, 0xeb, 0x04, 0x9f, 0x7e, 0xf0, 0x57, 0x0d, 0xf2, + 0xb1, 0x46, 0xa3, 0x7f, 0x07, 0x6e, 0xb5, 0x4e, 0xce, 0x0f, 0x3e, 0x33, 0xdb, 0x87, 0xe6, 0xa7, + 0x27, 0xcd, 0x47, 0xe6, 0xe7, 0x67, 0x9f, 0x9d, 0x9d, 0xff, 0xfc, 0xac, 0xb4, 0x56, 0xb9, 0x7d, + 0x75, 0x5d, 0xd3, 0x63, 0xd8, 0xcf, 0xdd, 0xa7, 0xae, 0xf7, 0x85, 0xab, 0xef, 0xc3, 0xf6, 0xbc, + 0x49, 0xb3, 0xd5, 0x3d, 0x3a, 0xeb, 0x95, 0xb4, 0xca, 0xad, 0xab, 0xeb, 0xda, 0x56, 0xcc, 0xa2, + 0xd9, 0x67, 0xd4, 0xe5, 0x8b, 0x06, 0x07, 0xe7, 0xa7, 0xa7, 0xed, 0x5e, 0x29, 0xb1, 0x60, 0xa0, + 0x3a, 0xff, 0xfb, 0xb0, 0x35, 0x6f, 0x70, 0xd6, 0x3e, 0x29, 0x25, 0x2b, 0xfa, 0xd5, 0x75, 0x6d, + 0x23, 0x86, 0x3e, 0xb3, 0x9d, 0x4a, 0xf6, 0x37, 0xbf, 0xab, 0xae, 0xfd, 0xe1, 0xf7, 0x55, 0x4d, + 0x9c, 0xac, 0x38, 0xd7, 0x6c, 0xf4, 0x8f, 0xe0, 0x4e, 0xb7, 0xfd, 0xe8, 0xec, 0xe8, 0xd0, 0x3c, + 0xed, 0x3e, 0x32, 0x7b, 0xbf, 0xe8, 0x1c, 0xc5, 0x4e, 0xb7, 0x79, 0x75, 0x5d, 0xcb, 0xab, 0x23, + 0xad, 0x42, 0x77, 0x8c, 0xa3, 0xc7, 0xe7, 0xbd, 0xa3, 0x92, 0x26, 0xd1, 0x9d, 0x80, 0x8a, 0x2b, + 0x1b, 0xa2, 0x1f, 0xc0, 0xce, 0x12, 0x74, 0x74, 0xb0, 0xad, 0xab, 0xeb, 0x5a, 0xb1, 0x13, 0x50, + 0x59, 0x88, 0x68, 0xd1, 0x80, 0xf2, 0xa2, 0xc5, 0x79, 0xe7, 0xbc, 0xdb, 0x3c, 0x29, 0xd5, 0x2a, + 0xa5, 0xab, 0xeb, 0x5a, 0x21, 0xec, 0xaa, 0x02, 0x3f, 0x3b, 0x59, 0xeb, 0x67, 0x5f, 0xbe, 0xac, + 0x6a, 0x5f, 0xbd, 0xac, 0x6a, 0xff, 0x7c, 0x59, 0xd5, 0x9e, 0xbf, 0xaa, 0xae, 0x7d, 0xf5, 0xaa, + 0xba, 0xf6, 0xb7, 0x57, 0xd5, 0xb5, 0x5f, 0x7e, 0x7f, 0x68, 0xf3, 0xd1, 0xa4, 0xdf, 0x18, 0x78, + 0xe3, 0xfd, 0xf8, 0x1f, 0x29, 0xb3, 0x47, 0xf9, 0x87, 0xce, 0xcd, 0x3f, 0x59, 0xfa, 0x69, 0x94, + 0x7f, 0xfc, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x08, 0x7d, 0x29, 0x8d, 0x25, 0x12, 0x00, 0x00, } func (m *PartSetHeader) Marshal() (dAtA []byte, err error) { @@ -2708,7 +2709,7 @@ func (m *TxProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *ChildTx) Marshal() (dAtA []byte, err error) { +func (m *MalleatedTx) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -2718,12 +2719,12 @@ func (m *ChildTx) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *ChildTx) MarshalTo(dAtA []byte) (int, error) { +func (m *MalleatedTx) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *ChildTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MalleatedTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -2735,10 +2736,10 @@ func (m *ChildTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if len(m.ParentTxHash) > 0 { - i -= len(m.ParentTxHash) - copy(dAtA[i:], m.ParentTxHash) - i = encodeVarintTypes(dAtA, i, uint64(len(m.ParentTxHash))) + if len(m.OriginalTxHash) > 0 { + i -= len(m.OriginalTxHash) + copy(dAtA[i:], m.OriginalTxHash) + i = encodeVarintTypes(dAtA, i, uint64(len(m.OriginalTxHash))) i-- dAtA[i] = 0xa } @@ -3205,13 +3206,13 @@ func (m *TxProof) Size() (n int) { return n } -func (m *ChildTx) Size() (n int) { +func (m *MalleatedTx) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.ParentTxHash) + l = len(m.OriginalTxHash) if l > 0 { n += 1 + l + sovTypes(uint64(l)) } @@ -6444,7 +6445,7 @@ func (m *TxProof) Unmarshal(dAtA []byte) error { } return nil } -func (m *ChildTx) Unmarshal(dAtA []byte) error { +func (m *MalleatedTx) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -6467,15 +6468,15 @@ func (m *ChildTx) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ChildTx: wiretype end group for non-group") + return fmt.Errorf("proto: MalleatedTx: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ChildTx: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MalleatedTx: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ParentTxHash", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field OriginalTxHash", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -6502,9 +6503,9 @@ func (m *ChildTx) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ParentTxHash = append(m.ParentTxHash[:0], dAtA[iNdEx:postIndex]...) - if m.ParentTxHash == nil { - m.ParentTxHash = []byte{} + m.OriginalTxHash = append(m.OriginalTxHash[:0], dAtA[iNdEx:postIndex]...) + if m.OriginalTxHash == nil { + m.OriginalTxHash = []byte{} } iNdEx = postIndex case 2: diff --git a/proto/tendermint/types/types.proto b/proto/tendermint/types/types.proto index 89b3e21536..a1db322381 100644 --- a/proto/tendermint/types/types.proto +++ b/proto/tendermint/types/types.proto @@ -201,9 +201,10 @@ message TxProof { tendermint.crypto.Proof proof = 3; } -// ChildTx wraps a transaction that was derived from a parent transaction. This -// allows for removal of the parent transaction from the mempool. -message ChildTx { - bytes parent_tx_hash = 1; - bytes tx = 2; +// MalleatedTx wraps a transaction that was derived from a different original +// transaction. This allows for tendermint to track malleated and original +// transactions +message MalleatedTx { + bytes original_tx_hash = 1; + bytes tx = 2; } diff --git a/types/block.go b/types/block.go index 97d1bbae0e..b814b77a73 100644 --- a/types/block.go +++ b/types/block.go @@ -40,8 +40,10 @@ const ( // Uvarint length of MaxBlockSizeBytes: 4 bytes // 2 fields (2 embedded): 2 bytes // Uvarint length of Data.Txs: 4 bytes - // Data.Txs field: 1 byte - MaxOverheadForBlock int64 = 11 + // Data fields: 6 bytes + // Hash in Data 32 bytes + // OriginalSquareSize in Data 8 bytes + MaxOverheadForBlock int64 = 56 ) // Block defines the atomic unit of a Tendermint blockchain. diff --git a/types/block_test.go b/types/block_test.go index c5fbcd510d..c1d9d9c227 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -459,11 +459,11 @@ func TestBlockMaxDataBytes(t *testing.T) { }{ 0: {-10, 1, 0, true, 0}, 1: {10, 1, 0, true, 0}, - 2: {841, 1, 0, true, 0}, - 3: {842, 1, 0, false, 0}, - 4: {843, 1, 0, false, 1}, - 5: {954, 2, 0, false, 1}, - 6: {1053, 2, 100, false, 0}, + 2: {886, 1, 0, true, 0}, + 3: {887, 1, 0, false, 0}, + 4: {888, 1, 0, false, 1}, + 5: {999, 2, 0, false, 1}, + 6: {1098, 2, 100, false, 0}, } for i, tc := range testCases { @@ -490,9 +490,9 @@ func TestBlockMaxDataBytesNoEvidence(t *testing.T) { }{ 0: {-10, 1, true, 0}, 1: {10, 1, true, 0}, - 2: {841, 1, true, 0}, - 3: {842, 1, false, 0}, - 4: {843, 1, false, 1}, + 2: {886, 1, true, 0}, + 3: {887, 1, false, 0}, + 4: {888, 1, false, 1}, } for i, tc := range testCases { diff --git a/types/event_bus.go b/types/event_bus.go index dfe3a06644..5ac434d584 100644 --- a/types/event_bus.go +++ b/types/event_bus.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/libs/log" tmpubsub "github.com/tendermint/tendermint/libs/pubsub" "github.com/tendermint/tendermint/libs/service" @@ -172,13 +173,20 @@ func (b *EventBus) PublishEventTx(data EventDataTx) error { // add Tendermint-reserved events events = append(events, EventTx) + var txHash []byte + if len(data.OriginalHash) == tmhash.Size { + txHash = data.OriginalHash + } else { + txHash = Tx(data.Tx).Hash() + } + tokens := strings.Split(TxHashKey, ".") events = append(events, types.Event{ Type: tokens[0], Attributes: []types.EventAttribute{ { Key: tokens[1], - Value: fmt.Sprintf("%X", Tx(data.Tx).Hash()), + Value: fmt.Sprintf("%X", txHash), }, }, }) diff --git a/types/event_bus_test.go b/types/event_bus_test.go index 27c2e6f22f..56a5d035a7 100644 --- a/types/event_bus_test.go +++ b/types/event_bus_test.go @@ -64,6 +64,58 @@ func TestEventBusPublishEventTx(t *testing.T) { } } +func TestEventBusPublishEventMalleatedTx(t *testing.T) { + eventBus := NewEventBus() + err := eventBus.Start() + require.NoError(t, err) + t.Cleanup(func() { + if err := eventBus.Stop(); err != nil { + t.Error(err) + } + }) + + tx := Tx("foo") + malleatedTx := Tx("foo-malleated") + + result := abci.ResponseDeliverTx{ + Data: []byte("bar"), + Events: []abci.Event{ + {Type: "testType", Attributes: []abci.EventAttribute{{Key: "baz", Value: "1"}}}, + }, + } + + // PublishEventTx adds 3 composite keys, so the query below should work + query := fmt.Sprintf("tm.event='Tx' AND tx.height=1 AND tx.hash='%X' AND testType.baz=1", tx.Hash()) + txsSub, err := eventBus.Subscribe(context.Background(), "test", tmquery.MustCompile(query)) + require.NoError(t, err) + + done := make(chan struct{}) + go func() { + msg := <-txsSub.Out() + edt := msg.Data().(EventDataTx) + assert.Equal(t, int64(1), edt.Height) + assert.Equal(t, uint32(0), edt.Index) + assert.EqualValues(t, malleatedTx, edt.Tx) + assert.Equal(t, result, edt.Result) + close(done) + }() + + err = eventBus.PublishEventTx(EventDataTx{abci.TxResult{ + Height: 1, + Index: 0, + Tx: malleatedTx, + Result: result, + OriginalHash: tx.Hash(), + }}) + assert.NoError(t, err) + + select { + case <-done: + case <-time.After(1 * time.Second): + t.Fatal("did not receive a transaction after 1 sec.") + } +} + func TestEventBusPublishEventNewBlock(t *testing.T) { eventBus := NewEventBus() err := eventBus.Start() diff --git a/types/tx.go b/types/tx.go index b507351c7e..d730ff1297 100644 --- a/types/tx.go +++ b/types/tx.go @@ -176,28 +176,39 @@ func ToTxs(txs [][]byte) Txs { return txBzs } -// DecodeChildTx attempts to unmarshal the provided transaction into a child -// transaction wrapper, if this an be done, then it returns true. A child -// transaction is a normal transaction that has been derived from a different -// parent transaction. The returned hash is that of the parent transaction, -// which allows us to remove the parent transaction from the mempool -func DecodeChildTx(tx Tx) (hash []byte, unwrapped Tx, has bool) { - // attempt to unmarshal into a a child transaction - var childTx tmproto.ChildTx - err := proto.Unmarshal(tx, &childTx) +// UnwrapMalleatedTx attempts to unmarshal the provided transaction into a malleated +// transaction wrapper, if this an be done, then it returns true. A malleated +// transaction is a normal transaction that has been derived (malleated) from a +// different original transaction. The returned hash is that of the original +// transaction, which allows us to remove the original transaction from the +// mempool. NOTE: protobuf sometimes does not throw an error if the transaction +// passed is not a tmproto.MalleatedTx, since the schema for PayForMessage is kept +// in the app, we cannot perform further checks without creating an import +// cycle. +func UnwrapMalleatedTx(tx Tx) (originalHash []byte, unwrapped Tx, isMalleated bool) { + // attempt to unmarshal into a a malleated transaction + var malleatedTx tmproto.MalleatedTx + err := proto.Unmarshal(tx, &malleatedTx) if err != nil { return nil, nil, false } - return childTx.ParentTxHash, childTx.Tx, true + // this check will fail to catch unwanted types should those unmarshalled + // types happen to have a hash sized slice of bytes in the same field number + // as originalTxHash. TODO(evan): either fix this, or better yet use a different + // mechanism + if len(malleatedTx.OriginalTxHash) != tmhash.Size { + return nil, nil, false + } + return malleatedTx.OriginalTxHash, malleatedTx.Tx, true } -// WrapChildTx creates a wrapped Tx that includes the parent transaction's hash +// WrapMalleatedTx creates a wrapped Tx that includes the original transaction's hash // so that it can be easily removed from the mempool. note: must be unwrapped to // be a viable sdk.Tx -func WrapChildTx(parentHash []byte, child Tx) (Tx, error) { - wTx := tmproto.ChildTx{ - ParentTxHash: parentHash, - Tx: child, +func WrapMalleatedTx(originalHash []byte, malleated Tx) (Tx, error) { + wTx := tmproto.MalleatedTx{ + OriginalTxHash: originalHash, + Tx: malleated, } return proto.Marshal(&wTx) } From 03e9219c7a7a51a6b64e0ba64dda423912916642 Mon Sep 17 00:00:00 2001 From: John Adler Date: Tue, 12 Apr 2022 16:19:23 +0200 Subject: [PATCH 12/31] Fix super linter CI (#713) * Fix super linter CI * Update linter.yml * Port linter fix from #608 * Add missed ADRs * fix typo --- .github/workflows/linter.yml | 6 +- docs/architecture/README.md | 113 +++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 docs/architecture/README.md diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index ec560069df..b7c2b5a009 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -12,6 +12,7 @@ on: paths: - "**.md" - "**.yml" + - "**.yaml" jobs: build: @@ -20,11 +21,14 @@ jobs: steps: - name: Checkout Code uses: actions/checkout@v3 + with: + # Full git history is needed to get a proper list of changed files within `super-linter` + fetch-depth: 0 - name: Lint Code Base uses: docker://github/super-linter:v4 env: VALIDATE_ALL_CODEBASE: true - DEFAULT_BRANCH: master + DEFAULT_BRANCH: v0.34.x-celestia GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VALIDATE_MD: true VALIDATE_OPENAPI: true diff --git a/docs/architecture/README.md b/docs/architecture/README.md new file mode 100644 index 0000000000..e6c9c0a06e --- /dev/null +++ b/docs/architecture/README.md @@ -0,0 +1,113 @@ +--- +order: 1 +parent: + order: false +--- + +# Architecture Decision Records (ADR) + +This is a location to record all high-level architecture decisions in the tendermint project. + +You can read more about the ADR concept in this [blog post](https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t). + +An ADR should provide: + +- Context on the relevant goals and the current state +- Proposed changes to achieve the goals +- Summary of pros and cons +- References +- Changelog + +Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something +new. The spec is much more compressed and streamlined summary of everything as +it stands today. + +If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match. + +Note the context/background should be written in the present tense. + +## Table of Contents + +### Implemented + +- [ADR-001: Logging](./adr-001-logging.md) +- [ADR-002: Event-Subscription](./adr-002-event-subscription.md) +- [ADR-003: ABCI-APP-RPC](./adr-003-abci-app-rpc.md) +- [ADR-004: Historical-Validators](./adr-004-historical-validators.md) +- [ADR-005: Consensus-Params](./adr-005-consensus-params.md) +- [ADR-008: Priv-Validator](./adr-008-priv-validator.md) +- [ADR-009: ABCI-Design](./adr-009-ABCI-design.md) +- [ADR-010: Crypto-Changes](./adr-010-crypto-changes.md) +- [ADR-011: Monitoring](./adr-011-monitoring.md) +- [ADR-014: Secp-Malleability](./adr-014-secp-malleability.md) +- [ADR-015: Crypto-Encoding](./adr-015-crypto-encoding.md) +- [ADR-016: Protocol-Versions](./adr-016-protocol-versions.md) +- [ADR-017: Chain-Versions](./adr-017-chain-versions.md) +- [ADR-018: ABCI-Validators](./adr-018-ABCI-Validators.md) +- [ADR-019: Multisigs](./adr-019-multisigs.md) +- [ADR-020: Block-Size](./adr-020-block-size.md) +- [ADR-021: ABCI-Events](./adr-021-abci-events.md) +- [ADR-025: Commit](./adr-025-commit.md) +- [ADR-026: General-Merkle-Proof](./adr-026-general-merkle-proof.md) +- [ADR-033: Pubsub](./adr-033-pubsub.md) +- [ADR-034: Priv-Validator-File-Structure](./adr-034-priv-validator-file-structure.md) +- [ADR-043: Blockchain-RiRi-Org](./adr-043-blockchain-riri-org.md) +- [ADR-044: Lite-Client-With-Weak-Subjectivity](./adr-044-lite-client-with-weak-subjectivity.md) +- [ADR-046: Light-Client-Implementation](./adr-046-light-client-implementation.md) +- [ADR-047: Handling-Evidence-From-Light-Client](./adr-047-handling-evidence-from-light-client.md) +- [ADR-051: Double-Signing-Risk-Reduction](./adr-051-double-signing-risk-reduction.md) +- [ADR-052: Tendermint-Mode](./adr-052-tendermint-mode.md) +- [ADR-053: State-Sync-Prototype](./adr-053-state-sync-prototype.md) +- [ADR-054: Crypto-Encoding-2](./adr-054-crypto-encoding-2.md) +- [ADR-055: Protobuf-Design](./adr-055-protobuf-design.md) +- [ADR-056: Light-Client-Amnesia-Attacks](./adr-056-light-client-amnesia-attacks.md) +- [ADR-059: Evidence-Composition-and-Lifecycle](./adr-059-evidence-composition-and-lifecycle.md) +- [ADR-062: P2P-Architecture](./adr-062-p2p-architecture.md) +- [ADR-063: Privval-gRPC](./adr-063-privval-grpc.md) +- [ADR-064: Batch-Verification](./adr-064-batch-verification.md) +- [ADR-066-E2E-Testing](./adr-066-e2e-testing.md) + +### Accepted + +- [ADR-006: Trust-Metric](./adr-006-trust-metric.md) +- [ADR-024: Sign-Bytes](./adr-024-sign-bytes.md) +- [ADR-035: Documentation](./adr-035-documentation.md) +- [ADR-039: Peer-Behaviour](./adr-039-peer-behaviour.md) +- [ADR-060: Go-API-Stability](./adr-060-go-api-stability.md) +- [ADR-061: P2P-Refactor-Scope](./adr-061-p2p-refactor-scope.md) +- [ADR-065: Custom Event Indexing](./adr-065-custom-event-indexing.md) +- [ADR-068: Reverse-Sync](./adr-068-reverse-sync.md) +- [ADR-067: Mempool Refactor](./adr-067-mempool-refactor.md) + +### Rejected + +- [ADR-023: ABCI-Propose-tx](./adr-023-ABCI-propose-tx.md) +- [ADR-029: Check-Tx-Consensus](./adr-029-check-tx-consensus.md) +- [ADR-058: Event-Hashing](./adr-058-event-hashing.md) + + +### Proposed + +- [ADR-007: Trust-Metric-Usage](./adr-007-trust-metric-usage.md) +- [ADR-012: Peer-Transport](./adr-012-peer-transport.md) +- [ADR-013: Symmetric-Crypto](./adr-013-symmetric-crypto.md) +- [ADR-022: ABCI-Errors](./adr-022-abci-errors.md) +- [ADR-030: Consensus-Refactor](./adr-030-consensus-refactor.md) +- [ADR-037: Deliver-Block](./adr-037-deliver-block.md) +- [ADR-038: Non-Zero-Start-Height](./adr-038-non-zero-start-height.md) +- [ADR-041: Proposer-Selection-via-ABCI](./adr-041-proposer-selection-via-abci.md) +- [ADR-042: State-Sync](./adr-042-state-sync.md) +- [ADR-045: ABCI-Evidence](./adr-045-abci-evidence.md) +- [ADR-050: Improved-Trusted-Peering](./adr-050-improved-trusted-peering.md) +- [ADR 056: Proving amnesia attacks](./adr-056-proving-amnesia-attacks.md) +- [ADR-057: RPC](./adr-057-RPC.md) +- [ADR-069: Flexible-Node-Initialization](./adr-069-flexible-node-intitalization.md) +- [ADR-071: Proposer-Based-Timestamps](./adr-071-proposer-based-timestamps.md) +- [ADR-072: Restore Requests for Comments](./adr-072-request-for-comments.md) + +### Draft +- [ADR 028: LibP2P Integration](./adr-028-libp2p.md) +- [ADR 031: Changelog Structure](./adr-031-changelog.md) +- [ADR-036: Empty-Blocks-ABCI](./adr-036-empty-blocks-abci.md) +- [ADR-040: Blockchain-Reactor-Refactor](./adr-040-blockchain-reactor-refactor.md) From b8a792020da79f444536b496fa767d5d2586b5e4 Mon Sep 17 00:00:00 2001 From: John Adler Date: Mon, 11 Apr 2022 12:32:48 +0200 Subject: [PATCH 13/31] Fix codeowners (#699) * Use codeowners from master. * Remove reviewers for dependabot prs. --- .github/CODEOWNERS | 5 ++++- .github/dependabot.yml | 3 --- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b48354f014..286370b90f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,4 +7,7 @@ # global owners are only requested if there isn't a more specific # codeowner specified below. For this reason, the global codeowners # are often repeated in package-level definitions. -* @ebuchman @cmwaters @tychoish @williambanfield @creachadair +* @liamsi @evan-forbes @Wondertan + +# Overrides for tooling packages +docs/ @liamsi @adlerjohn diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b6729552d2..22036cf683 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -20,8 +20,5 @@ updates: interval: daily time: "11:00" open-pull-requests-limit: 10 - reviewers: - - melekes - - tessr labels: - T:dependencies From 01051aa5fef0693bf3bda801e39c80e5746b9c33 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Thu, 28 Apr 2022 17:45:34 -0500 Subject: [PATCH 14/31] Create nmt inclusion proofs for transactions in a given block (#615) * add ability to create nmt proofs by progressively generating the square * rename var to be more specific * fix file name change * core logic and testing * export needed function * export needed function * generate nmtProof proto files * update remaining tests * update proto files * update test to use new format for verifying proofs * make tx proofs more ergonomic and handle multiple proofs * integrate into rpc core * cache original square size * move proving logic to pkg * add original square size * change name of function to TxInclusion * typo * linter * better docs Co-authored-by: John Adler * use passed codec arg instead of using the default Co-authored-by: John Adler * use already existing constant * return error for txSharePosition * bubble error instead of panicking * use uint cause it's the right thing to do even tho go fights you * include the lengths of bytes in the nmt proofs * use passed codec Co-authored-by: John Adler * add comment to better explain division * linter Co-authored-by: John Adler --- internal/rpc/core/tx.go | 29 +- light/rpc/client.go | 9 +- pkg/prove/proof.go | 187 ++++++ pkg/prove/proof_test.go | 237 ++++++++ proto/gogoproto/gogo.pb.go | 888 +++++++++++++++++++++++++++++ proto/tendermint/types/types.pb.go | 644 +++++++++++++++------ proto/tendermint/types/types.proto | 28 +- rpc/client/rpc_test.go | 9 +- types/block.go | 2 +- types/tx.go | 107 ++-- types/tx_test.go | 103 ---- 11 files changed, 1910 insertions(+), 333 deletions(-) create mode 100644 pkg/prove/proof.go create mode 100644 pkg/prove/proof_test.go create mode 100644 proto/gogoproto/gogo.pb.go diff --git a/internal/rpc/core/tx.go b/internal/rpc/core/tx.go index 7ba2bf90c0..7e6d0ec1cf 100644 --- a/internal/rpc/core/tx.go +++ b/internal/rpc/core/tx.go @@ -9,6 +9,8 @@ import ( "github.com/tendermint/tendermint/libs/bytes" tmmath "github.com/tendermint/tendermint/libs/math" tmquery "github.com/tendermint/tendermint/libs/pubsub/query" + "github.com/tendermint/tendermint/pkg/consts" + "github.com/tendermint/tendermint/pkg/prove" "github.com/tendermint/tendermint/rpc/coretypes" rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" "github.com/tendermint/tendermint/types" @@ -18,7 +20,7 @@ import ( // transaction is in the mempool, invalidated, or was not sent in the first // place. // More: https://docs.tendermint.com/master/rpc/#/Info/tx -func (env *Environment) Tx(ctx *rpctypes.Context, hash bytes.HexBytes, prove bool) (*coretypes.ResultTx, error) { +func (env *Environment) Tx(ctx *rpctypes.Context, hash bytes.HexBytes, proveTx bool) (*coretypes.ResultTx, error) { // if index is disabled, return error // N.B. The hash parameter is HexBytes so that the reflective parameter @@ -39,10 +41,18 @@ func (env *Environment) Tx(ctx *rpctypes.Context, hash bytes.HexBytes, prove boo height := r.Height index := r.Index - var proof types.TxProof - if prove { + var txProof types.TxProof + if proveTx { block := env.BlockStore.LoadBlock(height) - proof = block.Data.Txs.Proof(int(index)) // XXX: overflow on 32-bit machines + txProof, err = prove.TxInclusion( + consts.DefaultCodec(), + block.Data, + uint(block.Data.OriginalSquareSize), + uint(r.Index), + ) + if err != nil { + return nil, err + } } return &coretypes.ResultTx{ @@ -51,7 +61,7 @@ func (env *Environment) Tx(ctx *rpctypes.Context, hash bytes.HexBytes, prove boo Index: index, TxResult: r.Result, Tx: r.Tx, - Proof: proof, + Proof: txProof, }, nil } } @@ -65,7 +75,7 @@ func (env *Environment) Tx(ctx *rpctypes.Context, hash bytes.HexBytes, prove boo func (env *Environment) TxSearch( ctx *rpctypes.Context, query string, - prove bool, + proveTx bool, pagePtr, perPagePtr *int, orderBy string, ) (*coretypes.ResultTxSearch, error) { @@ -125,9 +135,12 @@ func (env *Environment) TxSearch( r := results[i] var proof types.TxProof - if prove { + if proveTx { block := env.BlockStore.LoadBlock(r.Height) - proof = block.Data.Txs.Proof(int(r.Index)) // XXX: overflow on 32-bit machines + proof, err = prove.TxInclusion(consts.DefaultCodec(), block.Data, uint(block.Data.OriginalSquareSize), uint(r.Index)) + if err != nil { + return nil, err + } } apiResults = append(apiResults, &coretypes.ResultTx{ diff --git a/light/rpc/client.go b/light/rpc/client.go index 1852297c73..7bcc093e61 100644 --- a/light/rpc/client.go +++ b/light/rpc/client.go @@ -517,13 +517,18 @@ func (c *Client) Tx(ctx context.Context, hash tmbytes.HexBytes, prove bool) (*co } // Update the light client if we're behind. - l, err := c.updateLightClientIfNeededTo(ctx, &res.Height) + _, err = c.updateLightClientIfNeededTo(ctx, &res.Height) if err != nil { return nil, err } + valid := res.Proof.VerifyProof() + if !valid { + err = errors.New("proof for transaction inclusion could not be verified") + } + // Validate the proof. - return res, res.Proof.Validate(l.DataHash) + return res, err } func (c *Client) TxSearch( diff --git a/pkg/prove/proof.go b/pkg/prove/proof.go new file mode 100644 index 0000000000..7e358ed9a7 --- /dev/null +++ b/pkg/prove/proof.go @@ -0,0 +1,187 @@ +package prove + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/celestiaorg/rsmt2d" + tmbytes "github.com/tendermint/tendermint/libs/bytes" + "github.com/tendermint/tendermint/pkg/consts" + "github.com/tendermint/tendermint/pkg/wrapper" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + "github.com/tendermint/tendermint/types" +) + +// TxInclusion uses the provided block data to progressively generate rows +// of a data square, and then using those shares to creates nmt inclusion proofs +// It is possible that a transaction spans more than one row. In that case, we +// have to return two proofs. +func TxInclusion(codec rsmt2d.Codec, data types.Data, origSquareSize, txIndex uint) (types.TxProof, error) { + // calculate the index of the shares that contain the tx + startPos, endPos, err := txSharePosition(data.Txs, txIndex) + if err != nil { + return types.TxProof{}, err + } + if (endPos - startPos) > 1 { + return types.TxProof{}, errors.New("transaction spanned more than two shares, this is not yet supported") + } + + // use the index of the shares and the square size to determine the row that + // contains the tx we need to prove + startRow := startPos / origSquareSize + endRow := endPos / origSquareSize + + rowShares, err := genRowShares(codec, data, origSquareSize, startRow, endRow) + if err != nil { + return types.TxProof{}, err + } + + var proofs []*tmproto.NMTProof //nolint:prealloc // rarely will this contain more than a single proof + var shares [][]byte //nolint:prealloc // rarely will this contain more than a single share + var rowRoots []tmbytes.HexBytes //nolint:prealloc // rarely will this contain more than a single root + for i, row := range rowShares { + // create an nmt to use to generate a proof + tree := wrapper.NewErasuredNamespacedMerkleTree(uint64(origSquareSize)) + for j, share := range row { + tree.Push( + share, + rsmt2d.SquareIndex{ + Axis: uint(i), + Cell: uint(j), + }, + ) + } + + var pos uint + if i == 0 { + pos = startPos - (startRow * origSquareSize) + } else { + pos = endPos - (endRow * origSquareSize) + } + + shares = append(shares, row[pos]) + + proof, err := tree.Prove(int(pos)) + if err != nil { + return types.TxProof{}, err + } + + proofs = append(proofs, &tmproto.NMTProof{ + Start: int32(proof.Start()), + End: int32(proof.End()), + Nodes: proof.Nodes(), + LeafHash: proof.LeafHash(), + }) + + // we don't store the data availability header anywhere, so we + // regenerate the roots to each row + rowRoots = append(rowRoots, tree.Root()) + } + + return types.TxProof{ + RowRoots: rowRoots, + Data: shares, + Proofs: proofs, + }, nil +} + +// txSharePosition returns the share that a given transaction is included in. +// returns -1 if index is greater than that of the provided txs. +func txSharePosition(txs types.Txs, txIndex uint) (startSharePos, endSharePos uint, err error) { + if txIndex >= uint(len(txs)) { + return startSharePos, endSharePos, errors.New("transaction index is greater than the number of txs") + } + + totalLen := 0 + for i := uint(0); i < txIndex; i++ { + txLen := len(txs[i]) + totalLen += (delimLen(txLen) + txLen) + } + + txLen := len(txs[txIndex]) + + startSharePos = uint((totalLen) / consts.TxShareSize) + endSharePos = uint((totalLen + txLen + delimLen(txLen)) / consts.TxShareSize) + + return startSharePos, endSharePos, nil +} + +func delimLen(txLen int) int { + lenBuf := make([]byte, binary.MaxVarintLen64) + return binary.PutUvarint(lenBuf, uint64(txLen)) +} + +// genRowShares progessively generates data square rows from block data +func genRowShares(codec rsmt2d.Codec, data types.Data, origSquareSize, startRow, endRow uint) ([][][]byte, error) { + if endRow > origSquareSize { + return nil, errors.New("cannot generate row shares past the original square size") + } + origRowShares := splitIntoRows( + origSquareSize, + genOrigRowShares(data, origSquareSize, startRow, endRow), + ) + + encodedRowShares := make([][][]byte, len(origRowShares)) + for i, row := range origRowShares { + encRow, err := codec.Encode(row) + if err != nil { + panic(err) + } + encodedRowShares[i] = append( + append( + make([][]byte, 0, len(row)+len(encRow)), + row..., + ), encRow..., + ) + } + + return encodedRowShares, nil +} + +// genOrigRowShares progressively generates data square rows for the original +// data square, meaning the rows only half the full square length, as there is +// not erasure data +func genOrigRowShares(data types.Data, originalSquareSize, startRow, endRow uint) [][]byte { + wantLen := (endRow + 1) * originalSquareSize + startPos := startRow * originalSquareSize + + shares := data.Txs.SplitIntoShares() + // return if we have enough shares + if uint(len(shares)) >= wantLen { + return shares[startPos:wantLen].RawShares() + } + + shares = append(shares, data.Evidence.SplitIntoShares()...) + if uint(len(shares)) >= wantLen { + return shares[startPos:wantLen].RawShares() + } + + for _, m := range data.Messages.MessagesList { + rawData, err := m.MarshalDelimited() + if err != nil { + panic(fmt.Sprintf("app accepted a Message that can not be encoded %#v", m)) + } + shares = types.AppendToShares(shares, m.NamespaceID, rawData) + + // return if we have enough shares + if uint(len(shares)) >= wantLen { + return shares[startPos:wantLen].RawShares() + } + } + + tailShares := types.TailPaddingShares(int(wantLen) - len(shares)) + shares = append(shares, tailShares...) + + return shares[startPos:wantLen].RawShares() +} + +// splitIntoRows splits shares into rows of a particular square size +func splitIntoRows(origSquareSize uint, shares [][]byte) [][][]byte { + rowCount := uint(len(shares)) / origSquareSize + rows := make([][][]byte, rowCount) + for i := uint(0); i < rowCount; i++ { + rows[i] = shares[i*origSquareSize : (i+1)*origSquareSize] + } + return rows +} diff --git a/pkg/prove/proof_test.go b/pkg/prove/proof_test.go new file mode 100644 index 0000000000..87eb87bd91 --- /dev/null +++ b/pkg/prove/proof_test.go @@ -0,0 +1,237 @@ +package prove + +import ( + "bytes" + "fmt" + "math" + "math/rand" + "sort" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/pkg/consts" + "github.com/tendermint/tendermint/pkg/da" + "github.com/tendermint/tendermint/types" +) + +func TestTxInclusion(t *testing.T) { + txCount := 100 + typicalBlockData := types.Data{ + Txs: generateRandomlySizedContiguousShares(txCount, 200), + Messages: generateRandomlySizedMessages(10, 150), + } + + // compute the data availability header + shares, _ := typicalBlockData.ComputeShares() + + squareSize := uint(math.Sqrt(float64(len(shares)))) + + for i := 0; i < txCount; i++ { + txProof, err := TxInclusion(consts.DefaultCodec(), typicalBlockData, squareSize, uint(i)) + require.NoError(t, err) + assert.True(t, txProof.VerifyProof()) + } +} + +func TestTxSharePosition(t *testing.T) { + type test struct { + name string + txs types.Txs + } + + tests := []test{ + { + name: "typical", + txs: generateRandomlySizedContiguousShares(44, 200), + }, + { + name: "many small tx", + txs: generateRandomlySizedContiguousShares(444, 100), + }, + { + name: "one small tx", + txs: generateRandomlySizedContiguousShares(1, 200), + }, + { + name: "one large tx", + txs: generateRandomlySizedContiguousShares(1, 2000), + }, + { + name: "many large txs", + txs: generateRandomlySizedContiguousShares(100, 2000), + }, + } + + type startEndPoints struct { + start, end uint + } + + for _, tt := range tests { + positions := make([]startEndPoints, len(tt.txs)) + for i := 0; i < len(tt.txs); i++ { + start, end, err := txSharePosition(tt.txs, uint(i)) + require.NoError(t, err) + positions[i] = startEndPoints{start: start, end: end} + } + + shares := tt.txs.SplitIntoShares().RawShares() + + for i, pos := range positions { + if pos.start == pos.end { + assert.Contains(t, string(shares[pos.start]), string(tt.txs[i]), tt.name, i, pos) + } else { + assert.Contains( + t, + joinByteSlices(shares[pos.start:pos.end+1]...), + string(tt.txs[i]), + tt.name, + pos, + len(tt.txs[i]), + ) + } + } + } +} + +func Test_genRowShares(t *testing.T) { + typicalBlockData := types.Data{ + Txs: generateRandomlySizedContiguousShares(120, 200), + Messages: generateRandomlySizedMessages(10, 1000), + } + + allShares, _ := typicalBlockData.ComputeShares() + rawShares := allShares.RawShares() + + originalSquareSize := uint(math.Sqrt(float64(len(rawShares)))) + + eds, err := da.ExtendShares(uint64(originalSquareSize), rawShares) + require.NoError(t, err) + + eds.ColRoots() + + rowShares, err := genRowShares( + consts.DefaultCodec(), + typicalBlockData, + originalSquareSize, + 0, + originalSquareSize-1, + ) + require.NoError(t, err) + + for i := uint(0); i < originalSquareSize; i++ { + row := eds.Row(i) + assert.Equal(t, row, rowShares[i], fmt.Sprintf("row %d", i)) + // also test fetching individual rows + secondSet, err := genRowShares(consts.DefaultCodec(), typicalBlockData, originalSquareSize, i, i) + require.NoError(t, err) + assert.Equal(t, row, secondSet[0], fmt.Sprintf("row %d", i)) + } +} + +func Test_genOrigRowShares(t *testing.T) { + txCount := 100 + typicalBlockData := types.Data{ + Txs: generateRandomlySizedContiguousShares(txCount, 200), + Messages: generateRandomlySizedMessages(10, 1500), + } + + allShares, _ := typicalBlockData.ComputeShares() + rawShares := allShares.RawShares() + + genShares := genOrigRowShares(typicalBlockData, 8, 0, 7) + + require.Equal(t, len(allShares), len(genShares)) + assert.Equal(t, rawShares, genShares) +} + +func joinByteSlices(s ...[]byte) string { + out := make([]string, len(s)) + for i, sl := range s { + sl, _, _ := types.ParseDelimiter(sl) + out[i] = string(sl[consts.NamespaceSize:]) + } + return strings.Join(out, "") +} + +func generateRandomlySizedContiguousShares(count, max int) types.Txs { + txs := make(types.Txs, count) + for i := 0; i < count; i++ { + size := rand.Intn(max) + if size == 0 { + size = 1 + } + txs[i] = generateRandomContiguousShares(1, size)[0] + } + return txs +} + +func generateRandomContiguousShares(count, size int) types.Txs { + txs := make(types.Txs, count) + for i := 0; i < count; i++ { + tx := make([]byte, size) + _, err := rand.Read(tx) + if err != nil { + panic(err) + } + txs[i] = tx + } + return txs +} + +func generateRandomlySizedMessages(count, maxMsgSize int) types.Messages { + msgs := make([]types.Message, count) + for i := 0; i < count; i++ { + msgs[i] = generateRandomMessage(rand.Intn(maxMsgSize)) + } + + // this is just to let us use assert.Equal + if count == 0 { + msgs = nil + } + + return types.Messages{MessagesList: msgs} +} + +func generateRandomMessage(size int) types.Message { + share := generateRandomNamespacedShares(1, size)[0] + msg := types.Message{ + NamespaceID: share.NamespaceID(), + Data: share.Data(), + } + return msg +} + +func generateRandomNamespacedShares(count, msgSize int) types.NamespacedShares { + shares := generateRandNamespacedRawData(uint32(count), consts.NamespaceSize, uint32(msgSize)) + msgs := make([]types.Message, count) + for i, s := range shares { + msgs[i] = types.Message{ + Data: s[consts.NamespaceSize:], + NamespaceID: s[:consts.NamespaceSize], + } + } + return types.Messages{MessagesList: msgs}.SplitIntoShares() +} + +func generateRandNamespacedRawData(total, nidSize, leafSize uint32) [][]byte { + data := make([][]byte, total) + for i := uint32(0); i < total; i++ { + nid := make([]byte, nidSize) + rand.Read(nid) + data[i] = nid + } + sortByteArrays(data) + for i := uint32(0); i < total; i++ { + d := make([]byte, leafSize) + rand.Read(d) + data[i] = append(data[i], d...) + } + + return data +} + +func sortByteArrays(src [][]byte) { + sort.Slice(src, func(i, j int) bool { return bytes.Compare(src[i], src[j]) < 0 }) +} diff --git a/proto/gogoproto/gogo.pb.go b/proto/gogoproto/gogo.pb.go new file mode 100644 index 0000000000..9a76ba844c --- /dev/null +++ b/proto/gogoproto/gogo.pb.go @@ -0,0 +1,888 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: gogoproto/gogo.proto + +package gogoproto + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + descriptorpb "google.golang.org/protobuf/types/descriptorpb" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +var E_GoprotoEnumPrefix = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.EnumOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 62001, + Name: "gogoproto.goproto_enum_prefix", + Tag: "varint,62001,opt,name=goproto_enum_prefix", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoEnumStringer = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.EnumOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 62021, + Name: "gogoproto.goproto_enum_stringer", + Tag: "varint,62021,opt,name=goproto_enum_stringer", + Filename: "gogoproto/gogo.proto", +} + +var E_EnumStringer = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.EnumOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 62022, + Name: "gogoproto.enum_stringer", + Tag: "varint,62022,opt,name=enum_stringer", + Filename: "gogoproto/gogo.proto", +} + +var E_EnumCustomname = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.EnumOptions)(nil), + ExtensionType: (*string)(nil), + Field: 62023, + Name: "gogoproto.enum_customname", + Tag: "bytes,62023,opt,name=enum_customname", + Filename: "gogoproto/gogo.proto", +} + +var E_Enumdecl = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.EnumOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 62024, + Name: "gogoproto.enumdecl", + Tag: "varint,62024,opt,name=enumdecl", + Filename: "gogoproto/gogo.proto", +} + +var E_EnumvalueCustomname = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.EnumValueOptions)(nil), + ExtensionType: (*string)(nil), + Field: 66001, + Name: "gogoproto.enumvalue_customname", + Tag: "bytes,66001,opt,name=enumvalue_customname", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoGettersAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63001, + Name: "gogoproto.goproto_getters_all", + Tag: "varint,63001,opt,name=goproto_getters_all", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoEnumPrefixAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63002, + Name: "gogoproto.goproto_enum_prefix_all", + Tag: "varint,63002,opt,name=goproto_enum_prefix_all", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoStringerAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63003, + Name: "gogoproto.goproto_stringer_all", + Tag: "varint,63003,opt,name=goproto_stringer_all", + Filename: "gogoproto/gogo.proto", +} + +var E_VerboseEqualAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63004, + Name: "gogoproto.verbose_equal_all", + Tag: "varint,63004,opt,name=verbose_equal_all", + Filename: "gogoproto/gogo.proto", +} + +var E_FaceAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63005, + Name: "gogoproto.face_all", + Tag: "varint,63005,opt,name=face_all", + Filename: "gogoproto/gogo.proto", +} + +var E_GostringAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63006, + Name: "gogoproto.gostring_all", + Tag: "varint,63006,opt,name=gostring_all", + Filename: "gogoproto/gogo.proto", +} + +var E_PopulateAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63007, + Name: "gogoproto.populate_all", + Tag: "varint,63007,opt,name=populate_all", + Filename: "gogoproto/gogo.proto", +} + +var E_StringerAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63008, + Name: "gogoproto.stringer_all", + Tag: "varint,63008,opt,name=stringer_all", + Filename: "gogoproto/gogo.proto", +} + +var E_OnlyoneAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63009, + Name: "gogoproto.onlyone_all", + Tag: "varint,63009,opt,name=onlyone_all", + Filename: "gogoproto/gogo.proto", +} + +var E_EqualAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63013, + Name: "gogoproto.equal_all", + Tag: "varint,63013,opt,name=equal_all", + Filename: "gogoproto/gogo.proto", +} + +var E_DescriptionAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63014, + Name: "gogoproto.description_all", + Tag: "varint,63014,opt,name=description_all", + Filename: "gogoproto/gogo.proto", +} + +var E_TestgenAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63015, + Name: "gogoproto.testgen_all", + Tag: "varint,63015,opt,name=testgen_all", + Filename: "gogoproto/gogo.proto", +} + +var E_BenchgenAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63016, + Name: "gogoproto.benchgen_all", + Tag: "varint,63016,opt,name=benchgen_all", + Filename: "gogoproto/gogo.proto", +} + +var E_MarshalerAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63017, + Name: "gogoproto.marshaler_all", + Tag: "varint,63017,opt,name=marshaler_all", + Filename: "gogoproto/gogo.proto", +} + +var E_UnmarshalerAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63018, + Name: "gogoproto.unmarshaler_all", + Tag: "varint,63018,opt,name=unmarshaler_all", + Filename: "gogoproto/gogo.proto", +} + +var E_StableMarshalerAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63019, + Name: "gogoproto.stable_marshaler_all", + Tag: "varint,63019,opt,name=stable_marshaler_all", + Filename: "gogoproto/gogo.proto", +} + +var E_SizerAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63020, + Name: "gogoproto.sizer_all", + Tag: "varint,63020,opt,name=sizer_all", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoEnumStringerAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63021, + Name: "gogoproto.goproto_enum_stringer_all", + Tag: "varint,63021,opt,name=goproto_enum_stringer_all", + Filename: "gogoproto/gogo.proto", +} + +var E_EnumStringerAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63022, + Name: "gogoproto.enum_stringer_all", + Tag: "varint,63022,opt,name=enum_stringer_all", + Filename: "gogoproto/gogo.proto", +} + +var E_UnsafeMarshalerAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63023, + Name: "gogoproto.unsafe_marshaler_all", + Tag: "varint,63023,opt,name=unsafe_marshaler_all", + Filename: "gogoproto/gogo.proto", +} + +var E_UnsafeUnmarshalerAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63024, + Name: "gogoproto.unsafe_unmarshaler_all", + Tag: "varint,63024,opt,name=unsafe_unmarshaler_all", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoExtensionsMapAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63025, + Name: "gogoproto.goproto_extensions_map_all", + Tag: "varint,63025,opt,name=goproto_extensions_map_all", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoUnrecognizedAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63026, + Name: "gogoproto.goproto_unrecognized_all", + Tag: "varint,63026,opt,name=goproto_unrecognized_all", + Filename: "gogoproto/gogo.proto", +} + +var E_GogoprotoImport = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63027, + Name: "gogoproto.gogoproto_import", + Tag: "varint,63027,opt,name=gogoproto_import", + Filename: "gogoproto/gogo.proto", +} + +var E_ProtosizerAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63028, + Name: "gogoproto.protosizer_all", + Tag: "varint,63028,opt,name=protosizer_all", + Filename: "gogoproto/gogo.proto", +} + +var E_CompareAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63029, + Name: "gogoproto.compare_all", + Tag: "varint,63029,opt,name=compare_all", + Filename: "gogoproto/gogo.proto", +} + +var E_TypedeclAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63030, + Name: "gogoproto.typedecl_all", + Tag: "varint,63030,opt,name=typedecl_all", + Filename: "gogoproto/gogo.proto", +} + +var E_EnumdeclAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63031, + Name: "gogoproto.enumdecl_all", + Tag: "varint,63031,opt,name=enumdecl_all", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoRegistration = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63032, + Name: "gogoproto.goproto_registration", + Tag: "varint,63032,opt,name=goproto_registration", + Filename: "gogoproto/gogo.proto", +} + +var E_MessagenameAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63033, + Name: "gogoproto.messagename_all", + Tag: "varint,63033,opt,name=messagename_all", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoSizecacheAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63034, + Name: "gogoproto.goproto_sizecache_all", + Tag: "varint,63034,opt,name=goproto_sizecache_all", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoUnkeyedAll = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63035, + Name: "gogoproto.goproto_unkeyed_all", + Tag: "varint,63035,opt,name=goproto_unkeyed_all", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoGetters = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64001, + Name: "gogoproto.goproto_getters", + Tag: "varint,64001,opt,name=goproto_getters", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoStringer = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64003, + Name: "gogoproto.goproto_stringer", + Tag: "varint,64003,opt,name=goproto_stringer", + Filename: "gogoproto/gogo.proto", +} + +var E_VerboseEqual = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64004, + Name: "gogoproto.verbose_equal", + Tag: "varint,64004,opt,name=verbose_equal", + Filename: "gogoproto/gogo.proto", +} + +var E_Face = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64005, + Name: "gogoproto.face", + Tag: "varint,64005,opt,name=face", + Filename: "gogoproto/gogo.proto", +} + +var E_Gostring = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64006, + Name: "gogoproto.gostring", + Tag: "varint,64006,opt,name=gostring", + Filename: "gogoproto/gogo.proto", +} + +var E_Populate = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64007, + Name: "gogoproto.populate", + Tag: "varint,64007,opt,name=populate", + Filename: "gogoproto/gogo.proto", +} + +var E_Stringer = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 67008, + Name: "gogoproto.stringer", + Tag: "varint,67008,opt,name=stringer", + Filename: "gogoproto/gogo.proto", +} + +var E_Onlyone = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64009, + Name: "gogoproto.onlyone", + Tag: "varint,64009,opt,name=onlyone", + Filename: "gogoproto/gogo.proto", +} + +var E_Equal = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64013, + Name: "gogoproto.equal", + Tag: "varint,64013,opt,name=equal", + Filename: "gogoproto/gogo.proto", +} + +var E_Description = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64014, + Name: "gogoproto.description", + Tag: "varint,64014,opt,name=description", + Filename: "gogoproto/gogo.proto", +} + +var E_Testgen = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64015, + Name: "gogoproto.testgen", + Tag: "varint,64015,opt,name=testgen", + Filename: "gogoproto/gogo.proto", +} + +var E_Benchgen = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64016, + Name: "gogoproto.benchgen", + Tag: "varint,64016,opt,name=benchgen", + Filename: "gogoproto/gogo.proto", +} + +var E_Marshaler = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64017, + Name: "gogoproto.marshaler", + Tag: "varint,64017,opt,name=marshaler", + Filename: "gogoproto/gogo.proto", +} + +var E_Unmarshaler = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64018, + Name: "gogoproto.unmarshaler", + Tag: "varint,64018,opt,name=unmarshaler", + Filename: "gogoproto/gogo.proto", +} + +var E_StableMarshaler = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64019, + Name: "gogoproto.stable_marshaler", + Tag: "varint,64019,opt,name=stable_marshaler", + Filename: "gogoproto/gogo.proto", +} + +var E_Sizer = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64020, + Name: "gogoproto.sizer", + Tag: "varint,64020,opt,name=sizer", + Filename: "gogoproto/gogo.proto", +} + +var E_UnsafeMarshaler = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64023, + Name: "gogoproto.unsafe_marshaler", + Tag: "varint,64023,opt,name=unsafe_marshaler", + Filename: "gogoproto/gogo.proto", +} + +var E_UnsafeUnmarshaler = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64024, + Name: "gogoproto.unsafe_unmarshaler", + Tag: "varint,64024,opt,name=unsafe_unmarshaler", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoExtensionsMap = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64025, + Name: "gogoproto.goproto_extensions_map", + Tag: "varint,64025,opt,name=goproto_extensions_map", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoUnrecognized = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64026, + Name: "gogoproto.goproto_unrecognized", + Tag: "varint,64026,opt,name=goproto_unrecognized", + Filename: "gogoproto/gogo.proto", +} + +var E_Protosizer = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64028, + Name: "gogoproto.protosizer", + Tag: "varint,64028,opt,name=protosizer", + Filename: "gogoproto/gogo.proto", +} + +var E_Compare = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64029, + Name: "gogoproto.compare", + Tag: "varint,64029,opt,name=compare", + Filename: "gogoproto/gogo.proto", +} + +var E_Typedecl = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64030, + Name: "gogoproto.typedecl", + Tag: "varint,64030,opt,name=typedecl", + Filename: "gogoproto/gogo.proto", +} + +var E_Messagename = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64033, + Name: "gogoproto.messagename", + Tag: "varint,64033,opt,name=messagename", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoSizecache = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64034, + Name: "gogoproto.goproto_sizecache", + Tag: "varint,64034,opt,name=goproto_sizecache", + Filename: "gogoproto/gogo.proto", +} + +var E_GoprotoUnkeyed = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64035, + Name: "gogoproto.goproto_unkeyed", + Tag: "varint,64035,opt,name=goproto_unkeyed", + Filename: "gogoproto/gogo.proto", +} + +var E_Nullable = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FieldOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 65001, + Name: "gogoproto.nullable", + Tag: "varint,65001,opt,name=nullable", + Filename: "gogoproto/gogo.proto", +} + +var E_Embed = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FieldOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 65002, + Name: "gogoproto.embed", + Tag: "varint,65002,opt,name=embed", + Filename: "gogoproto/gogo.proto", +} + +var E_Customtype = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FieldOptions)(nil), + ExtensionType: (*string)(nil), + Field: 65003, + Name: "gogoproto.customtype", + Tag: "bytes,65003,opt,name=customtype", + Filename: "gogoproto/gogo.proto", +} + +var E_Customname = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FieldOptions)(nil), + ExtensionType: (*string)(nil), + Field: 65004, + Name: "gogoproto.customname", + Tag: "bytes,65004,opt,name=customname", + Filename: "gogoproto/gogo.proto", +} + +var E_Jsontag = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FieldOptions)(nil), + ExtensionType: (*string)(nil), + Field: 65005, + Name: "gogoproto.jsontag", + Tag: "bytes,65005,opt,name=jsontag", + Filename: "gogoproto/gogo.proto", +} + +var E_Moretags = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FieldOptions)(nil), + ExtensionType: (*string)(nil), + Field: 65006, + Name: "gogoproto.moretags", + Tag: "bytes,65006,opt,name=moretags", + Filename: "gogoproto/gogo.proto", +} + +var E_Casttype = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FieldOptions)(nil), + ExtensionType: (*string)(nil), + Field: 65007, + Name: "gogoproto.casttype", + Tag: "bytes,65007,opt,name=casttype", + Filename: "gogoproto/gogo.proto", +} + +var E_Castkey = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FieldOptions)(nil), + ExtensionType: (*string)(nil), + Field: 65008, + Name: "gogoproto.castkey", + Tag: "bytes,65008,opt,name=castkey", + Filename: "gogoproto/gogo.proto", +} + +var E_Castvalue = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FieldOptions)(nil), + ExtensionType: (*string)(nil), + Field: 65009, + Name: "gogoproto.castvalue", + Tag: "bytes,65009,opt,name=castvalue", + Filename: "gogoproto/gogo.proto", +} + +var E_Stdtime = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FieldOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 65010, + Name: "gogoproto.stdtime", + Tag: "varint,65010,opt,name=stdtime", + Filename: "gogoproto/gogo.proto", +} + +var E_Stdduration = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FieldOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 65011, + Name: "gogoproto.stdduration", + Tag: "varint,65011,opt,name=stdduration", + Filename: "gogoproto/gogo.proto", +} + +var E_Wktpointer = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FieldOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 65012, + Name: "gogoproto.wktpointer", + Tag: "varint,65012,opt,name=wktpointer", + Filename: "gogoproto/gogo.proto", +} + +var E_Castrepeated = &proto.ExtensionDesc{ + ExtendedType: (*descriptorpb.FieldOptions)(nil), + ExtensionType: (*string)(nil), + Field: 65013, + Name: "gogoproto.castrepeated", + Tag: "bytes,65013,opt,name=castrepeated", + Filename: "gogoproto/gogo.proto", +} + +func init() { + proto.RegisterExtension(E_GoprotoEnumPrefix) + proto.RegisterExtension(E_GoprotoEnumStringer) + proto.RegisterExtension(E_EnumStringer) + proto.RegisterExtension(E_EnumCustomname) + proto.RegisterExtension(E_Enumdecl) + proto.RegisterExtension(E_EnumvalueCustomname) + proto.RegisterExtension(E_GoprotoGettersAll) + proto.RegisterExtension(E_GoprotoEnumPrefixAll) + proto.RegisterExtension(E_GoprotoStringerAll) + proto.RegisterExtension(E_VerboseEqualAll) + proto.RegisterExtension(E_FaceAll) + proto.RegisterExtension(E_GostringAll) + proto.RegisterExtension(E_PopulateAll) + proto.RegisterExtension(E_StringerAll) + proto.RegisterExtension(E_OnlyoneAll) + proto.RegisterExtension(E_EqualAll) + proto.RegisterExtension(E_DescriptionAll) + proto.RegisterExtension(E_TestgenAll) + proto.RegisterExtension(E_BenchgenAll) + proto.RegisterExtension(E_MarshalerAll) + proto.RegisterExtension(E_UnmarshalerAll) + proto.RegisterExtension(E_StableMarshalerAll) + proto.RegisterExtension(E_SizerAll) + proto.RegisterExtension(E_GoprotoEnumStringerAll) + proto.RegisterExtension(E_EnumStringerAll) + proto.RegisterExtension(E_UnsafeMarshalerAll) + proto.RegisterExtension(E_UnsafeUnmarshalerAll) + proto.RegisterExtension(E_GoprotoExtensionsMapAll) + proto.RegisterExtension(E_GoprotoUnrecognizedAll) + proto.RegisterExtension(E_GogoprotoImport) + proto.RegisterExtension(E_ProtosizerAll) + proto.RegisterExtension(E_CompareAll) + proto.RegisterExtension(E_TypedeclAll) + proto.RegisterExtension(E_EnumdeclAll) + proto.RegisterExtension(E_GoprotoRegistration) + proto.RegisterExtension(E_MessagenameAll) + proto.RegisterExtension(E_GoprotoSizecacheAll) + proto.RegisterExtension(E_GoprotoUnkeyedAll) + proto.RegisterExtension(E_GoprotoGetters) + proto.RegisterExtension(E_GoprotoStringer) + proto.RegisterExtension(E_VerboseEqual) + proto.RegisterExtension(E_Face) + proto.RegisterExtension(E_Gostring) + proto.RegisterExtension(E_Populate) + proto.RegisterExtension(E_Stringer) + proto.RegisterExtension(E_Onlyone) + proto.RegisterExtension(E_Equal) + proto.RegisterExtension(E_Description) + proto.RegisterExtension(E_Testgen) + proto.RegisterExtension(E_Benchgen) + proto.RegisterExtension(E_Marshaler) + proto.RegisterExtension(E_Unmarshaler) + proto.RegisterExtension(E_StableMarshaler) + proto.RegisterExtension(E_Sizer) + proto.RegisterExtension(E_UnsafeMarshaler) + proto.RegisterExtension(E_UnsafeUnmarshaler) + proto.RegisterExtension(E_GoprotoExtensionsMap) + proto.RegisterExtension(E_GoprotoUnrecognized) + proto.RegisterExtension(E_Protosizer) + proto.RegisterExtension(E_Compare) + proto.RegisterExtension(E_Typedecl) + proto.RegisterExtension(E_Messagename) + proto.RegisterExtension(E_GoprotoSizecache) + proto.RegisterExtension(E_GoprotoUnkeyed) + proto.RegisterExtension(E_Nullable) + proto.RegisterExtension(E_Embed) + proto.RegisterExtension(E_Customtype) + proto.RegisterExtension(E_Customname) + proto.RegisterExtension(E_Jsontag) + proto.RegisterExtension(E_Moretags) + proto.RegisterExtension(E_Casttype) + proto.RegisterExtension(E_Castkey) + proto.RegisterExtension(E_Castvalue) + proto.RegisterExtension(E_Stdtime) + proto.RegisterExtension(E_Stdduration) + proto.RegisterExtension(E_Wktpointer) + proto.RegisterExtension(E_Castrepeated) +} + +func init() { proto.RegisterFile("gogoproto/gogo.proto", fileDescriptor_c586470e9b64aee7) } + +var fileDescriptor_c586470e9b64aee7 = []byte{ + // 1382 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x98, 0x49, 0x6c, 0x1c, 0x45, + 0x17, 0x80, 0x63, 0xfd, 0x89, 0x62, 0x97, 0xed, 0x38, 0x5e, 0xfe, 0x10, 0x22, 0x30, 0x81, 0x13, + 0x27, 0xe7, 0x14, 0xa1, 0x94, 0x15, 0x45, 0x8e, 0xe5, 0x58, 0x41, 0x24, 0x18, 0x27, 0x0e, 0x9b, + 0xd0, 0xa8, 0x67, 0xa6, 0xdc, 0x6e, 0xd2, 0xdd, 0xd5, 0x74, 0x57, 0x87, 0x38, 0x37, 0x14, 0x16, + 0x21, 0x04, 0x84, 0x45, 0x82, 0x84, 0x24, 0x10, 0x10, 0xfb, 0x1a, 0xf6, 0xe5, 0xc2, 0x05, 0xc8, + 0x31, 0xdc, 0x38, 0xa2, 0x98, 0x0b, 0x60, 0x76, 0x73, 0xf2, 0x05, 0xbd, 0xee, 0xf7, 0x7a, 0xaa, + 0xdb, 0x23, 0x55, 0xcd, 0x6d, 0x3c, 0xae, 0xef, 0x73, 0xf5, 0x7b, 0x55, 0xef, 0x3d, 0x37, 0x1b, + 0x71, 0xa5, 0x2b, 0xa3, 0x58, 0x2a, 0xb9, 0x03, 0x3e, 0x8d, 0x65, 0x1f, 0x87, 0x7a, 0x8a, 0x6f, + 0xb7, 0x6d, 0x77, 0xa5, 0x74, 0x7d, 0xb1, 0x23, 0xfb, 0xa9, 0x9e, 0xce, 0xef, 0x68, 0x8a, 0xa4, + 0x11, 0x7b, 0x91, 0x92, 0x71, 0xbe, 0x98, 0x1f, 0x64, 0xc3, 0xb8, 0xb8, 0x26, 0xc2, 0x34, 0xa8, + 0x45, 0xb1, 0x98, 0xf7, 0x8e, 0x0f, 0x5d, 0x33, 0x96, 0x93, 0x63, 0x44, 0x8e, 0x4d, 0x85, 0x69, + 0x70, 0x6b, 0xa4, 0x3c, 0x19, 0x26, 0x5b, 0x2f, 0xfe, 0xf4, 0xbf, 0xed, 0x5d, 0x37, 0x76, 0xcf, + 0x0e, 0x22, 0x0a, 0xbf, 0x9b, 0xc9, 0x40, 0x3e, 0xcb, 0xfe, 0x5f, 0xf2, 0x25, 0x2a, 0xf6, 0x42, + 0x57, 0xc4, 0x06, 0xe3, 0x37, 0x68, 0x1c, 0xd6, 0x8c, 0x87, 0x10, 0xe5, 0x93, 0xac, 0xbf, 0x13, + 0xd7, 0xb7, 0xe8, 0xea, 0x13, 0xba, 0x64, 0x9a, 0x0d, 0x64, 0x92, 0x46, 0x9a, 0x28, 0x19, 0x84, + 0x4e, 0x20, 0x0c, 0x9a, 0xef, 0x32, 0x4d, 0xcf, 0xec, 0x26, 0xc0, 0x26, 0x0b, 0x8a, 0x73, 0xd6, + 0x0d, 0xdf, 0x34, 0x45, 0xc3, 0x37, 0x18, 0x2e, 0xe1, 0x46, 0x8a, 0xf5, 0xfc, 0x08, 0x1b, 0x81, + 0xcf, 0xc7, 0x1c, 0x3f, 0x15, 0xfa, 0x4e, 0xae, 0x6f, 0xeb, 0x39, 0x02, 0xcb, 0x48, 0xf6, 0xfd, + 0xc9, 0xf5, 0xd9, 0x76, 0x86, 0x0b, 0x81, 0xb6, 0x27, 0x2d, 0x8b, 0xae, 0x50, 0x4a, 0xc4, 0x49, + 0xcd, 0xf1, 0xdb, 0x6d, 0x6f, 0x9f, 0xe7, 0x17, 0xc6, 0xd3, 0xcb, 0xe5, 0x2c, 0x4e, 0xe7, 0xe4, + 0x84, 0xef, 0xf3, 0x39, 0x76, 0x55, 0x9b, 0x53, 0x61, 0xe1, 0x3c, 0x83, 0xce, 0x91, 0x35, 0x27, + 0x03, 0xb4, 0x33, 0x8c, 0xbe, 0x2f, 0x72, 0x69, 0xe1, 0x7c, 0x01, 0x9d, 0x43, 0xc8, 0x52, 0x4a, + 0xc1, 0x78, 0x33, 0x1b, 0x3c, 0x26, 0xe2, 0xba, 0x4c, 0x44, 0x4d, 0xdc, 0x97, 0x3a, 0xbe, 0x85, + 0xee, 0x2c, 0xea, 0x06, 0x10, 0x9c, 0x02, 0x0e, 0x5c, 0xbb, 0x58, 0xf7, 0xbc, 0xd3, 0x10, 0x16, + 0x8a, 0x73, 0xa8, 0xd8, 0x08, 0xeb, 0x01, 0x9d, 0x60, 0x7d, 0xae, 0xcc, 0x1f, 0xc9, 0x02, 0x3f, + 0x8f, 0x78, 0x2f, 0x31, 0xa8, 0x88, 0x64, 0x94, 0xfa, 0x8e, 0xb2, 0xd9, 0xc1, 0x8b, 0xa4, 0x20, + 0x06, 0x15, 0x1d, 0x84, 0xf5, 0x25, 0x52, 0x24, 0x5a, 0x3c, 0xf7, 0xb0, 0x5e, 0x19, 0xfa, 0x8b, + 0x32, 0xb4, 0xd9, 0xc4, 0x05, 0x34, 0x30, 0x44, 0x40, 0x30, 0xce, 0x7a, 0x6c, 0x13, 0xf1, 0xea, + 0x32, 0x5d, 0x0f, 0xca, 0xc0, 0x34, 0x1b, 0xa0, 0x02, 0xe5, 0xc9, 0xd0, 0x42, 0xf1, 0x1a, 0x2a, + 0x36, 0x69, 0x18, 0x3e, 0x86, 0x12, 0x89, 0x72, 0x85, 0x8d, 0xe4, 0x75, 0x7a, 0x0c, 0x44, 0x30, + 0x94, 0x75, 0x11, 0x36, 0x16, 0xec, 0x0c, 0x6f, 0x50, 0x28, 0x89, 0x01, 0xc5, 0x24, 0xeb, 0x0f, + 0x9c, 0x38, 0x59, 0x70, 0x7c, 0xab, 0x74, 0xbc, 0x89, 0x8e, 0xbe, 0x02, 0xc2, 0x88, 0xa4, 0x61, + 0x27, 0x9a, 0xb7, 0x28, 0x22, 0x1a, 0x86, 0x57, 0x2f, 0x51, 0x4e, 0xdd, 0x17, 0xb5, 0x4e, 0x6c, + 0x6f, 0xd3, 0xd5, 0xcb, 0xd9, 0x03, 0xba, 0x71, 0x9c, 0xf5, 0x24, 0xde, 0x09, 0x2b, 0xcd, 0x3b, + 0x94, 0xe9, 0x0c, 0x00, 0xf8, 0x4e, 0x76, 0x75, 0xdb, 0x36, 0x61, 0x21, 0x7b, 0x17, 0x65, 0x5b, + 0xda, 0xb4, 0x0a, 0x2c, 0x09, 0x9d, 0x2a, 0xdf, 0xa3, 0x92, 0x20, 0x2a, 0xae, 0x19, 0x36, 0x92, + 0x86, 0x89, 0x33, 0xdf, 0x59, 0xd4, 0xde, 0xa7, 0xa8, 0xe5, 0x6c, 0x29, 0x6a, 0x87, 0xd9, 0x16, + 0x34, 0x76, 0x96, 0xd7, 0x0f, 0xa8, 0xb0, 0xe6, 0xf4, 0x5c, 0x39, 0xbb, 0x77, 0xb3, 0x6d, 0x45, + 0x38, 0x8f, 0x2b, 0x11, 0x26, 0xc0, 0xd4, 0x02, 0x27, 0xb2, 0x30, 0x5f, 0x44, 0x33, 0x55, 0xfc, + 0xa9, 0x42, 0x70, 0xc0, 0x89, 0x40, 0x7e, 0x07, 0xdb, 0x4a, 0xf2, 0x34, 0x8c, 0x45, 0x43, 0xba, + 0xa1, 0x77, 0x42, 0x34, 0x2d, 0xd4, 0x1f, 0x56, 0x52, 0x35, 0xa7, 0xe1, 0x60, 0xde, 0xcf, 0x36, + 0x17, 0xb3, 0x4a, 0xcd, 0x0b, 0x22, 0x19, 0x2b, 0x83, 0xf1, 0x23, 0xca, 0x54, 0xc1, 0xed, 0xcf, + 0x30, 0x3e, 0xc5, 0x36, 0x65, 0x3f, 0xda, 0x1e, 0xc9, 0x8f, 0x51, 0xd4, 0xdf, 0xa2, 0xb0, 0x70, + 0x34, 0x64, 0x10, 0x39, 0xb1, 0x4d, 0xfd, 0xfb, 0x84, 0x0a, 0x07, 0x22, 0x58, 0x38, 0xd4, 0x62, + 0x24, 0xa0, 0xdb, 0x5b, 0x18, 0x3e, 0xa5, 0xc2, 0x41, 0x0c, 0x2a, 0x68, 0x60, 0xb0, 0x50, 0x7c, + 0x46, 0x0a, 0x62, 0x40, 0x71, 0x5b, 0xab, 0xd1, 0xc6, 0xc2, 0xf5, 0x12, 0x15, 0x3b, 0xb0, 0xda, + 0xa0, 0xfa, 0x7c, 0xb9, 0x3c, 0x84, 0xcd, 0x6a, 0x28, 0x54, 0xa2, 0x40, 0x24, 0x89, 0xe3, 0x0a, + 0x98, 0x38, 0x2c, 0x36, 0xf6, 0x05, 0x55, 0x22, 0x0d, 0x83, 0xbd, 0x69, 0x13, 0x22, 0x84, 0xbd, + 0xe1, 0x34, 0x16, 0x6c, 0x74, 0x5f, 0x56, 0x36, 0x77, 0x88, 0x58, 0x70, 0x6a, 0xf3, 0x4f, 0x1a, + 0x1e, 0x15, 0x8b, 0x56, 0xa7, 0xf3, 0xab, 0xca, 0xfc, 0x33, 0x97, 0x93, 0x79, 0x0d, 0x19, 0xa8, + 0xcc, 0x53, 0x43, 0xd7, 0xad, 0x71, 0x1d, 0xc8, 0x9f, 0x8b, 0x74, 0x0f, 0xac, 0xe0, 0xf3, 0x96, + 0xc7, 0x29, 0x7e, 0x0b, 0x1c, 0xf2, 0xf2, 0xd0, 0x63, 0x96, 0x9d, 0x5c, 0x29, 0xce, 0x79, 0x69, + 0xe6, 0xe1, 0xfb, 0x58, 0x7f, 0x69, 0xe0, 0x31, 0xab, 0x1e, 0x44, 0x55, 0x9f, 0x3e, 0xef, 0xf0, + 0x9d, 0x6c, 0x3d, 0x0c, 0x2f, 0x66, 0xfc, 0x21, 0xc4, 0xb3, 0xe5, 0x7c, 0x37, 0xeb, 0xa6, 0xa1, + 0xc5, 0x8c, 0x3e, 0x8c, 0x68, 0x81, 0x00, 0x4e, 0x03, 0x8b, 0x19, 0x7f, 0x84, 0x70, 0x42, 0x00, + 0xb7, 0x0f, 0xe1, 0xd7, 0x8f, 0xad, 0xc7, 0xa6, 0x43, 0xb1, 0x1b, 0x67, 0x1b, 0x71, 0x52, 0x31, + 0xd3, 0x8f, 0xe2, 0x1f, 0x27, 0x82, 0xdf, 0xc4, 0x36, 0x58, 0x06, 0xfc, 0x71, 0x44, 0xf3, 0xf5, + 0x7c, 0x92, 0xf5, 0x6a, 0xd3, 0x89, 0x19, 0x7f, 0x02, 0x71, 0x9d, 0x82, 0xad, 0xe3, 0x74, 0x62, + 0x16, 0x3c, 0x49, 0x5b, 0x47, 0x02, 0xc2, 0x46, 0x83, 0x89, 0x99, 0x3e, 0x45, 0x51, 0x27, 0x84, + 0xef, 0x61, 0x3d, 0x45, 0xb3, 0x31, 0xf3, 0x4f, 0x21, 0xdf, 0x62, 0x20, 0x02, 0x5a, 0xb3, 0x33, + 0x2b, 0x9e, 0xa6, 0x08, 0x68, 0x14, 0x5c, 0xa3, 0xea, 0x00, 0x63, 0x36, 0x3d, 0x43, 0xd7, 0xa8, + 0x32, 0xbf, 0x40, 0x36, 0xb3, 0x9a, 0x6f, 0x56, 0x3c, 0x4b, 0xd9, 0xcc, 0xd6, 0xc3, 0x36, 0xaa, + 0x13, 0x81, 0xd9, 0xf1, 0x1c, 0x6d, 0xa3, 0x32, 0x10, 0xf0, 0x19, 0x36, 0xb4, 0x76, 0x1a, 0x30, + 0xfb, 0x9e, 0x47, 0xdf, 0xe0, 0x9a, 0x61, 0x80, 0xdf, 0xce, 0xb6, 0xb4, 0x9f, 0x04, 0xcc, 0xd6, + 0xd3, 0x2b, 0x95, 0xff, 0xdd, 0xf4, 0x41, 0x80, 0x1f, 0x6e, 0xb5, 0x14, 0x7d, 0x0a, 0x30, 0x6b, + 0xcf, 0xac, 0x94, 0x0b, 0xb7, 0x3e, 0x04, 0xf0, 0x09, 0xc6, 0x5a, 0x0d, 0xd8, 0xec, 0x3a, 0x8b, + 0x2e, 0x0d, 0x82, 0xab, 0x81, 0xfd, 0xd7, 0xcc, 0x9f, 0xa3, 0xab, 0x81, 0x04, 0x5c, 0x0d, 0x6a, + 0xbd, 0x66, 0xfa, 0x3c, 0x5d, 0x0d, 0x42, 0xe0, 0x64, 0x6b, 0xdd, 0xcd, 0x6c, 0xb8, 0x40, 0x27, + 0x5b, 0xa3, 0xf8, 0x41, 0x36, 0xb8, 0xa6, 0x21, 0x9a, 0x55, 0x2f, 0xa3, 0x6a, 0x73, 0xb5, 0x1f, + 0xea, 0xcd, 0x0b, 0x9b, 0xa1, 0xd9, 0xf6, 0x4a, 0xa5, 0x79, 0x61, 0x2f, 0xe4, 0xe3, 0xac, 0x3b, + 0x4c, 0x7d, 0x1f, 0x2e, 0xcf, 0xd0, 0xb5, 0x6d, 0xba, 0xa9, 0xf0, 0x9b, 0xa4, 0xf8, 0x79, 0x15, + 0xa3, 0x43, 0x00, 0xdf, 0xc9, 0x36, 0x88, 0xa0, 0x2e, 0x9a, 0x26, 0xf2, 0x97, 0x55, 0x2a, 0x98, + 0xb0, 0x9a, 0xef, 0x61, 0x2c, 0x7f, 0x35, 0x02, 0x61, 0x36, 0xb1, 0xbf, 0xae, 0xe6, 0x6f, 0x69, + 0x34, 0xa4, 0x25, 0xc8, 0x92, 0x62, 0x10, 0x2c, 0x97, 0x05, 0x59, 0x46, 0x76, 0xb1, 0x8d, 0xf7, + 0x26, 0x32, 0x54, 0x8e, 0x6b, 0xa2, 0x7f, 0x43, 0x9a, 0xd6, 0x43, 0xc0, 0x02, 0x19, 0x0b, 0xe5, + 0xb8, 0x89, 0x89, 0xfd, 0x1d, 0xd9, 0x02, 0x00, 0xb8, 0xe1, 0x24, 0xca, 0xe6, 0xb9, 0xff, 0x20, + 0x98, 0x00, 0xd8, 0x34, 0x7c, 0x3e, 0x2a, 0x16, 0x4d, 0xec, 0x9f, 0xb4, 0x69, 0x5c, 0xcf, 0x77, + 0xb3, 0x1e, 0xf8, 0x98, 0xbd, 0x55, 0x32, 0xc1, 0x7f, 0x21, 0xdc, 0x22, 0xe0, 0x2f, 0x27, 0xaa, + 0xa9, 0x3c, 0x73, 0xb0, 0xff, 0xc6, 0x4c, 0xd3, 0x7a, 0x3e, 0xc1, 0x7a, 0x13, 0xd5, 0x6c, 0xa6, + 0x38, 0x9f, 0x1a, 0xf0, 0x7f, 0x56, 0x8b, 0x57, 0x16, 0x05, 0x03, 0xd9, 0xbe, 0xff, 0xa8, 0x8a, + 0xa4, 0x17, 0x2a, 0x11, 0x9b, 0x0c, 0x2b, 0x68, 0xd0, 0x10, 0x3e, 0xc9, 0xfa, 0xe0, 0x59, 0x62, + 0x11, 0x09, 0x47, 0x99, 0x4f, 0xeb, 0xbf, 0x18, 0x80, 0x12, 0xb4, 0xf7, 0x9e, 0x4b, 0x57, 0x46, + 0xbb, 0x2e, 0x5f, 0x19, 0xed, 0xfa, 0xf1, 0xca, 0x68, 0xd7, 0xa9, 0xa5, 0xd1, 0x75, 0x97, 0x97, + 0x46, 0xd7, 0xfd, 0xb0, 0x34, 0xba, 0x8e, 0x0d, 0x37, 0x64, 0x50, 0x35, 0xee, 0x65, 0xd3, 0x72, + 0x5a, 0xce, 0x64, 0x45, 0xec, 0xae, 0x1b, 0x5c, 0x4f, 0x2d, 0xa4, 0xf5, 0xb1, 0x86, 0x0c, 0xb2, + 0xd7, 0xb8, 0xad, 0xb7, 0xb5, 0xc5, 0x3f, 0x39, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x5f, 0xbe, + 0x0f, 0x06, 0xea, 0x15, 0x00, 0x00, +} diff --git a/proto/tendermint/types/types.pb.go b/proto/tendermint/types/types.pb.go index 1613a0a5e2..1f0048075d 100644 --- a/proto/tendermint/types/types.pb.go +++ b/proto/tendermint/types/types.pb.go @@ -1382,9 +1382,9 @@ func (m *BlockMeta) GetNumTxs() int64 { // TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree. type TxProof struct { - RootHash []byte `protobuf:"bytes,1,opt,name=root_hash,json=rootHash,proto3" json:"root_hash,omitempty"` - Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` - Proof *crypto.Proof `protobuf:"bytes,3,opt,name=proof,proto3" json:"proof,omitempty"` + RowRoots [][]byte `protobuf:"bytes,1,rep,name=row_roots,json=rowRoots,proto3" json:"row_roots,omitempty"` + Data [][]byte `protobuf:"bytes,2,rep,name=data,proto3" json:"data,omitempty"` + Proofs []*NMTProof `protobuf:"bytes,3,rep,name=proofs,proto3" json:"proofs,omitempty"` } func (m *TxProof) Reset() { *m = TxProof{} } @@ -1420,23 +1420,23 @@ func (m *TxProof) XXX_DiscardUnknown() { var xxx_messageInfo_TxProof proto.InternalMessageInfo -func (m *TxProof) GetRootHash() []byte { +func (m *TxProof) GetRowRoots() [][]byte { if m != nil { - return m.RootHash + return m.RowRoots } return nil } -func (m *TxProof) GetData() []byte { +func (m *TxProof) GetData() [][]byte { if m != nil { return m.Data } return nil } -func (m *TxProof) GetProof() *crypto.Proof { +func (m *TxProof) GetProofs() []*NMTProof { if m != nil { - return m.Proof + return m.Proofs } return nil } @@ -1496,6 +1496,89 @@ func (m *MalleatedTx) GetTx() []byte { return nil } +// 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 +// where that namespace would be. +type NMTProof struct { + // start index of this proof. + Start int32 `protobuf:"varint,1,opt,name=start,proto3" json:"start,omitempty"` + // end index of this proof. + End int32 `protobuf:"varint,2,opt,name=end,proto3" json:"end,omitempty"` + // Nodes that together with the corresponding leaf values can be used to + // recompute the root and verify this proof. Nodes should consist of the max + // and min namespaces along with the actual hash, resulting in each being 48 + // bytes each + Nodes [][]byte `protobuf:"bytes,3,rep,name=nodes,proto3" json:"nodes,omitempty"` + // leafHash are nil if the namespace is present in the NMT. In case the + // namespace to be proved is in the min/max range of the tree but absent, this + // will contain the leaf hash necessary to verify the proof of absence. Leaf + // hashes should consist of the namespace along with the actual hash, + // resulting 40 bytes total. + LeafHash []byte `protobuf:"bytes,4,opt,name=leaf_hash,json=leafHash,proto3" json:"leaf_hash,omitempty"` +} + +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{20} +} +func (m *NMTProof) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *NMTProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_NMTProof.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 *NMTProof) XXX_Merge(src proto.Message) { + xxx_messageInfo_NMTProof.Merge(m, src) +} +func (m *NMTProof) XXX_Size() int { + return m.Size() +} +func (m *NMTProof) XXX_DiscardUnknown() { + xxx_messageInfo_NMTProof.DiscardUnknown(m) +} + +var xxx_messageInfo_NMTProof proto.InternalMessageInfo + +func (m *NMTProof) GetStart() int32 { + if m != nil { + return m.Start + } + return 0 +} + +func (m *NMTProof) GetEnd() int32 { + if m != nil { + return m.End + } + return 0 +} + +func (m *NMTProof) GetNodes() [][]byte { + if m != nil { + return m.Nodes + } + return nil +} + +func (m *NMTProof) GetLeafHash() []byte { + if m != nil { + return m.LeafHash + } + return nil +} + func init() { proto.RegisterEnum("tendermint.types.BlockIDFlag", BlockIDFlag_name, BlockIDFlag_value) proto.RegisterEnum("tendermint.types.SignedMsgType", SignedMsgType_name, SignedMsgType_value) @@ -1519,121 +1602,126 @@ func init() { proto.RegisterType((*BlockMeta)(nil), "tendermint.types.BlockMeta") proto.RegisterType((*TxProof)(nil), "tendermint.types.TxProof") proto.RegisterType((*MalleatedTx)(nil), "tendermint.types.MalleatedTx") + proto.RegisterType((*NMTProof)(nil), "tendermint.types.NMTProof") } func init() { proto.RegisterFile("tendermint/types/types.proto", fileDescriptor_d3a6e55e2345de56) } var fileDescriptor_d3a6e55e2345de56 = []byte{ - // 1744 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcd, 0x73, 0x1b, 0x49, - 0x15, 0xf7, 0x48, 0xb2, 0x3e, 0x9e, 0x24, 0x5b, 0x1e, 0x9c, 0x44, 0x56, 0x12, 0x59, 0x88, 0x82, - 0xf5, 0x7e, 0x20, 0x87, 0x2c, 0xc5, 0x47, 0x15, 0x50, 0x2b, 0xd9, 0xde, 0x58, 0xac, 0x3f, 0xc4, - 0x48, 0x1b, 0x0a, 0x2e, 0x53, 0x2d, 0x4d, 0x47, 0x1a, 0x32, 0x9a, 0x19, 0xa6, 0x5b, 0x5e, 0x39, - 0x7f, 0x01, 0xe5, 0x53, 0x4e, 0xdc, 0x7c, 0x82, 0x03, 0x77, 0xfe, 0x01, 0x8a, 0xd3, 0x5e, 0xa8, - 0xda, 0x1b, 0x5c, 0x08, 0x54, 0x42, 0x51, 0xfc, 0x19, 0x54, 0xbf, 0xee, 0x19, 0x8d, 0x2c, 0x29, - 0xa4, 0x52, 0x29, 0x2e, 0xaa, 0x99, 0xf7, 0x7e, 0xaf, 0xfb, 0xf5, 0xef, 0x7d, 0xf5, 0x08, 0xee, - 0x71, 0xea, 0x5a, 0x34, 0x18, 0xdb, 0x2e, 0xdf, 0xe7, 0x97, 0x3e, 0x65, 0xf2, 0xb7, 0xe1, 0x07, - 0x1e, 0xf7, 0xf4, 0xd2, 0x4c, 0xdb, 0x40, 0x79, 0x65, 0x7b, 0xe8, 0x0d, 0x3d, 0x54, 0xee, 0x8b, - 0x27, 0x89, 0xab, 0xec, 0x0e, 0x3d, 0x6f, 0xe8, 0xd0, 0x7d, 0x7c, 0xeb, 0x4f, 0x9e, 0xec, 0x73, - 0x7b, 0x4c, 0x19, 0x27, 0x63, 0x5f, 0x01, 0xee, 0xc7, 0xb6, 0x19, 0x04, 0x97, 0x3e, 0xf7, 0x04, - 0xd6, 0x7b, 0xa2, 0xd4, 0xd5, 0x98, 0xfa, 0x82, 0x06, 0xcc, 0xf6, 0xdc, 0xb8, 0x1f, 0x95, 0xda, - 0x82, 0x97, 0x17, 0xc4, 0xb1, 0x2d, 0xc2, 0xbd, 0x40, 0x22, 0xea, 0x3f, 0x84, 0x62, 0x87, 0x04, - 0xbc, 0x4b, 0xf9, 0x31, 0x25, 0x16, 0x0d, 0xf4, 0x6d, 0x58, 0xe7, 0x1e, 0x27, 0x4e, 0x59, 0xab, - 0x69, 0x7b, 0x45, 0x43, 0xbe, 0xe8, 0x3a, 0xa4, 0x46, 0x84, 0x8d, 0xca, 0x89, 0x9a, 0xb6, 0x57, - 0x30, 0xf0, 0xb9, 0x3e, 0x82, 0x94, 0x30, 0x15, 0x16, 0xb6, 0x6b, 0xd1, 0x69, 0x68, 0x81, 0x2f, - 0x42, 0xda, 0xbf, 0xe4, 0x94, 0x29, 0x13, 0xf9, 0xa2, 0x7f, 0x17, 0xd6, 0xd1, 0xff, 0x72, 0xb2, - 0xa6, 0xed, 0xe5, 0x1f, 0x96, 0x1b, 0x31, 0xa2, 0xe4, 0xf9, 0x1a, 0x1d, 0xa1, 0x6f, 0xa5, 0xbe, - 0x7c, 0xb1, 0xbb, 0x66, 0x48, 0x70, 0xdd, 0x81, 0x4c, 0xcb, 0xf1, 0x06, 0x4f, 0xdb, 0x87, 0x91, - 0x23, 0xda, 0xcc, 0x11, 0xfd, 0x14, 0x36, 0x7d, 0x12, 0x70, 0x93, 0x51, 0x6e, 0x8e, 0xf0, 0x14, - 0xb8, 0x69, 0xfe, 0xe1, 0x6e, 0xe3, 0x66, 0x1c, 0x1a, 0x73, 0x87, 0x55, 0xbb, 0x14, 0xfd, 0xb8, - 0xb0, 0xfe, 0xef, 0x14, 0xa4, 0x15, 0x19, 0x3f, 0x86, 0x8c, 0xa2, 0x15, 0x37, 0xcc, 0x3f, 0xbc, - 0x1f, 0x5f, 0x51, 0xa9, 0x1a, 0x07, 0x9e, 0xcb, 0xa8, 0xcb, 0x26, 0x4c, 0xad, 0x17, 0xda, 0xe8, - 0xdf, 0x82, 0xec, 0x60, 0x44, 0x6c, 0xd7, 0xb4, 0x2d, 0xf4, 0x28, 0xd7, 0xca, 0xbf, 0x7c, 0xb1, - 0x9b, 0x39, 0x10, 0xb2, 0xf6, 0xa1, 0x91, 0x41, 0x65, 0xdb, 0xd2, 0x6f, 0x43, 0x7a, 0x44, 0xed, - 0xe1, 0x88, 0x23, 0x2d, 0x49, 0x43, 0xbd, 0xe9, 0x3f, 0x80, 0x94, 0x48, 0x88, 0x72, 0x0a, 0xf7, - 0xae, 0x34, 0x64, 0xb6, 0x34, 0xc2, 0x6c, 0x69, 0xf4, 0xc2, 0x6c, 0x69, 0x65, 0xc5, 0xc6, 0xcf, - 0xff, 0xb1, 0xab, 0x19, 0x68, 0xa1, 0x1f, 0x40, 0xd1, 0x21, 0x8c, 0x9b, 0x7d, 0x41, 0x9b, 0xd8, - 0x7e, 0x1d, 0x97, 0xd8, 0x59, 0x24, 0x44, 0x11, 0xab, 0x5c, 0xcf, 0x0b, 0x2b, 0x29, 0xb2, 0xf4, - 0x3d, 0x28, 0xe1, 0x22, 0x03, 0x6f, 0x3c, 0xb6, 0xb9, 0x89, 0xbc, 0xa7, 0x91, 0xf7, 0x0d, 0x21, - 0x3f, 0x40, 0xf1, 0xb1, 0x88, 0xc0, 0x5d, 0xc8, 0x59, 0x84, 0x13, 0x09, 0xc9, 0x20, 0x24, 0x2b, - 0x04, 0xa8, 0x7c, 0x0f, 0x36, 0xa3, 0xac, 0x63, 0x12, 0x92, 0x95, 0xab, 0xcc, 0xc4, 0x08, 0x7c, - 0x00, 0xdb, 0x2e, 0x9d, 0x72, 0xf3, 0x26, 0x3a, 0x87, 0x68, 0x5d, 0xe8, 0x1e, 0xcf, 0x5b, 0x7c, - 0x13, 0x36, 0x06, 0x21, 0xf9, 0x12, 0x0b, 0x88, 0x2d, 0x46, 0x52, 0x84, 0xed, 0x40, 0x96, 0xf8, - 0xbe, 0x04, 0xe4, 0x11, 0x90, 0x21, 0xbe, 0x8f, 0xaa, 0x0f, 0x60, 0x0b, 0xcf, 0x18, 0x50, 0x36, - 0x71, 0xb8, 0x5a, 0xa4, 0x80, 0x98, 0x4d, 0xa1, 0x30, 0xa4, 0x1c, 0xb1, 0xdf, 0x80, 0x22, 0xbd, - 0xb0, 0x2d, 0xea, 0x0e, 0xa8, 0xc4, 0x15, 0x11, 0x57, 0x08, 0x85, 0x08, 0x7a, 0x1f, 0x4a, 0x7e, - 0xe0, 0xf9, 0x1e, 0xa3, 0x81, 0x49, 0x2c, 0x2b, 0xa0, 0x8c, 0x95, 0x37, 0xe4, 0x7a, 0xa1, 0xbc, - 0x29, 0xc5, 0xf5, 0x17, 0x1a, 0xa4, 0x0e, 0x09, 0x27, 0x7a, 0x09, 0x92, 0x7c, 0xca, 0xca, 0x5a, - 0x2d, 0xb9, 0x57, 0x30, 0xc4, 0xa3, 0xfe, 0x09, 0x64, 0xc3, 0x55, 0x55, 0xa9, 0x54, 0x17, 0x43, - 0x77, 0xa4, 0x10, 0x27, 0x36, 0xe3, 0x2a, 0x7e, 0x91, 0x95, 0xfe, 0x23, 0xc8, 0x8e, 0x29, 0x63, - 0x64, 0x48, 0x59, 0x94, 0x3f, 0x0b, 0x2b, 0x9c, 0x2a, 0x44, 0x68, 0x1d, 0x5a, 0x88, 0x50, 0x78, - 0x81, 0x3d, 0xb4, 0x5d, 0xe2, 0x98, 0xec, 0xd7, 0x13, 0x12, 0x50, 0x93, 0xd9, 0xcf, 0x28, 0xa6, - 0x51, 0xca, 0xd0, 0x43, 0x5d, 0x17, 0x55, 0x5d, 0xfb, 0x19, 0x8d, 0x0a, 0x33, 0x1d, 0xeb, 0x10, - 0xcf, 0x13, 0x70, 0xeb, 0x70, 0xe2, 0x3b, 0xf6, 0x80, 0x70, 0xfa, 0xd8, 0xe3, 0x34, 0xf4, 0x58, - 0xff, 0x36, 0xa4, 0x2f, 0x3c, 0x4e, 0x4d, 0xa2, 0xea, 0xea, 0xf6, 0xa2, 0x6f, 0x02, 0x6f, 0xac, - 0x0b, 0x54, 0x33, 0x82, 0xf7, 0x55, 0x61, 0xbf, 0x16, 0xde, 0xd2, 0x3f, 0x02, 0x1d, 0xdb, 0x96, - 0x79, 0xe1, 0x71, 0xdb, 0x1d, 0x9a, 0xbe, 0xf7, 0x05, 0x0d, 0x54, 0x6d, 0x95, 0x50, 0xf3, 0x18, - 0x15, 0x1d, 0x21, 0x9f, 0xcb, 0x4f, 0x05, 0x4d, 0x21, 0x74, 0x96, 0x9f, 0x12, 0xd8, 0x82, 0x5c, - 0xd4, 0x9f, 0x55, 0x41, 0xbd, 0x59, 0x4d, 0xce, 0xcc, 0xea, 0x7f, 0x49, 0xc0, 0xce, 0x89, 0x28, - 0xee, 0x03, 0xc7, 0xa6, 0x2e, 0x6f, 0x72, 0x4e, 0x06, 0x4f, 0x23, 0x5a, 0xda, 0xb0, 0x35, 0xf0, - 0xdc, 0x27, 0x8e, 0x3d, 0x40, 0xbf, 0xb1, 0x7a, 0x15, 0x43, 0xf7, 0x16, 0x8f, 0x8c, 0xeb, 0x60, - 0xb1, 0x1a, 0xa5, 0x98, 0x19, 0x4a, 0x44, 0xb2, 0x8a, 0xba, 0xf5, 0x5c, 0x53, 0xb5, 0x96, 0x04, - 0x9e, 0xa9, 0x20, 0x85, 0xc7, 0xb2, 0xc1, 0x9c, 0xc1, 0x76, 0xff, 0xf2, 0x19, 0x71, 0xb9, 0xed, - 0xd2, 0x58, 0xd9, 0x95, 0x93, 0xb5, 0xe4, 0x5e, 0xfe, 0xe1, 0xdd, 0x25, 0x2c, 0x87, 0x18, 0xe3, - 0x6b, 0x91, 0xe1, 0xac, 0x26, 0x57, 0x10, 0x9f, 0x5a, 0x41, 0xfc, 0xbb, 0xe0, 0xf3, 0x5f, 0x1a, - 0x64, 0x23, 0xfa, 0x08, 0xdc, 0xb1, 0xc2, 0x74, 0x33, 0x31, 0x61, 0xa2, 0x22, 0x92, 0x24, 0xbe, - 0xb7, 0x78, 0xa2, 0xa5, 0xf9, 0x79, 0xbc, 0x66, 0xdc, 0xb2, 0x96, 0x26, 0xae, 0x0b, 0xf7, 0x1c, - 0x41, 0x9d, 0x39, 0xc0, 0xf8, 0x99, 0x04, 0x03, 0x38, 0xdb, 0x47, 0xe6, 0xe7, 0x87, 0x2b, 0x82, - 0xb5, 0x2c, 0xe8, 0xc7, 0x6b, 0xc6, 0x8e, 0xb3, 0x4a, 0xd9, 0x5a, 0x87, 0x24, 0x9b, 0x8c, 0xeb, - 0x27, 0x50, 0x88, 0x57, 0xbb, 0xa8, 0xee, 0xd8, 0xd1, 0x92, 0xcb, 0xab, 0x3b, 0x5a, 0xe4, 0x46, - 0x6f, 0xa8, 0xff, 0x14, 0xb2, 0x61, 0xe5, 0xeb, 0x3f, 0x81, 0x62, 0x58, 0xf5, 0xa6, 0x63, 0x33, - 0xae, 0x96, 0xdb, 0x59, 0xd9, 0x2c, 0x8c, 0x42, 0x88, 0x17, 0x9e, 0xd4, 0x3f, 0x81, 0x8c, 0x52, - 0xe8, 0x5f, 0x87, 0x82, 0x4b, 0xc6, 0x94, 0xf9, 0x64, 0x40, 0xc5, 0xcc, 0x91, 0x33, 0x3a, 0x1f, - 0xc9, 0xda, 0x96, 0xe8, 0x12, 0x62, 0x2e, 0x84, 0xf7, 0x08, 0xf1, 0x5c, 0xff, 0x4f, 0x02, 0x52, - 0x82, 0x63, 0xfd, 0x63, 0x48, 0x89, 0x9d, 0xd0, 0x6e, 0x63, 0xd9, 0xf0, 0xee, 0xda, 0x43, 0x97, - 0x5a, 0xa7, 0x6c, 0xd8, 0xbb, 0xf4, 0xa9, 0x81, 0xe0, 0xd8, 0xec, 0x4c, 0xcc, 0xcd, 0xce, 0x6d, - 0x58, 0x0f, 0xbc, 0x89, 0x6b, 0x61, 0xd9, 0xaf, 0x1b, 0xf2, 0x45, 0x3f, 0x82, 0x6c, 0x34, 0x12, - 0x53, 0xff, 0x6b, 0x24, 0x6e, 0x0a, 0xda, 0xc4, 0xc0, 0x56, 0x02, 0x23, 0xd3, 0x57, 0x93, 0xf1, - 0x1d, 0x64, 0xae, 0xfe, 0x21, 0x6c, 0xcd, 0xda, 0x4e, 0x38, 0x29, 0x64, 0xf7, 0x2c, 0x45, 0x0a, - 0x35, 0x2a, 0xe6, 0x7b, 0x94, 0xbc, 0x6d, 0x65, 0xf0, 0x5c, 0xb3, 0x1e, 0xd5, 0xc6, 0x6b, 0xd7, - 0x3d, 0xc8, 0x31, 0x7b, 0xe8, 0x12, 0x3e, 0x09, 0xa8, 0x1a, 0xb3, 0x33, 0x41, 0xfd, 0x4f, 0x1a, - 0xa4, 0xe5, 0xd8, 0x8e, 0xf1, 0xa6, 0x2d, 0xe7, 0x2d, 0xb1, 0x8a, 0xb7, 0xe4, 0xdb, 0xf3, 0xd6, - 0x04, 0x88, 0x9c, 0x11, 0x63, 0x69, 0x45, 0x97, 0x91, 0x2e, 0x76, 0xed, 0xa1, 0xca, 0xdc, 0x98, - 0x51, 0xfd, 0xef, 0x1a, 0xe4, 0x22, 0xbd, 0xde, 0x84, 0x62, 0xe8, 0x97, 0xf9, 0xc4, 0x21, 0x43, - 0x95, 0x3b, 0xf7, 0x57, 0x3a, 0xf7, 0xa9, 0x43, 0x86, 0x46, 0x5e, 0xf9, 0x23, 0x5e, 0x96, 0xc7, - 0x21, 0xb1, 0x22, 0x0e, 0x73, 0x81, 0x4f, 0xbe, 0x5d, 0xe0, 0xe7, 0x42, 0x94, 0xba, 0x19, 0xa2, - 0x3f, 0x26, 0x20, 0xdb, 0xc1, 0x8b, 0x02, 0x71, 0xfe, 0x1f, 0x15, 0x71, 0x17, 0x72, 0xbe, 0xe7, - 0x98, 0x52, 0x93, 0x42, 0x4d, 0xd6, 0xf7, 0x1c, 0x63, 0x21, 0xec, 0xeb, 0xef, 0xa8, 0x5c, 0xd2, - 0xef, 0x80, 0xb5, 0xcc, 0x4d, 0xd6, 0x02, 0x28, 0x48, 0x2a, 0xd4, 0xc5, 0xfd, 0x81, 0xe0, 0x00, - 0xbf, 0x04, 0xb4, 0xc5, 0x0f, 0x0d, 0xe9, 0xb6, 0x44, 0x1a, 0x0a, 0x27, 0x2c, 0xe4, 0x3d, 0x57, - 0xb5, 0xf0, 0xf2, 0xaa, 0xb4, 0x34, 0x14, 0xae, 0xfe, 0x5b, 0x0d, 0x60, 0x36, 0x82, 0xc5, 0x95, - 0x9b, 0xa1, 0x0b, 0xe6, 0xdc, 0xce, 0xd5, 0x55, 0x41, 0x53, 0xfb, 0x17, 0x58, 0xdc, 0xef, 0x03, - 0x28, 0xce, 0x92, 0x91, 0xd1, 0xd0, 0x99, 0xea, 0x6b, 0x26, 0x71, 0x97, 0x72, 0xa3, 0x70, 0x11, - 0x7b, 0xab, 0xff, 0x59, 0x83, 0x1c, 0xfa, 0x74, 0x4a, 0x39, 0x99, 0x8b, 0xa1, 0xf6, 0xf6, 0x31, - 0xbc, 0x0f, 0x20, 0x97, 0xc1, 0x7b, 0xa0, 0xcc, 0xac, 0x1c, 0x4a, 0xf0, 0xfa, 0xf7, 0xbd, 0x88, - 0xf0, 0xe4, 0xeb, 0x09, 0x57, 0x25, 0x1d, 0xd2, 0x7e, 0x07, 0x32, 0xee, 0x64, 0x6c, 0x8a, 0xeb, - 0xaf, 0xbc, 0x26, 0xa4, 0xdd, 0xc9, 0xb8, 0x37, 0x65, 0xf5, 0x5f, 0x41, 0xa6, 0x37, 0xc5, 0x6f, - 0x41, 0x91, 0xa2, 0x81, 0xe7, 0xa9, 0x0f, 0x10, 0x39, 0x54, 0xb2, 0x42, 0x80, 0xf7, 0xed, 0x25, - 0x13, 0x45, 0x6f, 0xbc, 0xe1, 0x57, 0x66, 0xf8, 0x7d, 0xf9, 0x08, 0xf2, 0xa7, 0xc4, 0x71, 0x28, - 0xe1, 0xd4, 0xea, 0x4d, 0xc5, 0x77, 0x4f, 0x74, 0xf9, 0xe5, 0xd3, 0xf8, 0xb6, 0x1b, 0xa1, 0xbc, - 0x37, 0xc5, 0xcd, 0x37, 0x20, 0xc1, 0xa7, 0x6a, 0xeb, 0x04, 0x9f, 0x7e, 0xf0, 0x57, 0x0d, 0xf2, - 0xb1, 0x46, 0xa3, 0x7f, 0x07, 0x6e, 0xb5, 0x4e, 0xce, 0x0f, 0x3e, 0x33, 0xdb, 0x87, 0xe6, 0xa7, - 0x27, 0xcd, 0x47, 0xe6, 0xe7, 0x67, 0x9f, 0x9d, 0x9d, 0xff, 0xfc, 0xac, 0xb4, 0x56, 0xb9, 0x7d, - 0x75, 0x5d, 0xd3, 0x63, 0xd8, 0xcf, 0xdd, 0xa7, 0xae, 0xf7, 0x85, 0xab, 0xef, 0xc3, 0xf6, 0xbc, - 0x49, 0xb3, 0xd5, 0x3d, 0x3a, 0xeb, 0x95, 0xb4, 0xca, 0xad, 0xab, 0xeb, 0xda, 0x56, 0xcc, 0xa2, - 0xd9, 0x67, 0xd4, 0xe5, 0x8b, 0x06, 0x07, 0xe7, 0xa7, 0xa7, 0xed, 0x5e, 0x29, 0xb1, 0x60, 0xa0, - 0x3a, 0xff, 0xfb, 0xb0, 0x35, 0x6f, 0x70, 0xd6, 0x3e, 0x29, 0x25, 0x2b, 0xfa, 0xd5, 0x75, 0x6d, - 0x23, 0x86, 0x3e, 0xb3, 0x9d, 0x4a, 0xf6, 0x37, 0xbf, 0xab, 0xae, 0xfd, 0xe1, 0xf7, 0x55, 0x4d, - 0x9c, 0xac, 0x38, 0xd7, 0x6c, 0xf4, 0x8f, 0xe0, 0x4e, 0xb7, 0xfd, 0xe8, 0xec, 0xe8, 0xd0, 0x3c, - 0xed, 0x3e, 0x32, 0x7b, 0xbf, 0xe8, 0x1c, 0xc5, 0x4e, 0xb7, 0x79, 0x75, 0x5d, 0xcb, 0xab, 0x23, - 0xad, 0x42, 0x77, 0x8c, 0xa3, 0xc7, 0xe7, 0xbd, 0xa3, 0x92, 0x26, 0xd1, 0x9d, 0x80, 0x8a, 0x2b, - 0x1b, 0xa2, 0x1f, 0xc0, 0xce, 0x12, 0x74, 0x74, 0xb0, 0xad, 0xab, 0xeb, 0x5a, 0xb1, 0x13, 0x50, - 0x59, 0x88, 0x68, 0xd1, 0x80, 0xf2, 0xa2, 0xc5, 0x79, 0xe7, 0xbc, 0xdb, 0x3c, 0x29, 0xd5, 0x2a, - 0xa5, 0xab, 0xeb, 0x5a, 0x21, 0xec, 0xaa, 0x02, 0x3f, 0x3b, 0x59, 0xeb, 0x67, 0x5f, 0xbe, 0xac, - 0x6a, 0x5f, 0xbd, 0xac, 0x6a, 0xff, 0x7c, 0x59, 0xd5, 0x9e, 0xbf, 0xaa, 0xae, 0x7d, 0xf5, 0xaa, - 0xba, 0xf6, 0xb7, 0x57, 0xd5, 0xb5, 0x5f, 0x7e, 0x7f, 0x68, 0xf3, 0xd1, 0xa4, 0xdf, 0x18, 0x78, - 0xe3, 0xfd, 0xf8, 0x1f, 0x29, 0xb3, 0x47, 0xf9, 0x87, 0xce, 0xcd, 0x3f, 0x59, 0xfa, 0x69, 0x94, - 0x7f, 0xfc, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x08, 0x7d, 0x29, 0x8d, 0x25, 0x12, 0x00, 0x00, + // 1805 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcd, 0x6f, 0x1b, 0x5b, + 0x15, 0xcf, 0xd8, 0x8e, 0x3f, 0x8e, 0xed, 0xc4, 0x19, 0xd2, 0xd6, 0x71, 0x5b, 0xc7, 0x0c, 0x82, + 0x97, 0xf7, 0x81, 0x53, 0xf2, 0x10, 0x1f, 0x12, 0xa0, 0x67, 0x27, 0x79, 0x8d, 0x79, 0xb1, 0x63, + 0xc6, 0x7e, 0x45, 0xb0, 0x19, 0x5d, 0x7b, 0x6e, 0x9c, 0x51, 0xc7, 0x33, 0xc3, 0xcc, 0x75, 0xea, + 0xf4, 0x2f, 0x40, 0x59, 0x75, 0xc5, 0x2e, 0x2b, 0x58, 0xb0, 0xe7, 0x1f, 0x40, 0xac, 0xde, 0x06, + 0xa9, 0x3b, 0xd8, 0x50, 0x50, 0x8b, 0x10, 0x7f, 0x06, 0xba, 0xe7, 0xde, 0x19, 0x8f, 0x63, 0xbb, + 0xa0, 0xaa, 0x62, 0x63, 0xcd, 0x3d, 0xe7, 0x77, 0xee, 0x3d, 0xf7, 0x7c, 0x5f, 0xc3, 0x03, 0x46, + 0x1d, 0x93, 0xfa, 0x63, 0xcb, 0x61, 0xfb, 0xec, 0xca, 0xa3, 0x81, 0xf8, 0xad, 0x7b, 0xbe, 0xcb, + 0x5c, 0xb5, 0x34, 0xe3, 0xd6, 0x91, 0x5e, 0xd9, 0x1e, 0xb9, 0x23, 0x17, 0x99, 0xfb, 0xfc, 0x4b, + 0xe0, 0x2a, 0xbb, 0x23, 0xd7, 0x1d, 0xd9, 0x74, 0x1f, 0x57, 0x83, 0xc9, 0xf9, 0x3e, 0xb3, 0xc6, + 0x34, 0x60, 0x64, 0xec, 0x49, 0xc0, 0xc3, 0xd8, 0x31, 0x43, 0xff, 0xca, 0x63, 0x2e, 0xc7, 0xba, + 0xe7, 0x92, 0x5d, 0x8d, 0xb1, 0x2f, 0xa9, 0x1f, 0x58, 0xae, 0x13, 0xd7, 0xa3, 0x52, 0x5b, 0xd0, + 0xf2, 0x92, 0xd8, 0x96, 0x49, 0x98, 0xeb, 0x0b, 0x84, 0xf6, 0x43, 0x28, 0x76, 0x89, 0xcf, 0x7a, + 0x94, 0x9d, 0x50, 0x62, 0x52, 0x5f, 0xdd, 0x86, 0x75, 0xe6, 0x32, 0x62, 0x97, 0x95, 0x9a, 0xb2, + 0x57, 0xd4, 0xc5, 0x42, 0x55, 0x21, 0x75, 0x41, 0x82, 0x8b, 0x72, 0xa2, 0xa6, 0xec, 0x15, 0x74, + 0xfc, 0xd6, 0x2e, 0x20, 0xc5, 0x45, 0xb9, 0x84, 0xe5, 0x98, 0x74, 0x1a, 0x4a, 0xe0, 0x82, 0x53, + 0x07, 0x57, 0x8c, 0x06, 0x52, 0x44, 0x2c, 0xd4, 0xef, 0xc2, 0x3a, 0xea, 0x5f, 0x4e, 0xd6, 0x94, + 0xbd, 0xfc, 0x41, 0xb9, 0x1e, 0x33, 0x94, 0xb8, 0x5f, 0xbd, 0xcb, 0xf9, 0xcd, 0xd4, 0x57, 0xaf, + 0x76, 0xd7, 0x74, 0x01, 0xd6, 0x6c, 0xc8, 0x34, 0x6d, 0x77, 0xf8, 0xb4, 0x75, 0x14, 0x29, 0xa2, + 0xcc, 0x14, 0x51, 0xdb, 0xb0, 0xe9, 0x11, 0x9f, 0x19, 0x01, 0x65, 0xc6, 0x05, 0xde, 0x02, 0x0f, + 0xcd, 0x1f, 0xec, 0xd6, 0x6f, 0xfb, 0xa1, 0x3e, 0x77, 0x59, 0x79, 0x4a, 0xd1, 0x8b, 0x13, 0xb5, + 0x7f, 0xa5, 0x20, 0x2d, 0x8d, 0xf1, 0x63, 0xc8, 0x48, 0xb3, 0xe2, 0x81, 0xf9, 0x83, 0x87, 0xf1, + 0x1d, 0x25, 0xab, 0x7e, 0xe8, 0x3a, 0x01, 0x75, 0x82, 0x49, 0x20, 0xf7, 0x0b, 0x65, 0xd4, 0x6f, + 0x41, 0x76, 0x78, 0x41, 0x2c, 0xc7, 0xb0, 0x4c, 0xd4, 0x28, 0xd7, 0xcc, 0xbf, 0x7e, 0xb5, 0x9b, + 0x39, 0xe4, 0xb4, 0xd6, 0x91, 0x9e, 0x41, 0x66, 0xcb, 0x54, 0xef, 0x42, 0xfa, 0x82, 0x5a, 0xa3, + 0x0b, 0x86, 0x66, 0x49, 0xea, 0x72, 0xa5, 0xfe, 0x00, 0x52, 0x3c, 0x20, 0xca, 0x29, 0x3c, 0xbb, + 0x52, 0x17, 0xd1, 0x52, 0x0f, 0xa3, 0xa5, 0xde, 0x0f, 0xa3, 0xa5, 0x99, 0xe5, 0x07, 0xbf, 0xf8, + 0xfb, 0xae, 0xa2, 0xa3, 0x84, 0x7a, 0x08, 0x45, 0x9b, 0x04, 0xcc, 0x18, 0x70, 0xb3, 0xf1, 0xe3, + 0xd7, 0x71, 0x8b, 0x9d, 0x45, 0x83, 0x48, 0xc3, 0x4a, 0xd5, 0xf3, 0x5c, 0x4a, 0x90, 0x4c, 0x75, + 0x0f, 0x4a, 0xb8, 0xc9, 0xd0, 0x1d, 0x8f, 0x2d, 0x66, 0xa0, 0xdd, 0xd3, 0x68, 0xf7, 0x0d, 0x4e, + 0x3f, 0x44, 0xf2, 0x09, 0xf7, 0xc0, 0x7d, 0xc8, 0x99, 0x84, 0x11, 0x01, 0xc9, 0x20, 0x24, 0xcb, + 0x09, 0xc8, 0xfc, 0x00, 0x36, 0xa3, 0xa8, 0x0b, 0x04, 0x24, 0x2b, 0x76, 0x99, 0x91, 0x11, 0xf8, + 0x08, 0xb6, 0x1d, 0x3a, 0x65, 0xc6, 0x6d, 0x74, 0x0e, 0xd1, 0x2a, 0xe7, 0x3d, 0x99, 0x97, 0xf8, + 0x26, 0x6c, 0x0c, 0x43, 0xe3, 0x0b, 0x2c, 0x20, 0xb6, 0x18, 0x51, 0x11, 0xb6, 0x03, 0x59, 0xe2, + 0x79, 0x02, 0x90, 0x47, 0x40, 0x86, 0x78, 0x1e, 0xb2, 0x3e, 0x82, 0x2d, 0xbc, 0xa3, 0x4f, 0x83, + 0x89, 0xcd, 0xe4, 0x26, 0x05, 0xc4, 0x6c, 0x72, 0x86, 0x2e, 0xe8, 0x88, 0xfd, 0x06, 0x14, 0xe9, + 0xa5, 0x65, 0x52, 0x67, 0x48, 0x05, 0xae, 0x88, 0xb8, 0x42, 0x48, 0x44, 0xd0, 0x87, 0x50, 0xf2, + 0x7c, 0xd7, 0x73, 0x03, 0xea, 0x1b, 0xc4, 0x34, 0x7d, 0x1a, 0x04, 0xe5, 0x0d, 0xb1, 0x5f, 0x48, + 0x6f, 0x08, 0xb2, 0xf6, 0x4a, 0x81, 0xd4, 0x11, 0x61, 0x44, 0x2d, 0x41, 0x92, 0x4d, 0x83, 0xb2, + 0x52, 0x4b, 0xee, 0x15, 0x74, 0xfe, 0xa9, 0x7e, 0x06, 0xd9, 0x70, 0x57, 0x99, 0x2a, 0xd5, 0x45, + 0xd7, 0x1d, 0x4b, 0xc4, 0xa9, 0x15, 0x30, 0xe9, 0xbf, 0x48, 0x4a, 0xfd, 0x11, 0x64, 0xc7, 0x34, + 0x08, 0xc8, 0x88, 0x06, 0x51, 0xfc, 0x2c, 0xec, 0xd0, 0x96, 0x88, 0x50, 0x3a, 0x94, 0xe0, 0xae, + 0x70, 0x7d, 0x6b, 0x64, 0x39, 0xc4, 0x36, 0x82, 0x5f, 0x4d, 0x88, 0x4f, 0x8d, 0xc0, 0x7a, 0x4e, + 0x31, 0x8c, 0x52, 0xba, 0x1a, 0xf2, 0x7a, 0xc8, 0xea, 0x59, 0xcf, 0x69, 0x94, 0x98, 0xe9, 0x58, + 0x85, 0x78, 0x91, 0x80, 0x3b, 0x47, 0x13, 0xcf, 0xb6, 0x86, 0x84, 0xd1, 0x27, 0x2e, 0xa3, 0xa1, + 0xc6, 0xea, 0xb7, 0x21, 0x7d, 0xe9, 0x32, 0x6a, 0x10, 0x99, 0x57, 0x77, 0x17, 0x75, 0xe3, 0x78, + 0x7d, 0x9d, 0xa3, 0x1a, 0x11, 0x7c, 0x20, 0x13, 0xfb, 0xad, 0xf0, 0xa6, 0xfa, 0x09, 0xa8, 0x58, + 0xb6, 0x8c, 0x4b, 0x97, 0x59, 0xce, 0xc8, 0xf0, 0xdc, 0x67, 0xd4, 0x97, 0xb9, 0x55, 0x42, 0xce, + 0x13, 0x64, 0x74, 0x39, 0x7d, 0x2e, 0x3e, 0x25, 0x34, 0x85, 0xd0, 0x59, 0x7c, 0x0a, 0x60, 0x13, + 0x72, 0x51, 0x7d, 0x96, 0x09, 0xf5, 0xbf, 0xe5, 0xe4, 0x4c, 0x4c, 0xfb, 0x73, 0x02, 0x76, 0x4e, + 0x79, 0x72, 0x1f, 0xda, 0x16, 0x75, 0x58, 0x83, 0x31, 0x32, 0x7c, 0x1a, 0x99, 0xa5, 0x05, 0x5b, + 0x43, 0xd7, 0x39, 0xb7, 0xad, 0x21, 0xea, 0x8d, 0xd9, 0x2b, 0x2d, 0xf4, 0x60, 0xf1, 0xca, 0xb8, + 0x0f, 0x26, 0xab, 0x5e, 0x8a, 0x89, 0x21, 0x85, 0x07, 0x2b, 0xcf, 0x5b, 0xd7, 0x31, 0x64, 0x69, + 0x49, 0xe0, 0x9d, 0x0a, 0x82, 0x78, 0x22, 0x0a, 0x4c, 0x07, 0xb6, 0x07, 0x57, 0xcf, 0x89, 0xc3, + 0x2c, 0x87, 0xc6, 0xd2, 0xae, 0x9c, 0xac, 0x25, 0xf7, 0xf2, 0x07, 0xf7, 0x97, 0x58, 0x39, 0xc4, + 0xe8, 0x5f, 0x8b, 0x04, 0x67, 0x39, 0xb9, 0xc2, 0xf0, 0xa9, 0x15, 0x86, 0x7f, 0x1f, 0xf6, 0xfc, + 0xa7, 0x02, 0xd9, 0xc8, 0x7c, 0x04, 0xee, 0x99, 0x61, 0xb8, 0x19, 0x18, 0x30, 0x51, 0x12, 0x09, + 0x23, 0x7e, 0xb0, 0x78, 0xa3, 0xa5, 0xf1, 0x79, 0xb2, 0xa6, 0xdf, 0x31, 0x97, 0x06, 0xae, 0x03, + 0x0f, 0x6c, 0x6e, 0x3a, 0x63, 0x88, 0xfe, 0x33, 0x08, 0x3a, 0x70, 0x76, 0x8e, 0x88, 0xcf, 0x8f, + 0x57, 0x38, 0x6b, 0x99, 0xd3, 0x4f, 0xd6, 0xf4, 0x1d, 0x7b, 0x15, 0xb3, 0xb9, 0x0e, 0xc9, 0x60, + 0x32, 0xd6, 0x4e, 0xa1, 0x10, 0xcf, 0x76, 0x9e, 0xdd, 0xb1, 0xab, 0x25, 0x97, 0x67, 0x77, 0xb4, + 0xc9, 0xad, 0xda, 0xa0, 0xfd, 0x14, 0xb2, 0x61, 0xe6, 0xab, 0x3f, 0x81, 0x62, 0x98, 0xf5, 0x86, + 0x6d, 0x05, 0x4c, 0x6e, 0xb7, 0xb3, 0xb2, 0x58, 0xe8, 0x85, 0x10, 0xcf, 0x35, 0xd1, 0x3e, 0x83, + 0x8c, 0x64, 0xa8, 0x5f, 0x87, 0x82, 0x43, 0xc6, 0x34, 0xf0, 0xc8, 0x90, 0xf2, 0x9e, 0x23, 0x7a, + 0x74, 0x3e, 0xa2, 0xb5, 0x4c, 0x5e, 0x25, 0x78, 0x5f, 0x08, 0xe7, 0x08, 0xfe, 0xad, 0xfd, 0x3b, + 0x01, 0x29, 0x6e, 0x63, 0xf5, 0x53, 0x48, 0xf1, 0x93, 0x50, 0x6e, 0x63, 0x59, 0xf3, 0xee, 0x59, + 0x23, 0x87, 0x9a, 0xed, 0x60, 0xd4, 0xbf, 0xf2, 0xa8, 0x8e, 0xe0, 0x58, 0xef, 0x4c, 0xcc, 0xf5, + 0xce, 0x6d, 0x58, 0xf7, 0xdd, 0x89, 0x63, 0x62, 0xda, 0xaf, 0xeb, 0x62, 0xa1, 0x1e, 0x43, 0x36, + 0x6a, 0x89, 0xa9, 0xff, 0xd6, 0x12, 0x37, 0xb9, 0xd9, 0x78, 0xc3, 0x96, 0x04, 0x3d, 0x33, 0x90, + 0x9d, 0xf1, 0x3d, 0x44, 0xae, 0xfa, 0x31, 0x6c, 0xcd, 0xca, 0x4e, 0xd8, 0x29, 0x44, 0xf5, 0x2c, + 0x45, 0x0c, 0xd9, 0x2a, 0xe6, 0x6b, 0x94, 0x98, 0xb6, 0x32, 0x78, 0xaf, 0x59, 0x8d, 0x6a, 0xe1, + 0xd8, 0xf5, 0x00, 0x72, 0x81, 0x35, 0x72, 0x08, 0x9b, 0xf8, 0x54, 0xb6, 0xd9, 0x19, 0x41, 0xfb, + 0xa3, 0x02, 0x69, 0xd1, 0xb6, 0x63, 0x76, 0x53, 0x96, 0xdb, 0x2d, 0xb1, 0xca, 0x6e, 0xc9, 0x77, + 0xb7, 0x5b, 0x03, 0x20, 0x52, 0x86, 0xb7, 0xa5, 0x15, 0x55, 0x46, 0xa8, 0xd8, 0xb3, 0x46, 0x32, + 0x72, 0x63, 0x42, 0xda, 0xdf, 0x14, 0xc8, 0x45, 0x7c, 0xb5, 0x01, 0xc5, 0x50, 0x2f, 0xe3, 0xdc, + 0x26, 0x23, 0x19, 0x3b, 0x0f, 0x57, 0x2a, 0xf7, 0xb9, 0x4d, 0x46, 0x7a, 0x5e, 0xea, 0xc3, 0x17, + 0xcb, 0xfd, 0x90, 0x58, 0xe1, 0x87, 0x39, 0xc7, 0x27, 0xdf, 0xcd, 0xf1, 0x73, 0x2e, 0x4a, 0xdd, + 0x76, 0xd1, 0x1f, 0x12, 0x90, 0xed, 0xe2, 0xa0, 0x40, 0xec, 0xff, 0x47, 0x46, 0xdc, 0x87, 0x9c, + 0xe7, 0xda, 0x86, 0xe0, 0xa4, 0x90, 0x93, 0xf5, 0x5c, 0x5b, 0x5f, 0x70, 0xfb, 0xfa, 0x7b, 0x4a, + 0x97, 0xf4, 0x7b, 0xb0, 0x5a, 0xe6, 0xb6, 0xd5, 0x7c, 0x28, 0x08, 0x53, 0xc8, 0xc1, 0xfd, 0x11, + 0xb7, 0x01, 0xbe, 0x04, 0x94, 0xc5, 0x87, 0x86, 0x50, 0x5b, 0x20, 0x75, 0x89, 0xe3, 0x12, 0x62, + 0xce, 0x95, 0x25, 0xbc, 0xbc, 0x2a, 0x2c, 0x75, 0x89, 0xd3, 0x7e, 0xa3, 0x00, 0xcc, 0x5a, 0x30, + 0x1f, 0xb9, 0x03, 0x54, 0xc1, 0x98, 0x3b, 0xb9, 0xba, 0xca, 0x69, 0xf2, 0xfc, 0x42, 0x10, 0xd7, + 0xfb, 0x10, 0x8a, 0xb3, 0x60, 0x0c, 0x68, 0xa8, 0x4c, 0xf5, 0x2d, 0x9d, 0xb8, 0x47, 0x99, 0x5e, + 0xb8, 0x8c, 0xad, 0xb4, 0x3f, 0x29, 0x90, 0x43, 0x9d, 0xda, 0x94, 0x91, 0x39, 0x1f, 0x2a, 0xef, + 0xee, 0xc3, 0x87, 0x00, 0x62, 0x1b, 0x9c, 0x03, 0x45, 0x64, 0xe5, 0x90, 0x82, 0xe3, 0xdf, 0xf7, + 0x22, 0x83, 0x27, 0xdf, 0x6e, 0x70, 0x99, 0xd2, 0xa1, 0xd9, 0xef, 0x41, 0xc6, 0x99, 0x8c, 0x0d, + 0x3e, 0xfe, 0x8a, 0x31, 0x21, 0xed, 0x4c, 0xc6, 0xfd, 0x69, 0xa0, 0x39, 0x90, 0xe9, 0x4f, 0xf1, + 0x2d, 0xc8, 0x43, 0xd4, 0x77, 0x9f, 0x19, 0xbe, 0xeb, 0xb2, 0x70, 0x48, 0xce, 0xfa, 0xee, 0x33, + 0x9d, 0xaf, 0x63, 0x1d, 0x25, 0x19, 0x76, 0x14, 0xf5, 0x00, 0xd2, 0xf8, 0x70, 0x0c, 0x07, 0x99, + 0x25, 0xbd, 0xb1, 0xd3, 0xee, 0xe3, 0xe6, 0xba, 0x44, 0x6a, 0x8f, 0x21, 0xdf, 0x26, 0xb6, 0x4d, + 0x09, 0xa3, 0x66, 0x7f, 0xca, 0xdf, 0x3e, 0xd1, 0x00, 0xcc, 0xa6, 0x46, 0xec, 0xcd, 0xb9, 0x11, + 0xd2, 0xfb, 0x53, 0x1c, 0xf8, 0x37, 0x20, 0xc1, 0xa6, 0xb2, 0x60, 0x24, 0xd8, 0x54, 0xa3, 0x90, + 0x0d, 0x37, 0xe7, 0x29, 0x17, 0x30, 0xe2, 0x8b, 0x1a, 0xbb, 0xae, 0x8b, 0x05, 0x1f, 0xf7, 0x69, + 0x54, 0x60, 0xf9, 0x27, 0xc7, 0x39, 0xae, 0x49, 0x85, 0xbe, 0x05, 0x5d, 0x2c, 0xf8, 0xbd, 0x6d, + 0x4a, 0xce, 0xc5, 0xe1, 0xa2, 0x50, 0x64, 0x39, 0x81, 0x1f, 0xfb, 0xd1, 0x5f, 0x14, 0xc8, 0xc7, + 0x6a, 0x9a, 0xfa, 0x1d, 0xb8, 0xd3, 0x3c, 0x3d, 0x3b, 0xfc, 0xc2, 0x68, 0x1d, 0x19, 0x9f, 0x9f, + 0x36, 0x1e, 0x1b, 0x5f, 0x76, 0xbe, 0xe8, 0x9c, 0xfd, 0xbc, 0x53, 0x5a, 0xab, 0xdc, 0xbd, 0xbe, + 0xa9, 0xa9, 0x31, 0xec, 0x97, 0xce, 0x53, 0xc7, 0x7d, 0xe6, 0xa8, 0xfb, 0xb0, 0x3d, 0x2f, 0xd2, + 0x68, 0xf6, 0x8e, 0x3b, 0xfd, 0x92, 0x52, 0xb9, 0x73, 0x7d, 0x53, 0xdb, 0x8a, 0x49, 0x34, 0x06, + 0x01, 0x75, 0xd8, 0xa2, 0xc0, 0xe1, 0x59, 0xbb, 0xdd, 0xea, 0x97, 0x12, 0x0b, 0x02, 0xb2, 0xc9, + 0x7c, 0x08, 0x5b, 0xf3, 0x02, 0x9d, 0xd6, 0x69, 0x29, 0x59, 0x51, 0xaf, 0x6f, 0x6a, 0x1b, 0x31, + 0x74, 0xc7, 0xb2, 0x2b, 0xd9, 0x5f, 0xff, 0xb6, 0xba, 0xf6, 0xfb, 0xdf, 0x55, 0x15, 0x7e, 0xb3, + 0xe2, 0x5c, 0x5d, 0x53, 0x3f, 0x81, 0x7b, 0xbd, 0xd6, 0xe3, 0xce, 0xf1, 0x91, 0xd1, 0xee, 0x3d, + 0x36, 0xfa, 0xbf, 0xe8, 0x1e, 0xc7, 0x6e, 0xb7, 0x79, 0x7d, 0x53, 0xcb, 0xcb, 0x2b, 0xad, 0x42, + 0x77, 0xf5, 0xe3, 0x27, 0x67, 0xfd, 0xe3, 0x92, 0x22, 0xd0, 0x5d, 0x9f, 0xf2, 0xe9, 0x10, 0xd1, + 0x8f, 0x60, 0x67, 0x09, 0x3a, 0xba, 0xd8, 0xd6, 0xf5, 0x4d, 0xad, 0xd8, 0xf5, 0xa9, 0xc8, 0x79, + 0x94, 0xa8, 0x43, 0x79, 0x51, 0xe2, 0xac, 0x7b, 0xd6, 0x6b, 0x9c, 0x96, 0x6a, 0x95, 0xd2, 0xf5, + 0x4d, 0xad, 0x10, 0x16, 0x70, 0x8e, 0x9f, 0xdd, 0xac, 0xf9, 0xb3, 0xaf, 0x5e, 0x57, 0x95, 0x97, + 0xaf, 0xab, 0xca, 0x3f, 0x5e, 0x57, 0x95, 0x17, 0x6f, 0xaa, 0x6b, 0x2f, 0xdf, 0x54, 0xd7, 0xfe, + 0xfa, 0xa6, 0xba, 0xf6, 0xcb, 0xef, 0x8f, 0x2c, 0x76, 0x31, 0x19, 0xd4, 0x87, 0xee, 0x78, 0x3f, + 0xfe, 0x9f, 0xcd, 0xec, 0x53, 0xfc, 0x77, 0x74, 0xfb, 0xff, 0x9c, 0x41, 0x1a, 0xe9, 0x9f, 0xfe, + 0x27, 0x00, 0x00, 0xff, 0xff, 0x6a, 0xf1, 0xb9, 0xe5, 0x90, 0x12, 0x00, 0x00, } func (m *PartSetHeader) Marshal() (dAtA []byte, err error) { @@ -2680,31 +2768,37 @@ func (m *TxProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Proof != nil { - { - size, err := m.Proof.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + 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 -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a } - i-- - dAtA[i] = 0x1a } if len(m.Data) > 0 { - i -= len(m.Data) - copy(dAtA[i:], m.Data) - i = encodeVarintTypes(dAtA, i, uint64(len(m.Data))) - i-- - dAtA[i] = 0x12 + 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] = 0x12 + } } - if len(m.RootHash) > 0 { - i -= len(m.RootHash) - copy(dAtA[i:], m.RootHash) - i = encodeVarintTypes(dAtA, i, uint64(len(m.RootHash))) - i-- - dAtA[i] = 0xa + if len(m.RowRoots) > 0 { + for iNdEx := len(m.RowRoots) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.RowRoots[iNdEx]) + copy(dAtA[i:], m.RowRoots[iNdEx]) + i = encodeVarintTypes(dAtA, i, uint64(len(m.RowRoots[iNdEx]))) + i-- + dAtA[i] = 0xa + } } return len(dAtA) - i, nil } @@ -2746,6 +2840,55 @@ func (m *MalleatedTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *NMTProof) 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 *NMTProof) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *NMTProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.LeafHash) > 0 { + i -= len(m.LeafHash) + copy(dAtA[i:], m.LeafHash) + i = encodeVarintTypes(dAtA, i, uint64(len(m.LeafHash))) + i-- + dAtA[i] = 0x22 + } + if len(m.Nodes) > 0 { + for iNdEx := len(m.Nodes) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Nodes[iNdEx]) + copy(dAtA[i:], m.Nodes[iNdEx]) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Nodes[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if m.End != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.End)) + i-- + dAtA[i] = 0x10 + } + if m.Start != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Start)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { offset -= sovTypes(v) base := offset @@ -3191,17 +3334,23 @@ func (m *TxProof) Size() (n int) { } var l int _ = l - l = len(m.RootHash) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) + if len(m.RowRoots) > 0 { + for _, b := range m.RowRoots { + l = len(b) + n += 1 + l + sovTypes(uint64(l)) + } } - l = len(m.Data) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) + if len(m.Data) > 0 { + for _, b := range m.Data { + l = len(b) + n += 1 + l + sovTypes(uint64(l)) + } } - if m.Proof != nil { - l = m.Proof.Size() - 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)) + } } return n } @@ -3223,6 +3372,31 @@ func (m *MalleatedTx) Size() (n int) { return n } +func (m *NMTProof) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Start != 0 { + n += 1 + sovTypes(uint64(m.Start)) + } + if m.End != 0 { + n += 1 + sovTypes(uint64(m.End)) + } + if len(m.Nodes) > 0 { + for _, b := range m.Nodes { + l = len(b) + n += 1 + l + sovTypes(uint64(l)) + } + } + l = len(m.LeafHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + func sovTypes(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -6322,7 +6496,7 @@ func (m *TxProof) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RootHash", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RowRoots", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -6349,10 +6523,8 @@ func (m *TxProof) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.RootHash = append(m.RootHash[:0], dAtA[iNdEx:postIndex]...) - if m.RootHash == nil { - m.RootHash = []byte{} - } + m.RowRoots = append(m.RowRoots, make([]byte, postIndex-iNdEx)) + copy(m.RowRoots[len(m.RowRoots)-1], dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { @@ -6383,14 +6555,12 @@ func (m *TxProof) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) - if m.Data == nil { - m.Data = []byte{} - } + m.Data = append(m.Data, make([]byte, postIndex-iNdEx)) + copy(m.Data[len(m.Data)-1], dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Proofs", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -6417,10 +6587,8 @@ func (m *TxProof) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Proof == nil { - m.Proof = &crypto.Proof{} - } - if err := m.Proof.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Proofs = append(m.Proofs, &NMTProof{}) + if err := m.Proofs[len(m.Proofs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -6563,6 +6731,160 @@ func (m *MalleatedTx) Unmarshal(dAtA []byte) error { } return nil } +func (m *NMTProof) 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: NMTProof: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NMTProof: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Start", wireType) + } + m.Start = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Start |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field End", wireType) + } + m.End = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.End |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Nodes", 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.Nodes = append(m.Nodes, make([]byte, postIndex-iNdEx)) + copy(m.Nodes[len(m.Nodes)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LeafHash", 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.LeafHash = append(m.LeafHash[:0], dAtA[iNdEx:postIndex]...) + if m.LeafHash == nil { + m.LeafHash = []byte{} + } + 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 skipTypes(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/proto/tendermint/types/types.proto b/proto/tendermint/types/types.proto index a1db322381..861e6515d9 100644 --- a/proto/tendermint/types/types.proto +++ b/proto/tendermint/types/types.proto @@ -196,9 +196,9 @@ message BlockMeta { // TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree. message TxProof { - bytes root_hash = 1; - bytes data = 2; - tendermint.crypto.Proof proof = 3; + repeated bytes row_roots = 1; + repeated bytes data = 2; + repeated NMTProof proofs = 3; } // MalleatedTx wraps a transaction that was derived from a different original @@ -208,3 +208,25 @@ message MalleatedTx { bytes original_tx_hash = 1; bytes tx = 2; } + +// 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 +// where that namespace would be. +message NMTProof { + // start index of this proof. + int32 start = 1; + // end index of this proof. + int32 end = 2; + // Nodes that together with the corresponding leaf values can be used to + // recompute the root and verify this proof. Nodes should consist of the max + // and min namespaces along with the actual hash, resulting in each being 48 + // bytes each + repeated bytes nodes = 3; + // leafHash are nil if the namespace is present in the NMT. In case the + // namespace to be proved is in the min/max range of the tree but absent, this + // will contain the leaf hash necessary to verify the proof of absence. Leaf + // hashes should consist of the namespace along with the actual hash, + // resulting 40 bytes total. + bytes leaf_hash = 4; +} \ No newline at end of file diff --git a/rpc/client/rpc_test.go b/rpc/client/rpc_test.go index 5c980bdd68..b4800d5811 100644 --- a/rpc/client/rpc_test.go +++ b/rpc/client/rpc_test.go @@ -617,8 +617,8 @@ func TestTx(t *testing.T) { // time to verify the proof proof := ptx.Proof - if tc.prove && assert.EqualValues(t, tx, proof.Data) { - assert.NoError(t, proof.Proof.Verify(proof.RootHash, txHash)) + if tc.prove && assert.True(t, proof.IncludesTx(ptx.Tx), i) { + assert.True(t, proof.VerifyProof(), i) } } } @@ -680,10 +680,9 @@ func TestTxSearch(t *testing.T) { assert.EqualValues(t, find.Hash, ptx.Hash) // time to verify the proof - if assert.EqualValues(t, find.Tx, ptx.Proof.Data) { - assert.NoError(t, ptx.Proof.Proof.Verify(ptx.Proof.RootHash, find.Hash)) + if assert.True(t, ptx.Proof.IncludesTx(find.Tx)) { + assert.True(t, ptx.Proof.VerifyProof()) } - // query by height result, err = c.TxSearch(context.Background(), fmt.Sprintf("tx.height=%d", find.Height), true, nil, nil, "asc") require.Nil(t, err) diff --git a/types/block.go b/types/block.go index b814b77a73..2c48b4e462 100644 --- a/types/block.go +++ b/types/block.go @@ -1000,7 +1000,7 @@ func CommitFromProto(cp *tmproto.Commit) (*Commit, error) { //----------------------------------------------------------------------------- // Data contains all the available Data of the block. -// Data with reserved namespaces (Txs, IntermediateStateRoots, Evidence) and +// Data with reserved namespaces (Txs, Evidence) and // Celestia application specific Messages. type Data struct { // Txs that will be applied by state @ block.Height+1. diff --git a/types/tx.go b/types/tx.go index d730ff1297..ec6f868a1d 100644 --- a/types/tx.go +++ b/types/tx.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" + "github.com/celestiaorg/nmt" "github.com/gogo/protobuf/proto" "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/crypto/tmhash" @@ -63,79 +64,85 @@ func (txs Txs) IndexByHash(hash []byte) int { return -1 } -// Proof returns a simple merkle proof for this node. -// Panics if i < 0 or i >= len(txs) -// TODO: optimize this! -func (txs Txs) Proof(i int) TxProof { - l := len(txs) - bzs := make([][]byte, l) - for i := 0; i < l; i++ { - bzs[i] = txs[i].Hash() - } - root, proofs := merkle.ProofsFromByteSlices(bzs) - - return TxProof{ - RootHash: root, - Data: txs[i], - Proof: *proofs[i], - } -} - // TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree. type TxProof struct { - RootHash tmbytes.HexBytes `json:"root_hash"` - Data Tx `json:"data"` - Proof merkle.Proof `json:"proof"` -} - -// Leaf returns the hash(tx), which is the leaf in the merkle tree which this proof refers to. -func (tp TxProof) Leaf() []byte { - return tp.Data.Hash() + RowRoots []tmbytes.HexBytes `json:"root_hash"` + Data [][]byte `json:"data"` + Proofs []*tmproto.NMTProof `json:"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(dataHash []byte) error { - if !bytes.Equal(dataHash, tp.RootHash) { - return errors.New("proof matches different data hash") - } - if tp.Proof.Index < 0 { - return errors.New("proof index cannot be negative") - } - if tp.Proof.Total <= 0 { - return errors.New("proof total must be positive") - } - valid := tp.Proof.Verify(tp.RootHash, tp.Leaf()) - if valid != nil { - return errors.New("proof is not internally consistent") +func (tp TxProof) Validate() error { + if len(tp.RowRoots) != len(tp.Proofs) || len(tp.Data) != len(tp.Proofs) { + return errors.New( + "invalid number of proofs, row roots, or data. they all must be the same to verify the proof", + ) + } + for _, proof := range tp.Proofs { + 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 := tp.VerifyProof() + if !valid { + return errors.New("proof is not internally consistent") + } } + return nil } -func (tp TxProof) ToProto() tmproto.TxProof { +func (tp *TxProof) VerifyProof() bool { + for i, proof := range tp.Proofs { + nmtProof := nmt.NewInclusionProof( + int(proof.Start), + int(proof.End), + proof.Nodes, + true, + ) + valid := nmtProof.VerifyInclusion( + consts.NewBaseHashFunc(), + consts.TxNamespaceID, + tp.Data[i], + tp.RowRoots[i], + ) + if !valid { + return false + } + } + return true +} - pbProof := tp.Proof.ToProto() +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{ - RootHash: tp.RootHash, + RowRoots: rowRoots, Data: tp.Data, - Proof: pbProof, + Proofs: tp.Proofs, } return pbtp } func TxProofFromProto(pb tmproto.TxProof) (TxProof, error) { - - pbProof, err := merkle.ProofFromProto(pb.Proof) - if err != nil { - return TxProof{}, err + rowRoots := make([]tmbytes.HexBytes, len(pb.RowRoots)) + for i, root := range pb.RowRoots { + rowRoots[i] = tmbytes.HexBytes(root) } - pbtp := TxProof{ - RootHash: pb.RootHash, + RowRoots: rowRoots, Data: pb.Data, - Proof: *pbProof, + Proofs: pb.Proofs, } return pbtp, nil diff --git a/types/tx_test.go b/types/tx_test.go index 8fe277da82..1366b88029 100644 --- a/types/tx_test.go +++ b/types/tx_test.go @@ -1,16 +1,12 @@ package types import ( - "bytes" mrand "math/rand" "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - ctest "github.com/tendermint/tendermint/internal/libs/test" tmrand "github.com/tendermint/tendermint/libs/rand" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) func makeTxs(cnt, size int) Txs { @@ -51,102 +47,3 @@ func TestTxIndexByHash(t *testing.T) { assert.Equal(t, -1, txs.IndexByHash(Tx("foodnwkf").Hash())) } } - -func TestValidTxProof(t *testing.T) { - cases := []struct { - txs Txs - }{ - {Txs{{1, 4, 34, 87, 163, 1}}}, - {Txs{{5, 56, 165, 2}, {4, 77}}}, - {Txs{Tx("foo"), Tx("bar"), Tx("baz")}}, - {makeTxs(20, 5)}, - {makeTxs(7, 81)}, - {makeTxs(61, 15)}, - } - - for h, tc := range cases { - txs := tc.txs - root := txs.Hash() - // make sure valid proof for every tx - for i := range txs { - tx := []byte(txs[i]) - proof := txs.Proof(i) - assert.EqualValues(t, i, proof.Proof.Index, "%d: %d", h, i) - assert.EqualValues(t, len(txs), proof.Proof.Total, "%d: %d", h, i) - assert.EqualValues(t, root, proof.RootHash, "%d: %d", h, i) - assert.EqualValues(t, tx, proof.Data, "%d: %d", h, i) - assert.EqualValues(t, txs[i].Hash(), proof.Leaf(), "%d: %d", h, i) - assert.Nil(t, proof.Validate(root), "%d: %d", h, i) - assert.NotNil(t, proof.Validate([]byte("foobar")), "%d: %d", h, i) - - // read-write must also work - var ( - p2 TxProof - pb2 tmproto.TxProof - ) - pbProof := proof.ToProto() - bin, err := pbProof.Marshal() - require.NoError(t, err) - - err = pb2.Unmarshal(bin) - require.NoError(t, err) - - p2, err = TxProofFromProto(pb2) - if assert.Nil(t, err, "%d: %d: %+v", h, i, err) { - assert.Nil(t, p2.Validate(root), "%d: %d", h, i) - } - } - } -} - -func TestTxProofUnchangable(t *testing.T) { - // run the other test a bunch... - for i := 0; i < 40; i++ { - testTxProofUnchangable(t) - } -} - -func testTxProofUnchangable(t *testing.T) { - // make some proof - txs := makeTxs(randInt(2, 100), randInt(16, 128)) - root := txs.Hash() - i := randInt(0, len(txs)-1) - proof := txs.Proof(i) - - // make sure it is valid to start with - assert.Nil(t, proof.Validate(root)) - pbProof := proof.ToProto() - bin, err := pbProof.Marshal() - require.NoError(t, err) - - // try mutating the data and make sure nothing breaks - for j := 0; j < 500; j++ { - bad := ctest.MutateByteSlice(bin) - if !bytes.Equal(bad, bin) { - assertBadProof(t, root, bad, proof) - } - } -} - -// This makes sure that the proof doesn't deserialize into something valid. -func assertBadProof(t *testing.T, root []byte, bad []byte, good TxProof) { - - var ( - proof TxProof - pbProof tmproto.TxProof - ) - err := pbProof.Unmarshal(bad) - if err == nil { - proof, err = TxProofFromProto(pbProof) - if err == nil { - err = proof.Validate(root) - if err == nil { - // XXX Fix simple merkle proofs so the following is *not* OK. - // This can happen if we have a slightly different total (where the - // path ends up the same). If it is something else, we have a real - // problem. - assert.NotEqual(t, proof.Proof.Total, good.Proof.Total, "bad: %#v\ngood: %#v", proof, good) - } - } - } -} From 134eeefb7af41afe760d4adc5b22a9d55e36bc3e Mon Sep 17 00:00:00 2001 From: CHAMI Rachid Date: Fri, 4 Feb 2022 20:59:23 +0100 Subject: [PATCH 15/31] Add an RPC endpoint for DataCommitment (#625) * init adding DataCommitment rpc * updates data commitment json response name * fix import * Update rpc/client/interface.go Co-authored-by: John Adler * Update rpc/core/blocks.go Co-authored-by: John Adler * Update rpc/core/blocks.go Co-authored-by: John Adler * lint * adds test for data commitment (still not working) * fixes data commitment creation * fixes data commitment test * adds data commitment RPC test * update comment * updates openapi specs * add blocks sanity check for data commitment * rename blockByQuery to heightsByQuery to reflect more what the function is doing * moves DataCommitmentBlocksLimit to consts * adds tests for data commitment limits Co-authored-by: John Adler run make mockery patch compute shares for pkg files finish remaining rpc refactor --- abci/client/mocks/client.go | 12 ++ internal/consensus/mocks/cons_sync_reactor.go | 12 ++ internal/evidence/mocks/block_store.go | 13 ++ internal/p2p/mocks/connection.go | 12 ++ internal/p2p/mocks/peer.go | 12 ++ internal/p2p/mocks/transport.go | 12 ++ internal/proxy/mocks/app_conn_consensus.go | 12 ++ internal/proxy/mocks/app_conn_mempool.go | 12 ++ internal/proxy/mocks/app_conn_query.go | 12 ++ internal/proxy/mocks/app_conn_snapshot.go | 12 ++ internal/rpc/core/blocks.go | 111 ++++++++++++++---- internal/rpc/core/blocks_test.go | 76 ++++++++++++ internal/rpc/core/routes.go | 1 + internal/state/indexer/mocks/event_sink.go | 12 ++ internal/state/mocks/block_store.go | 12 ++ internal/state/mocks/evidence_pool.go | 13 ++ internal/state/mocks/store.go | 12 ++ internal/statesync/mocks/state_provider.go | 12 ++ light/provider/mocks/provider.go | 12 ++ light/proxy/routes.go | 15 +++ light/rpc/client.go | 4 + light/rpc/mocks/light_client.go | 12 ++ pkg/prove/proof_test.go | 6 +- rpc/client/http/http.go | 14 +++ rpc/client/interface.go | 1 + rpc/client/local/local.go | 4 + rpc/client/mock/client.go | 4 + rpc/client/mocks/client.go | 35 ++++++ rpc/client/rpc_test.go | 28 +++++ rpc/coretypes/responses.go | 4 + rpc/openapi/openapi.yaml | 52 ++++++++ 31 files changed, 538 insertions(+), 23 deletions(-) diff --git a/abci/client/mocks/client.go b/abci/client/mocks/client.go index 664646e61c..2c0154e21f 100644 --- a/abci/client/mocks/client.go +++ b/abci/client/mocks/client.go @@ -11,6 +11,8 @@ import ( mock "github.com/stretchr/testify/mock" + testing "testing" + types "github.com/tendermint/tendermint/abci/types" ) @@ -801,3 +803,13 @@ func (_m *Client) String() string { func (_m *Client) Wait() { _m.Called() } + +// NewClient creates a new instance of Client. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewClient(t testing.TB) *Client { + mock := &Client{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/consensus/mocks/cons_sync_reactor.go b/internal/consensus/mocks/cons_sync_reactor.go index 5ac592f0d4..f904e9129a 100644 --- a/internal/consensus/mocks/cons_sync_reactor.go +++ b/internal/consensus/mocks/cons_sync_reactor.go @@ -3,6 +3,8 @@ package mocks import ( + testing "testing" + mock "github.com/stretchr/testify/mock" state "github.com/tendermint/tendermint/internal/state" ) @@ -26,3 +28,13 @@ func (_m *ConsSyncReactor) SetStateSyncingMetrics(_a0 float64) { func (_m *ConsSyncReactor) SwitchToConsensus(_a0 state.State, _a1 bool) { _m.Called(_a0, _a1) } + +// NewConsSyncReactor creates a new instance of ConsSyncReactor. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewConsSyncReactor(t testing.TB) *ConsSyncReactor { + mock := &ConsSyncReactor{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/evidence/mocks/block_store.go b/internal/evidence/mocks/block_store.go index ef3346b2a7..e45b281b90 100644 --- a/internal/evidence/mocks/block_store.go +++ b/internal/evidence/mocks/block_store.go @@ -3,7 +3,10 @@ package mocks import ( + testing "testing" + mock "github.com/stretchr/testify/mock" + types "github.com/tendermint/tendermint/types" ) @@ -57,3 +60,13 @@ func (_m *BlockStore) LoadBlockMeta(height int64) *types.BlockMeta { return r0 } + +// NewBlockStore creates a new instance of BlockStore. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewBlockStore(t testing.TB) *BlockStore { + mock := &BlockStore{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/p2p/mocks/connection.go b/internal/p2p/mocks/connection.go index 6c61741172..1ab635f53d 100644 --- a/internal/p2p/mocks/connection.go +++ b/internal/p2p/mocks/connection.go @@ -13,6 +13,8 @@ import ( p2p "github.com/tendermint/tendermint/internal/p2p" + testing "testing" + types "github.com/tendermint/tendermint/types" ) @@ -206,3 +208,13 @@ func (_m *Connection) TrySendMessage(_a0 p2p.ChannelID, _a1 []byte) (bool, error return r0, r1 } + +// NewConnection creates a new instance of Connection. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewConnection(t testing.TB) *Connection { + mock := &Connection{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/p2p/mocks/peer.go b/internal/p2p/mocks/peer.go index b905c1156b..a156b7a272 100644 --- a/internal/p2p/mocks/peer.go +++ b/internal/p2p/mocks/peer.go @@ -10,6 +10,8 @@ import ( net "net" + testing "testing" + types "github.com/tendermint/tendermint/types" ) @@ -332,3 +334,13 @@ func (_m *Peer) TrySend(_a0 byte, _a1 []byte) bool { func (_m *Peer) Wait() { _m.Called() } + +// NewPeer creates a new instance of Peer. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewPeer(t testing.TB) *Peer { + mock := &Peer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/p2p/mocks/transport.go b/internal/p2p/mocks/transport.go index 82bd670cbd..be5ef1d37d 100644 --- a/internal/p2p/mocks/transport.go +++ b/internal/p2p/mocks/transport.go @@ -7,6 +7,8 @@ import ( mock "github.com/stretchr/testify/mock" p2p "github.com/tendermint/tendermint/internal/p2p" + + testing "testing" ) // Transport is an autogenerated mock type for the Transport type @@ -119,3 +121,13 @@ func (_m *Transport) String() string { return r0 } + +// NewTransport creates a new instance of Transport. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewTransport(t testing.TB) *Transport { + mock := &Transport{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/proxy/mocks/app_conn_consensus.go b/internal/proxy/mocks/app_conn_consensus.go index fa93b0931e..391785adbb 100644 --- a/internal/proxy/mocks/app_conn_consensus.go +++ b/internal/proxy/mocks/app_conn_consensus.go @@ -9,6 +9,8 @@ import ( mock "github.com/stretchr/testify/mock" + testing "testing" + types "github.com/tendermint/tendermint/abci/types" ) @@ -150,3 +152,13 @@ func (_m *AppConnConsensus) InitChainSync(_a0 context.Context, _a1 types.Request func (_m *AppConnConsensus) SetResponseCallback(_a0 abciclient.Callback) { _m.Called(_a0) } + +// NewAppConnConsensus creates a new instance of AppConnConsensus. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewAppConnConsensus(t testing.TB) *AppConnConsensus { + mock := &AppConnConsensus{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/proxy/mocks/app_conn_mempool.go b/internal/proxy/mocks/app_conn_mempool.go index 5429d8f909..a4781cef09 100644 --- a/internal/proxy/mocks/app_conn_mempool.go +++ b/internal/proxy/mocks/app_conn_mempool.go @@ -9,6 +9,8 @@ import ( mock "github.com/stretchr/testify/mock" + testing "testing" + types "github.com/tendermint/tendermint/abci/types" ) @@ -118,3 +120,13 @@ func (_m *AppConnMempool) FlushSync(_a0 context.Context) error { func (_m *AppConnMempool) SetResponseCallback(_a0 abciclient.Callback) { _m.Called(_a0) } + +// NewAppConnMempool creates a new instance of AppConnMempool. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewAppConnMempool(t testing.TB) *AppConnMempool { + mock := &AppConnMempool{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/proxy/mocks/app_conn_query.go b/internal/proxy/mocks/app_conn_query.go index 47ac5bef94..3fc0013499 100644 --- a/internal/proxy/mocks/app_conn_query.go +++ b/internal/proxy/mocks/app_conn_query.go @@ -7,6 +7,8 @@ import ( mock "github.com/stretchr/testify/mock" + testing "testing" + types "github.com/tendermint/tendermint/abci/types" ) @@ -97,3 +99,13 @@ func (_m *AppConnQuery) QuerySync(_a0 context.Context, _a1 types.RequestQuery) ( return r0, r1 } + +// NewAppConnQuery creates a new instance of AppConnQuery. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewAppConnQuery(t testing.TB) *AppConnQuery { + mock := &AppConnQuery{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/proxy/mocks/app_conn_snapshot.go b/internal/proxy/mocks/app_conn_snapshot.go index 0b6f10ce13..af6ccfadad 100644 --- a/internal/proxy/mocks/app_conn_snapshot.go +++ b/internal/proxy/mocks/app_conn_snapshot.go @@ -7,6 +7,8 @@ import ( mock "github.com/stretchr/testify/mock" + testing "testing" + types "github.com/tendermint/tendermint/abci/types" ) @@ -120,3 +122,13 @@ func (_m *AppConnSnapshot) OfferSnapshotSync(_a0 context.Context, _a1 types.Requ return r0, r1 } + +// NewAppConnSnapshot creates a new instance of AppConnSnapshot. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewAppConnSnapshot(t testing.TB) *AppConnSnapshot { + mock := &AppConnSnapshot{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/rpc/core/blocks.go b/internal/rpc/core/blocks.go index 2e7f247265..8ea1c240fe 100644 --- a/internal/rpc/core/blocks.go +++ b/internal/rpc/core/blocks.go @@ -1,13 +1,16 @@ package core import ( + "errors" "fmt" "sort" + "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/internal/state/indexer" "github.com/tendermint/tendermint/libs/bytes" tmmath "github.com/tendermint/tendermint/libs/math" tmquery "github.com/tendermint/tendermint/libs/pubsub/query" + "github.com/tendermint/tendermint/pkg/consts" "github.com/tendermint/tendermint/rpc/coretypes" rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" "github.com/tendermint/tendermint/types" @@ -189,6 +192,55 @@ func (env *Environment) Commit(ctx *rpctypes.Context, heightPtr *int64) (*corety return coretypes.NewResultCommit(&header, commit, true), nil } +// DataCommitment collects the data roots over a provided ordered range of blocks, +// and then creates a new Merkle root of those data roots. +func (env *Environment) DataCommitment(ctx *rpctypes.Context, query string) (*coretypes.ResultDataCommitment, error) { + heights, err := searchBlocks(ctx, env, query) + if err != nil { + return nil, err + } + + if len(heights) > consts.DataCommitmentBlocksLimit { + return nil, fmt.Errorf("the query exceeds the limit of allowed blocks %d", consts.DataCommitmentBlocksLimit) + } else if len(heights) == 0 { + return nil, fmt.Errorf("cannot create the data commitments for an empty set of blocks") + } + + err = sortBlocks(heights, "asc") + if err != nil { + return nil, err + } + + if len(heights) > consts.DataCommitmentBlocksLimit { + return nil, fmt.Errorf("the query exceeds the limit of allowed blocks %d", consts.DataCommitmentBlocksLimit) + } + + if len(heights) == 0 { + return nil, fmt.Errorf("cannot create the data commitments for an empty set of blocks") + } + + err = sortBlocks(heights, "asc") + if err != nil { + return nil, err + } + + blockResults := fetchBlocks(env, heights, len(heights), 0) + root := hashDataRoots(blockResults) + + // Create data commitment + return &coretypes.ResultDataCommitment{DataCommitment: root}, nil +} + +// hashDataRoots hashes a list of blocks data hashes and returns their merkle root. +func hashDataRoots(blocks []*coretypes.ResultBlock) []byte { + dataRoots := make([][]byte, 0, len(blocks)) + for _, block := range blocks { + dataRoots = append(dataRoots, block.Block.DataHash) + } + root := merkle.HashFromByteSlices(dataRoots) + return root +} + // BlockResults gets ABCIResults at a given height. // If no height is provided, it will fetch results for the latest block. // @@ -232,6 +284,34 @@ func (env *Environment) BlockSearch( orderBy string, ) (*coretypes.ResultBlockSearch, error) { + results, err := searchBlocks(ctx, env, query) + if err != nil { + return nil, err + } + + err = sortBlocks(results, orderBy) + if err != nil { + return nil, err + } + + // paginate results + totalCount := len(results) + perPage := env.validatePerPage(perPagePtr) + + page, err := validatePage(pagePtr, perPage, totalCount) + if err != nil { + return nil, err + } + + skipCount := validateSkipCount(page, perPage) + pageSize := tmmath.MinInt(perPage, totalCount-skipCount) + + apiResults := fetchBlocks(env, results, pageSize, skipCount) + + return &coretypes.ResultBlockSearch{Blocks: apiResults, TotalCount: totalCount}, nil +} + +func searchBlocks(ctx *rpctypes.Context, env *Environment, query string) ([]int64, error) { if !indexer.KVSinkEnabled(env.EventSinks) { return nil, fmt.Errorf("block searching is disabled due to no kvEventSink") } @@ -248,12 +328,12 @@ func (env *Environment) BlockSearch( } } - results, err := kvsink.SearchBlockEvents(ctx.Context(), q) - if err != nil { - return nil, err - } + return kvsink.SearchBlockEvents(ctx.Context(), q) +} - // sort results (must be done before pagination) +// sortBlocks takes a list of block heights and sorts them according to the order: "asc" or "desc". +// If `orderBy` is blank, then it is considered descending. +func sortBlocks(results []int64, orderBy string) error { switch orderBy { case "desc", "": sort.Slice(results, func(i, j int) bool { return results[i] > results[j] }) @@ -262,21 +342,13 @@ func (env *Environment) BlockSearch( sort.Slice(results, func(i, j int) bool { return results[i] < results[j] }) default: - return nil, fmt.Errorf("expected order_by to be either `asc` or `desc` or empty: %w", coretypes.ErrInvalidRequest) - } - - // paginate results - totalCount := len(results) - perPage := env.validatePerPage(perPagePtr) - - page, err := validatePage(pagePtr, perPage, totalCount) - if err != nil { - return nil, err + return errors.New("expected order_by to be either `asc` or `desc` or empty") } + return nil +} - skipCount := validateSkipCount(page, perPage) - pageSize := tmmath.MinInt(perPage, totalCount-skipCount) - +// fetchBlocks takes a list of block heights and fetches them. +func fetchBlocks(env *Environment, results []int64, pageSize int, skipCount int) []*coretypes.ResultBlock { apiResults := make([]*coretypes.ResultBlock, 0, pageSize) for i := skipCount; i < skipCount+pageSize; i++ { block := env.BlockStore.LoadBlock(results[i]) @@ -290,6 +362,5 @@ func (env *Environment) BlockSearch( } } } - - return &coretypes.ResultBlockSearch{Blocks: apiResults, TotalCount: totalCount}, nil + return apiResults } diff --git a/internal/rpc/core/blocks_test.go b/internal/rpc/core/blocks_test.go index 213845bf40..627c5f9eec 100644 --- a/internal/rpc/core/blocks_test.go +++ b/internal/rpc/core/blocks_test.go @@ -1,16 +1,22 @@ package core import ( + "bytes" "fmt" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/merkle" + tmrand "github.com/tendermint/tendermint/libs/rand" + "github.com/tendermint/tendermint/types" dbm "github.com/tendermint/tm-db" abci "github.com/tendermint/tendermint/abci/types" sm "github.com/tendermint/tendermint/internal/state" + "github.com/tendermint/tendermint/internal/state/indexer" "github.com/tendermint/tendermint/internal/state/mocks" tmstate "github.com/tendermint/tendermint/proto/tendermint/state" "github.com/tendermint/tendermint/rpc/coretypes" @@ -118,3 +124,73 @@ func TestBlockResults(t *testing.T) { } } } + +func TestDataCommitmentResults(t *testing.T) { + env := &Environment{} + heights := []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + + blocks := randomBlocks(int64(len(heights))) + mockstore := &mocks.BlockStore{} + for i, height := range heights { + mockstore.On("LoadBlock", height).Return(blocks[i]) + mockstore.On("LoadBlockMeta", height).Return(types.NewBlockMeta(blocks[i], nil)) + } + + mockEVS := mocks.EventSink{} + mockEVS.On("SearchBlockEvents", mock.Anything, mock.Anything).Return(heights[1:3], nil) + mockEVS.On("Type").Return(indexer.KV) + + env.EventSinks = append(env.EventSinks, &mockEVS) + env.BlockStore = mockstore + + testCases := []struct { + beginQuery int + endQuery int + expectPass bool + }{ + {1, 2, true}, + // {10, 9, false}, // TODO: mock errors? + // {0, 1000, false}, + } + + for _, tc := range testCases { + mockedQuery := fmt.Sprintf("block.height >= %d AND block.height <= %d", tc.beginQuery, tc.endQuery) + + actualCommitment, err := env.DataCommitment(&rpctypes.Context{}, mockedQuery) + if tc.expectPass { + require.Nil(t, err, "should generate the needed data commitment.") + + size := tc.endQuery - tc.beginQuery + 1 + dataRoots := make([][]byte, size) + for i := 0; i < size; i++ { + dataRoots[i] = blocks[tc.beginQuery+i].DataHash + } + expectedCommitment := merkle.HashFromByteSlices(dataRoots) + + if !bytes.Equal(expectedCommitment, actualCommitment.DataCommitment) { + t.Error("expected data commitment and actual data commitment doesn't match.") + } + } else { + assert.Error(t, err) + } + } +} + +// randomBlocks generates a set of random blocks up to the provided height. +func randomBlocks(height int64) []*types.Block { + blocks := make([]*types.Block, height) + for i := int64(0); i < height; i++ { + blocks[i] = randomBlock(i) + } + return blocks +} + +// randomBlock generates a Block with a certain height and random data hash. +func randomBlock(height int64) *types.Block { + return &types.Block{ + Header: types.Header{ + Height: height, + DataHash: tmrand.Bytes(32), + }, + } +} diff --git a/internal/rpc/core/routes.go b/internal/rpc/core/routes.go index 740fe3b191..b45f93c184 100644 --- a/internal/rpc/core/routes.go +++ b/internal/rpc/core/routes.go @@ -29,6 +29,7 @@ func (env *Environment) GetRoutes() RoutesMap { "block_by_hash": rpc.NewRPCFunc(env.BlockByHash, "hash", true), "block_results": rpc.NewRPCFunc(env.BlockResults, "height", true), "commit": rpc.NewRPCFunc(env.Commit, "height", true), + "data_commitment": rpc.NewRPCFunc(env.DataCommitment, "query", true), "check_tx": rpc.NewRPCFunc(env.CheckTx, "tx", true), "remove_tx": rpc.NewRPCFunc(env.RemoveTx, "txkey", false), "tx": rpc.NewRPCFunc(env.Tx, "hash,prove", true), diff --git a/internal/state/indexer/mocks/event_sink.go b/internal/state/indexer/mocks/event_sink.go index 98b32e9350..82776483bf 100644 --- a/internal/state/indexer/mocks/event_sink.go +++ b/internal/state/indexer/mocks/event_sink.go @@ -12,6 +12,8 @@ import ( tenderminttypes "github.com/tendermint/tendermint/types" + testing "testing" + types "github.com/tendermint/tendermint/abci/types" ) @@ -165,3 +167,13 @@ func (_m *EventSink) Type() indexer.EventSinkType { return r0 } + +// NewEventSink creates a new instance of EventSink. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewEventSink(t testing.TB) *EventSink { + mock := &EventSink{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/state/mocks/block_store.go b/internal/state/mocks/block_store.go index 563183437f..7cc7fa883c 100644 --- a/internal/state/mocks/block_store.go +++ b/internal/state/mocks/block_store.go @@ -5,6 +5,8 @@ package mocks import ( mock "github.com/stretchr/testify/mock" + testing "testing" + types "github.com/tendermint/tendermint/types" ) @@ -208,3 +210,13 @@ func (_m *BlockStore) Size() int64 { return r0 } + +// NewBlockStore creates a new instance of BlockStore. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewBlockStore(t testing.TB) *BlockStore { + mock := &BlockStore{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/state/mocks/evidence_pool.go b/internal/state/mocks/evidence_pool.go index 8bf4a9b64b..96f9b32080 100644 --- a/internal/state/mocks/evidence_pool.go +++ b/internal/state/mocks/evidence_pool.go @@ -3,8 +3,11 @@ package mocks import ( + testing "testing" + mock "github.com/stretchr/testify/mock" state "github.com/tendermint/tendermint/internal/state" + types "github.com/tendermint/tendermint/types" ) @@ -68,3 +71,13 @@ func (_m *EvidencePool) PendingEvidence(maxBytes int64) ([]types.Evidence, int64 func (_m *EvidencePool) Update(_a0 state.State, _a1 types.EvidenceList) { _m.Called(_a0, _a1) } + +// NewEvidencePool creates a new instance of EvidencePool. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewEvidencePool(t testing.TB) *EvidencePool { + mock := &EvidencePool{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/state/mocks/store.go b/internal/state/mocks/store.go index 02c69d3e05..9b41f3c1bc 100644 --- a/internal/state/mocks/store.go +++ b/internal/state/mocks/store.go @@ -7,6 +7,8 @@ import ( state "github.com/tendermint/tendermint/internal/state" tendermintstate "github.com/tendermint/tendermint/proto/tendermint/state" + testing "testing" + types "github.com/tendermint/tendermint/types" ) @@ -186,3 +188,13 @@ func (_m *Store) SaveValidatorSets(_a0 int64, _a1 int64, _a2 *types.ValidatorSet return r0 } + +// NewStore creates a new instance of Store. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewStore(t testing.TB) *Store { + mock := &Store{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/statesync/mocks/state_provider.go b/internal/statesync/mocks/state_provider.go index b8d6816310..582ebcd9c4 100644 --- a/internal/statesync/mocks/state_provider.go +++ b/internal/statesync/mocks/state_provider.go @@ -8,6 +8,8 @@ import ( mock "github.com/stretchr/testify/mock" state "github.com/tendermint/tendermint/internal/state" + testing "testing" + types "github.com/tendermint/tendermint/types" ) @@ -82,3 +84,13 @@ func (_m *StateProvider) State(ctx context.Context, height uint64) (state.State, return r0, r1 } + +// NewStateProvider creates a new instance of StateProvider. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewStateProvider(t testing.TB) *StateProvider { + mock := &StateProvider{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/light/provider/mocks/provider.go b/light/provider/mocks/provider.go index aa36fa2d34..343ba1e7e2 100644 --- a/light/provider/mocks/provider.go +++ b/light/provider/mocks/provider.go @@ -7,6 +7,8 @@ import ( mock "github.com/stretchr/testify/mock" + testing "testing" + types "github.com/tendermint/tendermint/types" ) @@ -51,3 +53,13 @@ func (_m *Provider) ReportEvidence(_a0 context.Context, _a1 types.Evidence) erro return r0 } + +// NewProvider creates a new instance of Provider. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewProvider(t testing.TB) *Provider { + mock := &Provider{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/light/proxy/routes.go b/light/proxy/routes.go index ac2e8b5dfb..66747fd1f6 100644 --- a/light/proxy/routes.go +++ b/light/proxy/routes.go @@ -30,6 +30,7 @@ func RPCRoutes(c *lrpc.Client) map[string]*rpcserver.RPCFunc { "block_by_hash": rpcserver.NewRPCFunc(makeBlockByHashFunc(c), "hash", true), "block_results": rpcserver.NewRPCFunc(makeBlockResultsFunc(c), "height", true), "commit": rpcserver.NewRPCFunc(makeCommitFunc(c), "height", true), + "data_commitment": rpcserver.NewRPCFunc(makeDataCommitmentFunc(c), "query", true), "tx": rpcserver.NewRPCFunc(makeTxFunc(c), "hash,prove", true), "tx_search": rpcserver.NewRPCFunc(makeTxSearchFunc(c), "query,prove,page,per_page,order_by", false), "block_search": rpcserver.NewRPCFunc(makeBlockSearchFunc(c), "query,page,per_page,order_by", false), @@ -151,6 +152,20 @@ func makeCommitFunc(c *lrpc.Client) rpcCommitFunc { } } +type rpcDataCommitmentFunc func( + ctx *rpctypes.Context, + query string, +) (*coretypes.ResultDataCommitment, error) + +func makeDataCommitmentFunc(c *lrpc.Client) rpcDataCommitmentFunc { + return func( + ctx *rpctypes.Context, + query string, + ) (*coretypes.ResultDataCommitment, error) { + return c.DataCommitment(ctx.Context(), query) + } +} + type rpcTxFunc func(ctx *rpctypes.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) func makeTxFunc(c *lrpc.Client) rpcTxFunc { diff --git a/light/rpc/client.go b/light/rpc/client.go index 7bcc093e61..62dce3e3f6 100644 --- a/light/rpc/client.go +++ b/light/rpc/client.go @@ -503,6 +503,10 @@ func (c *Client) Commit(ctx context.Context, height *int64) (*coretypes.ResultCo }, nil } +func (c *Client) DataCommitment(ctx context.Context, query string) (*coretypes.ResultDataCommitment, error) { + return c.next.DataCommitment(ctx, query) +} + // Tx calls rpcclient#Tx method and then verifies the proof if such was // requested. func (c *Client) Tx(ctx context.Context, hash tmbytes.HexBytes, prove bool) (*coretypes.ResultTx, error) { diff --git a/light/rpc/mocks/light_client.go b/light/rpc/mocks/light_client.go index cc32cf6494..0a8b35dd2f 100644 --- a/light/rpc/mocks/light_client.go +++ b/light/rpc/mocks/light_client.go @@ -7,6 +7,8 @@ import ( mock "github.com/stretchr/testify/mock" + testing "testing" + time "time" types "github.com/tendermint/tendermint/types" @@ -99,3 +101,13 @@ func (_m *LightClient) VerifyLightBlockAtHeight(ctx context.Context, height int6 return r0, r1 } + +// NewLightClient creates a new instance of LightClient. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewLightClient(t testing.TB) *LightClient { + mock := &LightClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/prove/proof_test.go b/pkg/prove/proof_test.go index 87eb87bd91..cdf97c9d89 100644 --- a/pkg/prove/proof_test.go +++ b/pkg/prove/proof_test.go @@ -24,7 +24,7 @@ func TestTxInclusion(t *testing.T) { } // compute the data availability header - shares, _ := typicalBlockData.ComputeShares() + shares, _, _ := typicalBlockData.ComputeShares(64) squareSize := uint(math.Sqrt(float64(len(shares)))) @@ -101,7 +101,7 @@ func Test_genRowShares(t *testing.T) { Messages: generateRandomlySizedMessages(10, 1000), } - allShares, _ := typicalBlockData.ComputeShares() + allShares, _, _ := typicalBlockData.ComputeShares(64) rawShares := allShares.RawShares() originalSquareSize := uint(math.Sqrt(float64(len(rawShares)))) @@ -137,7 +137,7 @@ func Test_genOrigRowShares(t *testing.T) { Messages: generateRandomlySizedMessages(10, 1500), } - allShares, _ := typicalBlockData.ComputeShares() + allShares, _, _ := typicalBlockData.ComputeShares(64) rawShares := allShares.RawShares() genShares := genOrigRowShares(typicalBlockData, 8, 0, 7) diff --git a/rpc/client/http/http.go b/rpc/client/http/http.go index 6c518e8994..393ac89c4f 100644 --- a/rpc/client/http/http.go +++ b/rpc/client/http/http.go @@ -489,6 +489,20 @@ func (c *baseRPCClient) Commit(ctx context.Context, height *int64) (*coretypes.R return result, nil } +func (c *baseRPCClient) DataCommitment(ctx context.Context, query string) (*coretypes.ResultDataCommitment, error) { + result := new(coretypes.ResultDataCommitment) + params := map[string]interface{}{ + "query": query, + } + + _, err := c.caller.Call(ctx, "data_commitment", params, result) + if err != nil { + return nil, err + } + + return result, nil +} + func (c *baseRPCClient) Tx(ctx context.Context, hash bytes.HexBytes, prove bool) (*coretypes.ResultTx, error) { result := new(coretypes.ResultTx) params := map[string]interface{}{ diff --git a/rpc/client/interface.go b/rpc/client/interface.go index 5f6d9adddf..c55c4d1203 100644 --- a/rpc/client/interface.go +++ b/rpc/client/interface.go @@ -81,6 +81,7 @@ type SignClient interface { Header(ctx context.Context, height *int64) (*coretypes.ResultHeader, error) HeaderByHash(ctx context.Context, hash bytes.HexBytes) (*coretypes.ResultHeader, error) Commit(ctx context.Context, height *int64) (*coretypes.ResultCommit, error) + DataCommitment(ctx context.Context, query string) (*coretypes.ResultDataCommitment, error) Validators(ctx context.Context, height *int64, page, perPage *int) (*coretypes.ResultValidators, error) Tx(ctx context.Context, hash bytes.HexBytes, prove bool) (*coretypes.ResultTx, error) diff --git a/rpc/client/local/local.go b/rpc/client/local/local.go index 95428a93d7..18cce5ba7c 100644 --- a/rpc/client/local/local.go +++ b/rpc/client/local/local.go @@ -186,6 +186,10 @@ func (c *Local) HeaderByHash(ctx context.Context, hash bytes.HexBytes) (*coretyp return c.env.HeaderByHash(c.ctx, hash) } +func (c *Local) DataCommitment(_ context.Context, query string) (*coretypes.ResultDataCommitment, error) { + return c.env.DataCommitment(c.ctx, query) +} + func (c *Local) Commit(ctx context.Context, height *int64) (*coretypes.ResultCommit, error) { return c.env.Commit(c.ctx, height) } diff --git a/rpc/client/mock/client.go b/rpc/client/mock/client.go index c550c01c0d..7aa550a687 100644 --- a/rpc/client/mock/client.go +++ b/rpc/client/mock/client.go @@ -165,6 +165,10 @@ func (c Client) Commit(ctx context.Context, height *int64) (*coretypes.ResultCom return c.env.Commit(&rpctypes.Context{}, height) } +func (c Client) DataCommitment(ctx context.Context, query string) (*coretypes.ResultDataCommitment, error) { + return c.env.DataCommitment(&rpctypes.Context{}, query) +} + func (c Client) Validators(ctx context.Context, height *int64, page, perPage *int) (*coretypes.ResultValidators, error) { return c.env.Validators(&rpctypes.Context{}, height, page, perPage) } diff --git a/rpc/client/mocks/client.go b/rpc/client/mocks/client.go index 0a83ef201e..2725a5fa7c 100644 --- a/rpc/client/mocks/client.go +++ b/rpc/client/mocks/client.go @@ -12,6 +12,8 @@ import ( mock "github.com/stretchr/testify/mock" + testing "testing" + types "github.com/tendermint/tendermint/types" ) @@ -388,6 +390,29 @@ func (_m *Client) ConsensusState(_a0 context.Context) (*coretypes.ResultConsensu return r0, r1 } +// DataCommitment provides a mock function with given fields: ctx, query +func (_m *Client) DataCommitment(ctx context.Context, query string) (*coretypes.ResultDataCommitment, error) { + ret := _m.Called(ctx, query) + + var r0 *coretypes.ResultDataCommitment + if rf, ok := ret.Get(0).(func(context.Context, string) *coretypes.ResultDataCommitment); ok { + r0 = rf(ctx, query) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*coretypes.ResultDataCommitment) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, query) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // DumpConsensusState provides a mock function with given fields: _a0 func (_m *Client) DumpConsensusState(_a0 context.Context) (*coretypes.ResultDumpConsensusState, error) { ret := _m.Called(_a0) @@ -800,3 +825,13 @@ func (_m *Client) Validators(ctx context.Context, height *int64, page *int, perP return r0, r1 } + +// NewClient creates a new instance of Client. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewClient(t testing.TB) *Client { + mock := &Client{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/rpc/client/rpc_test.go b/rpc/client/rpc_test.go index b4800d5811..9762605947 100644 --- a/rpc/client/rpc_test.go +++ b/rpc/client/rpc_test.go @@ -765,6 +765,34 @@ func TestTxSearch(t *testing.T) { } } +func TestDataCommitment(t *testing.T) { + _, conf := NodeSuite(t) + c := getHTTPClient(t, conf) + + // first we broadcast a few tx + expectedHeight := int64(3) + var bres *coretypes.ResultBroadcastTxCommit + var err error + for i := int64(0); i < expectedHeight; i++ { + _, _, tx := MakeTxKV() + bres, err = c.BroadcastTxCommit(context.Background(), tx) + require.Nil(t, err, "%+v when submitting tx %d", err, i) + } + + // check if height >= 3 + actualHeight := bres.Height + require.LessOrEqual(t, expectedHeight, actualHeight, "couldn't create enough blocks for testing the commitment.") + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // check if data commitment is not nil. + // Checking if the commitment is correct is done in `core/blocks_test.go`. + dataCommitment, err := c.DataCommitment(ctx, fmt.Sprintf("block.height <= %d", expectedHeight)) + require.NotNil(t, dataCommitment, "data commitment shouldn't be nul.") + require.Nil(t, err, "%+v when creating data commitment.", err) +} + func TestBatchedJSONRPCCalls(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/rpc/coretypes/responses.go b/rpc/coretypes/responses.go index 223a25ff78..a9755a0f3a 100644 --- a/rpc/coretypes/responses.go +++ b/rpc/coretypes/responses.go @@ -73,6 +73,10 @@ type ResultBlockResults struct { ConsensusParamUpdates *tmproto.ConsensusParams `json:"consensus_param_updates"` } +type ResultDataCommitment struct { + DataCommitment bytes.HexBytes `json:"data_commitment"` +} + // NewResultCommit is a helper to initialize the ResultCommit with // the embedded struct func NewResultCommit(header *types.Header, commit *types.Commit, diff --git a/rpc/openapi/openapi.yaml b/rpc/openapi/openapi.yaml index bcb5739ddc..a60bb07ca7 100644 --- a/rpc/openapi/openapi.yaml +++ b/rpc/openapi/openapi.yaml @@ -1225,7 +1225,37 @@ paths: application/json: schema: $ref: "#/components/schemas/ErrorResponse" + /data_commitment: + get: + summary: Generates a data commitment for a range of blocks + description: | + Generates a data commitment over an ordered list of blocks matching the query. + See /subscribe for the query syntax. + operationId: data_commitment + parameters: + - in: query + name: query + description: Query + required: true + schema: + type: string + example: "block.height > 1000" + tags: + - Info + responses: + "200": + description: Hex representation of the data commitment. + content: + application/json: + schema: + $ref: "#/components/schemas/DataCommitmentResponse" + "500": + description: Error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" /tx: get: summary: Get transactions by hash @@ -2626,6 +2656,28 @@ components: example: "2" type: object + DataCommitmentResponse: + type: object + required: + - "jsonrpc" + - "id" + - "result" + properties: + jsonrpc: + type: string + example: "2.0" + id: + type: integer + example: 0 + result: + required: + - "dataCommitment" + properties: + dataCommitment: + type: string + example: "D70952032620CC4E2737EB8AC379806359D8E0B17B0488F627997A0B043ABDED" + type: object + TxResponse: type: object required: From 07f9a05444db763c44ff81f564e7350ddf57e5a4 Mon Sep 17 00:00:00 2001 From: Marko Date: Tue, 27 Jul 2021 07:30:34 +0000 Subject: [PATCH 16/31] abci: PrepareProposal (#6544) modify to use entire block data instead of only txs fix compile issue in kvstore linter use correct square size param in test remove persistent keystore modifying the second transaction of everyblock --- abci/client/client.go | 2 + abci/client/grpc_client.go | 33 + abci/client/local_client.go | 26 + abci/client/mocks/client.go | 46 + abci/client/socket_client.go | 21 + abci/example/kvstore/kvstore.go | 6 + abci/example/kvstore/persistent_kvstore.go | 9 + abci/server/socket_server.go | 3 + abci/types/application.go | 13 +- abci/types/messages.go | 12 + abci/types/types.pb.go | 1028 ++++++++++++++++---- internal/consensus/mempool_test.go | 5 + internal/proxy/app_conn.go | 8 + internal/proxy/mocks/app_conn_consensus.go | 23 + internal/state/execution.go | 63 +- pkg/prove/proof_test.go | 2 +- proto/tendermint/abci/types.proto | 16 + test/e2e/app/app.go | 5 + types/tx.go | 9 + types/tx_test.go | 6 - 20 files changed, 1115 insertions(+), 221 deletions(-) diff --git a/abci/client/client.go b/abci/client/client.go index 9725f88388..24ff4467c6 100644 --- a/abci/client/client.go +++ b/abci/client/client.go @@ -46,6 +46,7 @@ type Client interface { OfferSnapshotAsync(context.Context, types.RequestOfferSnapshot) (*ReqRes, error) LoadSnapshotChunkAsync(context.Context, types.RequestLoadSnapshotChunk) (*ReqRes, error) ApplySnapshotChunkAsync(context.Context, types.RequestApplySnapshotChunk) (*ReqRes, error) + PrepareProposalAsync(context.Context, types.RequestPrepareProposal) (*ReqRes, error) // Synchronous requests FlushSync(context.Context) error @@ -62,6 +63,7 @@ type Client interface { OfferSnapshotSync(context.Context, types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error) LoadSnapshotChunkSync(context.Context, types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error) ApplySnapshotChunkSync(context.Context, types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error) + PrepareProposalSync(context.Context, types.RequestPrepareProposal) (*types.ResponsePrepareProposal, error) } //---------------------------------------- diff --git a/abci/client/grpc_client.go b/abci/client/grpc_client.go index 049910beaf..483e4e523b 100644 --- a/abci/client/grpc_client.go +++ b/abci/client/grpc_client.go @@ -315,6 +315,27 @@ func (cli *grpcClient) ApplySnapshotChunkAsync( ) } +func (cli *grpcClient) PrepareProposalAsync( + ctx context.Context, + params types.RequestPrepareProposal, +) (*ReqRes, error) { + + req := types.ToRequestPrepareProposal(params) + res, err := cli.client.PrepareProposal(ctx, req.GetPrepareProposal(), grpc.WaitForReady(true)) + if err != nil { + return nil, err + } + return cli.finishAsyncCall( + ctx, + req, + &types.Response{ + Value: &types.Response_PrepareProposal{ + PrepareProposal: res, + }, + }, + ) +} + // finishAsyncCall creates a ReqRes for an async call, and immediately populates it // with the response. We don't complete it until it's been ordered via the channel. func (cli *grpcClient) finishAsyncCall(ctx context.Context, req *types.Request, res *types.Response) (*ReqRes, error) { @@ -505,3 +526,15 @@ func (cli *grpcClient) ApplySnapshotChunkSync( } return cli.finishSyncCall(reqres).GetApplySnapshotChunk(), cli.Error() } + +func (cli *grpcClient) PrepareProposalSync( + ctx context.Context, + params types.RequestPrepareProposal, +) (*types.ResponsePrepareProposal, error) { + + reqres, err := cli.PrepareProposalAsync(ctx, params) + if err != nil { + return nil, err + } + return cli.finishSyncCall(reqres).GetPrepareProposal(), cli.Error() +} diff --git a/abci/client/local_client.go b/abci/client/local_client.go index 33773e9363..9a72dae784 100644 --- a/abci/client/local_client.go +++ b/abci/client/local_client.go @@ -202,6 +202,20 @@ func (app *localClient) ApplySnapshotChunkAsync( ), nil } +func (app *localClient) PrepareProposalAsync( + ctx context.Context, + req types.RequestPrepareProposal, +) (*ReqRes, error) { + app.mtx.Lock() + defer app.mtx.Unlock() + + res := app.Application.PrepareProposal(req) + return app.callback( + types.ToRequestPrepareProposal(req), + types.ToResponsePrepareProposal(res), + ), nil +} + //------------------------------------------------------- func (app *localClient) FlushSync(ctx context.Context) error { @@ -344,6 +358,18 @@ func (app *localClient) ApplySnapshotChunkSync( return &res, nil } +func (app *localClient) PrepareProposalSync( + ctx context.Context, + req types.RequestPrepareProposal, +) (*types.ResponsePrepareProposal, error) { + + app.mtx.Lock() + defer app.mtx.Unlock() + + res := app.Application.PrepareProposal(req) + return &res, nil +} + //------------------------------------------------------- func (app *localClient) callback(req *types.Request, res *types.Response) *ReqRes { diff --git a/abci/client/mocks/client.go b/abci/client/mocks/client.go index 2c0154e21f..830516985a 100644 --- a/abci/client/mocks/client.go +++ b/abci/client/mocks/client.go @@ -671,6 +671,52 @@ func (_m *Client) OnStop() { _m.Called() } +// PrepareProposalAsync provides a mock function with given fields: _a0, _a1 +func (_m *Client) PrepareProposalAsync(_a0 context.Context, _a1 types.RequestPrepareProposal) (*abciclient.ReqRes, error) { + ret := _m.Called(_a0, _a1) + + var r0 *abciclient.ReqRes + if rf, ok := ret.Get(0).(func(context.Context, types.RequestPrepareProposal) *abciclient.ReqRes); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*abciclient.ReqRes) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, types.RequestPrepareProposal) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// PrepareProposalSync provides a mock function with given fields: _a0, _a1 +func (_m *Client) PrepareProposalSync(_a0 context.Context, _a1 types.RequestPrepareProposal) (*types.ResponsePrepareProposal, error) { + ret := _m.Called(_a0, _a1) + + var r0 *types.ResponsePrepareProposal + if rf, ok := ret.Get(0).(func(context.Context, types.RequestPrepareProposal) *types.ResponsePrepareProposal); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.ResponsePrepareProposal) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, types.RequestPrepareProposal) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // QueryAsync provides a mock function with given fields: _a0, _a1 func (_m *Client) QueryAsync(_a0 context.Context, _a1 types.RequestQuery) (*abciclient.ReqRes, error) { ret := _m.Called(_a0, _a1) diff --git a/abci/client/socket_client.go b/abci/client/socket_client.go index 8218458018..9ccefaed94 100644 --- a/abci/client/socket_client.go +++ b/abci/client/socket_client.go @@ -276,6 +276,13 @@ func (cli *socketClient) ApplySnapshotChunkAsync( return cli.queueRequestAsync(ctx, types.ToRequestApplySnapshotChunk(req)) } +func (cli *socketClient) PrepareProposalAsync( + ctx context.Context, + req types.RequestPrepareProposal, +) (*ReqRes, error) { + return cli.queueRequestAsync(ctx, types.ToRequestPrepareProposal(req)) +} + //---------------------------------------- func (cli *socketClient) FlushSync(ctx context.Context) error { @@ -446,6 +453,18 @@ func (cli *socketClient) ApplySnapshotChunkSync( return reqres.Response.GetApplySnapshotChunk(), nil } +func (cli *socketClient) PrepareProposalSync( + ctx context.Context, + req types.RequestPrepareProposal, +) (*types.ResponsePrepareProposal, error) { + + reqres, err := cli.queueRequestAndFlushSync(ctx, types.ToRequestPrepareProposal(req)) + if err != nil { + return nil, err + } + return reqres.Response.GetPrepareProposal(), nil +} + //---------------------------------------- // queueRequest enqueues req onto the queue. The request can break early if the @@ -562,6 +581,8 @@ func resMatchesReq(req *types.Request, res *types.Response) (ok bool) { _, ok = res.Value.(*types.Response_ListSnapshots) case *types.Request_OfferSnapshot: _, ok = res.Value.(*types.Response_OfferSnapshot) + case *types.Request_PrepareProposal: + _, ok = res.Value.(*types.Response_PrepareProposal) } return ok } diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index 97256c8ac4..b6cbce1d92 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -171,3 +171,9 @@ func (app *Application) Query(reqQuery types.RequestQuery) (resQuery types.Respo return resQuery } + +func (app *Application) PrepareProposal( + req types.RequestPrepareProposal) types.ResponsePrepareProposal { + return types.ResponsePrepareProposal{ + BlockData: req.BlockData} +} diff --git a/abci/example/kvstore/persistent_kvstore.go b/abci/example/kvstore/persistent_kvstore.go index 40451baa93..b98ae0c505 100644 --- a/abci/example/kvstore/persistent_kvstore.go +++ b/abci/example/kvstore/persistent_kvstore.go @@ -170,6 +170,15 @@ func (app *PersistentKVStoreApplication) ApplySnapshotChunk( return types.ResponseApplySnapshotChunk{Result: types.ResponseApplySnapshotChunk_ABORT} } +func (app *PersistentKVStoreApplication) PrepareProposal( + req types.RequestPrepareProposal) types.ResponsePrepareProposal { + // if len(req.BlockData.Txs) >= 1 { + // req.BlockData.Txs[0] = []byte("modified tx") + // } + + return types.ResponsePrepareProposal{BlockData: req.BlockData} +} + //--------------------------------------------- // update validators diff --git a/abci/server/socket_server.go b/abci/server/socket_server.go index 85539645bf..ead074f490 100644 --- a/abci/server/socket_server.go +++ b/abci/server/socket_server.go @@ -227,6 +227,9 @@ func (s *SocketServer) handleRequest(req *types.Request, responses chan<- *types case *types.Request_OfferSnapshot: res := s.app.OfferSnapshot(*r.OfferSnapshot) responses <- types.ToResponseOfferSnapshot(res) + case *types.Request_PrepareProposal: + res := s.app.PrepareProposal(*r.PrepareProposal) + responses <- types.ToResponsePrepareProposal(res) case *types.Request_LoadSnapshotChunk: res := s.app.LoadSnapshotChunk(*r.LoadSnapshotChunk) responses <- types.ToResponseLoadSnapshotChunk(res) diff --git a/abci/types/application.go b/abci/types/application.go index 2a3cabd8bb..4a74c78526 100644 --- a/abci/types/application.go +++ b/abci/types/application.go @@ -17,7 +17,8 @@ type Application interface { CheckTx(RequestCheckTx) ResponseCheckTx // Validate a tx for the mempool // Consensus Connection - InitChain(RequestInitChain) ResponseInitChain // Initialize blockchain w validators/other info from TendermintCore + InitChain(RequestInitChain) ResponseInitChain // Initialize blockchain w validators/other info from TendermintCore + PrepareProposal(RequestPrepareProposal) ResponsePrepareProposal BeginBlock(RequestBeginBlock) ResponseBeginBlock // Signals the beginning of a block DeliverTx(RequestDeliverTx) ResponseDeliverTx // Deliver a tx for full processing EndBlock(RequestEndBlock) ResponseEndBlock // Signals the end of a block, returns changes to the validator set @@ -90,6 +91,10 @@ func (BaseApplication) ApplySnapshotChunk(req RequestApplySnapshotChunk) Respons return ResponseApplySnapshotChunk{} } +func (BaseApplication) PrepareProposal(req RequestPrepareProposal) ResponsePrepareProposal { + return ResponsePrepareProposal{} +} + //------------------------------------------------------- // GRPCApplication is a GRPC wrapper for Application @@ -172,3 +177,9 @@ func (app *GRPCApplication) ApplySnapshotChunk( res := app.app.ApplySnapshotChunk(*req) return &res, nil } + +func (app *GRPCApplication) PrepareProposal( + ctx context.Context, req *RequestPrepareProposal) (*ResponsePrepareProposal, error) { + res := app.app.PrepareProposal(*req) + return &res, nil +} diff --git a/abci/types/messages.go b/abci/types/messages.go index 74f3cc75c8..8c17baeb3a 100644 --- a/abci/types/messages.go +++ b/abci/types/messages.go @@ -110,6 +110,12 @@ func ToRequestApplySnapshotChunk(req RequestApplySnapshotChunk) *Request { } } +func ToRequestPrepareProposal(req RequestPrepareProposal) *Request { + return &Request{ + Value: &Request_PrepareProposal{&req}, + } +} + //---------------------------------------- func ToResponseException(errStr string) *Response { @@ -200,3 +206,9 @@ func ToResponseApplySnapshotChunk(res ResponseApplySnapshotChunk) *Response { Value: &Response_ApplySnapshotChunk{&res}, } } + +func ToResponsePrepareProposal(res ResponsePrepareProposal) *Response { + return &Response{ + Value: &Response_PrepareProposal{&res}, + } +} diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 4fbebc6acc..125bd7ed51 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -120,7 +120,7 @@ func (x ResponseOfferSnapshot_Result) String() string { } func (ResponseOfferSnapshot_Result) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{28, 0} + return fileDescriptor_252557cfdd89a31a, []int{29, 0} } type ResponseApplySnapshotChunk_Result int32 @@ -157,7 +157,7 @@ func (x ResponseApplySnapshotChunk_Result) String() string { } func (ResponseApplySnapshotChunk_Result) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{30, 0} + return fileDescriptor_252557cfdd89a31a, []int{31, 0} } type Request struct { @@ -176,6 +176,7 @@ type Request struct { // *Request_OfferSnapshot // *Request_LoadSnapshotChunk // *Request_ApplySnapshotChunk + // *Request_PrepareProposal Value isRequest_Value `protobuf_oneof:"value"` } @@ -260,6 +261,9 @@ type Request_LoadSnapshotChunk struct { type Request_ApplySnapshotChunk struct { ApplySnapshotChunk *RequestApplySnapshotChunk `protobuf:"bytes,14,opt,name=apply_snapshot_chunk,json=applySnapshotChunk,proto3,oneof" json:"apply_snapshot_chunk,omitempty"` } +type Request_PrepareProposal struct { + PrepareProposal *RequestPrepareProposal `protobuf:"bytes,15,opt,name=prepare_proposal,json=prepareProposal,proto3,oneof" json:"prepare_proposal,omitempty"` +} func (*Request_Echo) isRequest_Value() {} func (*Request_Flush) isRequest_Value() {} @@ -275,6 +279,7 @@ func (*Request_ListSnapshots) isRequest_Value() {} func (*Request_OfferSnapshot) isRequest_Value() {} func (*Request_LoadSnapshotChunk) isRequest_Value() {} func (*Request_ApplySnapshotChunk) isRequest_Value() {} +func (*Request_PrepareProposal) isRequest_Value() {} func (m *Request) GetValue() isRequest_Value { if m != nil { @@ -381,6 +386,13 @@ func (m *Request) GetApplySnapshotChunk() *RequestApplySnapshotChunk { return nil } +func (m *Request) GetPrepareProposal() *RequestPrepareProposal { + if x, ok := m.GetValue().(*Request_PrepareProposal); ok { + return x.PrepareProposal + } + return nil +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*Request) XXX_OneofWrappers() []interface{} { return []interface{}{ @@ -398,6 +410,7 @@ func (*Request) XXX_OneofWrappers() []interface{} { (*Request_OfferSnapshot)(nil), (*Request_LoadSnapshotChunk)(nil), (*Request_ApplySnapshotChunk)(nil), + (*Request_PrepareProposal)(nil), } } @@ -1157,6 +1170,62 @@ func (m *RequestApplySnapshotChunk) GetSender() string { return "" } +type RequestPrepareProposal struct { + // block_data is an array of transactions that will be included in a block, + // sent to the app for possible modifications. + // applications can not exceed the size of the data passed to it. + BlockData *types1.Data `protobuf:"bytes,1,opt,name=block_data,json=blockData,proto3" json:"block_data,omitempty"` + // If an application decides to populate block_data with extra information, they can not exceed this value. + BlockDataSize int64 `protobuf:"varint,2,opt,name=block_data_size,json=blockDataSize,proto3" json:"block_data_size,omitempty"` +} + +func (m *RequestPrepareProposal) Reset() { *m = RequestPrepareProposal{} } +func (m *RequestPrepareProposal) String() string { return proto.CompactTextString(m) } +func (*RequestPrepareProposal) ProtoMessage() {} +func (*RequestPrepareProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{15} +} +func (m *RequestPrepareProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RequestPrepareProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RequestPrepareProposal.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 *RequestPrepareProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_RequestPrepareProposal.Merge(m, src) +} +func (m *RequestPrepareProposal) XXX_Size() int { + return m.Size() +} +func (m *RequestPrepareProposal) XXX_DiscardUnknown() { + xxx_messageInfo_RequestPrepareProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_RequestPrepareProposal proto.InternalMessageInfo + +func (m *RequestPrepareProposal) GetBlockData() *types1.Data { + if m != nil { + return m.BlockData + } + return nil +} + +func (m *RequestPrepareProposal) GetBlockDataSize() int64 { + if m != nil { + return m.BlockDataSize + } + return 0 +} + type Response struct { // Types that are valid to be assigned to Value: // *Response_Exception @@ -1174,6 +1243,7 @@ type Response struct { // *Response_OfferSnapshot // *Response_LoadSnapshotChunk // *Response_ApplySnapshotChunk + // *Response_PrepareProposal Value isResponse_Value `protobuf_oneof:"value"` } @@ -1181,7 +1251,7 @@ func (m *Response) Reset() { *m = Response{} } func (m *Response) String() string { return proto.CompactTextString(m) } func (*Response) ProtoMessage() {} func (*Response) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{15} + return fileDescriptor_252557cfdd89a31a, []int{16} } func (m *Response) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1261,6 +1331,9 @@ type Response_LoadSnapshotChunk struct { type Response_ApplySnapshotChunk struct { ApplySnapshotChunk *ResponseApplySnapshotChunk `protobuf:"bytes,15,opt,name=apply_snapshot_chunk,json=applySnapshotChunk,proto3,oneof" json:"apply_snapshot_chunk,omitempty"` } +type Response_PrepareProposal struct { + PrepareProposal *ResponsePrepareProposal `protobuf:"bytes,16,opt,name=prepare_proposal,json=prepareProposal,proto3,oneof" json:"prepare_proposal,omitempty"` +} func (*Response_Exception) isResponse_Value() {} func (*Response_Echo) isResponse_Value() {} @@ -1277,6 +1350,7 @@ func (*Response_ListSnapshots) isResponse_Value() {} func (*Response_OfferSnapshot) isResponse_Value() {} func (*Response_LoadSnapshotChunk) isResponse_Value() {} func (*Response_ApplySnapshotChunk) isResponse_Value() {} +func (*Response_PrepareProposal) isResponse_Value() {} func (m *Response) GetValue() isResponse_Value { if m != nil { @@ -1390,6 +1464,13 @@ func (m *Response) GetApplySnapshotChunk() *ResponseApplySnapshotChunk { return nil } +func (m *Response) GetPrepareProposal() *ResponsePrepareProposal { + if x, ok := m.GetValue().(*Response_PrepareProposal); ok { + return x.PrepareProposal + } + return nil +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*Response) XXX_OneofWrappers() []interface{} { return []interface{}{ @@ -1408,6 +1489,7 @@ func (*Response) XXX_OneofWrappers() []interface{} { (*Response_OfferSnapshot)(nil), (*Response_LoadSnapshotChunk)(nil), (*Response_ApplySnapshotChunk)(nil), + (*Response_PrepareProposal)(nil), } } @@ -1420,7 +1502,7 @@ func (m *ResponseException) Reset() { *m = ResponseException{} } func (m *ResponseException) String() string { return proto.CompactTextString(m) } func (*ResponseException) ProtoMessage() {} func (*ResponseException) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{16} + return fileDescriptor_252557cfdd89a31a, []int{17} } func (m *ResponseException) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1464,7 +1546,7 @@ func (m *ResponseEcho) Reset() { *m = ResponseEcho{} } func (m *ResponseEcho) String() string { return proto.CompactTextString(m) } func (*ResponseEcho) ProtoMessage() {} func (*ResponseEcho) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{17} + return fileDescriptor_252557cfdd89a31a, []int{18} } func (m *ResponseEcho) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1507,7 +1589,7 @@ func (m *ResponseFlush) Reset() { *m = ResponseFlush{} } func (m *ResponseFlush) String() string { return proto.CompactTextString(m) } func (*ResponseFlush) ProtoMessage() {} func (*ResponseFlush) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{18} + return fileDescriptor_252557cfdd89a31a, []int{19} } func (m *ResponseFlush) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1549,7 +1631,7 @@ func (m *ResponseInfo) Reset() { *m = ResponseInfo{} } func (m *ResponseInfo) String() string { return proto.CompactTextString(m) } func (*ResponseInfo) ProtoMessage() {} func (*ResponseInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{19} + return fileDescriptor_252557cfdd89a31a, []int{20} } func (m *ResponseInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1623,7 +1705,7 @@ func (m *ResponseInitChain) Reset() { *m = ResponseInitChain{} } func (m *ResponseInitChain) String() string { return proto.CompactTextString(m) } func (*ResponseInitChain) ProtoMessage() {} func (*ResponseInitChain) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{20} + return fileDescriptor_252557cfdd89a31a, []int{21} } func (m *ResponseInitChain) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1690,7 +1772,7 @@ func (m *ResponseQuery) Reset() { *m = ResponseQuery{} } func (m *ResponseQuery) String() string { return proto.CompactTextString(m) } func (*ResponseQuery) ProtoMessage() {} func (*ResponseQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{21} + return fileDescriptor_252557cfdd89a31a, []int{22} } func (m *ResponseQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1790,7 +1872,7 @@ func (m *ResponseBeginBlock) Reset() { *m = ResponseBeginBlock{} } func (m *ResponseBeginBlock) String() string { return proto.CompactTextString(m) } func (*ResponseBeginBlock) ProtoMessage() {} func (*ResponseBeginBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{22} + return fileDescriptor_252557cfdd89a31a, []int{23} } func (m *ResponseBeginBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1846,7 +1928,7 @@ func (m *ResponseCheckTx) Reset() { *m = ResponseCheckTx{} } func (m *ResponseCheckTx) String() string { return proto.CompactTextString(m) } func (*ResponseCheckTx) ProtoMessage() {} func (*ResponseCheckTx) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{23} + return fileDescriptor_252557cfdd89a31a, []int{24} } func (m *ResponseCheckTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1967,7 +2049,7 @@ func (m *ResponseDeliverTx) Reset() { *m = ResponseDeliverTx{} } func (m *ResponseDeliverTx) String() string { return proto.CompactTextString(m) } func (*ResponseDeliverTx) ProtoMessage() {} func (*ResponseDeliverTx) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{24} + return fileDescriptor_252557cfdd89a31a, []int{25} } func (m *ResponseDeliverTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2062,7 +2144,7 @@ func (m *ResponseEndBlock) Reset() { *m = ResponseEndBlock{} } func (m *ResponseEndBlock) String() string { return proto.CompactTextString(m) } func (*ResponseEndBlock) ProtoMessage() {} func (*ResponseEndBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{25} + return fileDescriptor_252557cfdd89a31a, []int{26} } func (m *ResponseEndBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2122,7 +2204,7 @@ func (m *ResponseCommit) Reset() { *m = ResponseCommit{} } func (m *ResponseCommit) String() string { return proto.CompactTextString(m) } func (*ResponseCommit) ProtoMessage() {} func (*ResponseCommit) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{26} + return fileDescriptor_252557cfdd89a31a, []int{27} } func (m *ResponseCommit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2173,7 +2255,7 @@ func (m *ResponseListSnapshots) Reset() { *m = ResponseListSnapshots{} } func (m *ResponseListSnapshots) String() string { return proto.CompactTextString(m) } func (*ResponseListSnapshots) ProtoMessage() {} func (*ResponseListSnapshots) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{27} + return fileDescriptor_252557cfdd89a31a, []int{28} } func (m *ResponseListSnapshots) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2217,7 +2299,7 @@ func (m *ResponseOfferSnapshot) Reset() { *m = ResponseOfferSnapshot{} } func (m *ResponseOfferSnapshot) String() string { return proto.CompactTextString(m) } func (*ResponseOfferSnapshot) ProtoMessage() {} func (*ResponseOfferSnapshot) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{28} + return fileDescriptor_252557cfdd89a31a, []int{29} } func (m *ResponseOfferSnapshot) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2261,7 +2343,7 @@ func (m *ResponseLoadSnapshotChunk) Reset() { *m = ResponseLoadSnapshotC func (m *ResponseLoadSnapshotChunk) String() string { return proto.CompactTextString(m) } func (*ResponseLoadSnapshotChunk) ProtoMessage() {} func (*ResponseLoadSnapshotChunk) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{29} + return fileDescriptor_252557cfdd89a31a, []int{30} } func (m *ResponseLoadSnapshotChunk) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2307,7 +2389,7 @@ func (m *ResponseApplySnapshotChunk) Reset() { *m = ResponseApplySnapsho func (m *ResponseApplySnapshotChunk) String() string { return proto.CompactTextString(m) } func (*ResponseApplySnapshotChunk) ProtoMessage() {} func (*ResponseApplySnapshotChunk) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{30} + return fileDescriptor_252557cfdd89a31a, []int{31} } func (m *ResponseApplySnapshotChunk) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2357,6 +2439,50 @@ func (m *ResponseApplySnapshotChunk) GetRejectSenders() []string { return nil } +type ResponsePrepareProposal struct { + BlockData *types1.Data `protobuf:"bytes,1,opt,name=block_data,json=blockData,proto3" json:"block_data,omitempty"` +} + +func (m *ResponsePrepareProposal) Reset() { *m = ResponsePrepareProposal{} } +func (m *ResponsePrepareProposal) String() string { return proto.CompactTextString(m) } +func (*ResponsePrepareProposal) ProtoMessage() {} +func (*ResponsePrepareProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{32} +} +func (m *ResponsePrepareProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResponsePrepareProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResponsePrepareProposal.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 *ResponsePrepareProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResponsePrepareProposal.Merge(m, src) +} +func (m *ResponsePrepareProposal) XXX_Size() int { + return m.Size() +} +func (m *ResponsePrepareProposal) XXX_DiscardUnknown() { + xxx_messageInfo_ResponsePrepareProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_ResponsePrepareProposal proto.InternalMessageInfo + +func (m *ResponsePrepareProposal) GetBlockData() *types1.Data { + if m != nil { + return m.BlockData + } + return nil +} + type LastCommitInfo struct { Round int32 `protobuf:"varint,1,opt,name=round,proto3" json:"round,omitempty"` Votes []VoteInfo `protobuf:"bytes,2,rep,name=votes,proto3" json:"votes"` @@ -2366,7 +2492,7 @@ func (m *LastCommitInfo) Reset() { *m = LastCommitInfo{} } func (m *LastCommitInfo) String() string { return proto.CompactTextString(m) } func (*LastCommitInfo) ProtoMessage() {} func (*LastCommitInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{31} + return fileDescriptor_252557cfdd89a31a, []int{33} } func (m *LastCommitInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2421,7 +2547,7 @@ func (m *Event) Reset() { *m = Event{} } func (m *Event) String() string { return proto.CompactTextString(m) } func (*Event) ProtoMessage() {} func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{32} + return fileDescriptor_252557cfdd89a31a, []int{34} } func (m *Event) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2475,7 +2601,7 @@ func (m *EventAttribute) Reset() { *m = EventAttribute{} } func (m *EventAttribute) String() string { return proto.CompactTextString(m) } func (*EventAttribute) ProtoMessage() {} func (*EventAttribute) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{33} + return fileDescriptor_252557cfdd89a31a, []int{35} } func (m *EventAttribute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2540,7 +2666,7 @@ func (m *TxResult) Reset() { *m = TxResult{} } func (m *TxResult) String() string { return proto.CompactTextString(m) } func (*TxResult) ProtoMessage() {} func (*TxResult) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{34} + return fileDescriptor_252557cfdd89a31a, []int{36} } func (m *TxResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2615,7 +2741,7 @@ func (m *Validator) Reset() { *m = Validator{} } func (m *Validator) String() string { return proto.CompactTextString(m) } func (*Validator) ProtoMessage() {} func (*Validator) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{35} + return fileDescriptor_252557cfdd89a31a, []int{37} } func (m *Validator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2668,7 +2794,7 @@ func (m *ValidatorUpdate) Reset() { *m = ValidatorUpdate{} } func (m *ValidatorUpdate) String() string { return proto.CompactTextString(m) } func (*ValidatorUpdate) ProtoMessage() {} func (*ValidatorUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{36} + return fileDescriptor_252557cfdd89a31a, []int{38} } func (m *ValidatorUpdate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2721,7 +2847,7 @@ func (m *VoteInfo) Reset() { *m = VoteInfo{} } func (m *VoteInfo) String() string { return proto.CompactTextString(m) } func (*VoteInfo) ProtoMessage() {} func (*VoteInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{37} + return fileDescriptor_252557cfdd89a31a, []int{39} } func (m *VoteInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2782,7 +2908,7 @@ func (m *Evidence) Reset() { *m = Evidence{} } func (m *Evidence) String() string { return proto.CompactTextString(m) } func (*Evidence) ProtoMessage() {} func (*Evidence) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{38} + return fileDescriptor_252557cfdd89a31a, []int{40} } func (m *Evidence) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2858,7 +2984,7 @@ func (m *Snapshot) Reset() { *m = Snapshot{} } func (m *Snapshot) String() string { return proto.CompactTextString(m) } func (*Snapshot) ProtoMessage() {} func (*Snapshot) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{39} + return fileDescriptor_252557cfdd89a31a, []int{41} } func (m *Snapshot) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2942,6 +3068,7 @@ func init() { proto.RegisterType((*RequestOfferSnapshot)(nil), "tendermint.abci.RequestOfferSnapshot") proto.RegisterType((*RequestLoadSnapshotChunk)(nil), "tendermint.abci.RequestLoadSnapshotChunk") proto.RegisterType((*RequestApplySnapshotChunk)(nil), "tendermint.abci.RequestApplySnapshotChunk") + proto.RegisterType((*RequestPrepareProposal)(nil), "tendermint.abci.RequestPrepareProposal") proto.RegisterType((*Response)(nil), "tendermint.abci.Response") proto.RegisterType((*ResponseException)(nil), "tendermint.abci.ResponseException") proto.RegisterType((*ResponseEcho)(nil), "tendermint.abci.ResponseEcho") @@ -2958,6 +3085,7 @@ func init() { proto.RegisterType((*ResponseOfferSnapshot)(nil), "tendermint.abci.ResponseOfferSnapshot") proto.RegisterType((*ResponseLoadSnapshotChunk)(nil), "tendermint.abci.ResponseLoadSnapshotChunk") proto.RegisterType((*ResponseApplySnapshotChunk)(nil), "tendermint.abci.ResponseApplySnapshotChunk") + proto.RegisterType((*ResponsePrepareProposal)(nil), "tendermint.abci.ResponsePrepareProposal") proto.RegisterType((*LastCommitInfo)(nil), "tendermint.abci.LastCommitInfo") proto.RegisterType((*Event)(nil), "tendermint.abci.Event") proto.RegisterType((*EventAttribute)(nil), "tendermint.abci.EventAttribute") @@ -2972,173 +3100,180 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 2644 bytes of a gzipped FileDescriptorProto + // 2756 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0x4b, 0x73, 0x1b, 0xc7, - 0xf1, 0xc7, 0x1b, 0xd8, 0xc6, 0x83, 0xe0, 0x88, 0x96, 0x61, 0x58, 0x26, 0xe5, 0x55, 0xd9, 0x7f, - 0x4b, 0xb6, 0xc9, 0xbf, 0xa9, 0x92, 0x22, 0x97, 0xf3, 0x30, 0x01, 0x41, 0x01, 0x2d, 0x86, 0x64, - 0x86, 0x90, 0x5c, 0x4e, 0x62, 0xad, 0x17, 0xd8, 0x21, 0xb0, 0x16, 0xb0, 0xbb, 0xde, 0x1d, 0x50, - 0xa4, 0x8f, 0xa9, 0xe4, 0xe2, 0xca, 0x41, 0xc7, 0x5c, 0x5c, 0x95, 0x6f, 0xe0, 0x6b, 0x4e, 0x39, - 0xe5, 0xe0, 0x43, 0x52, 0xe5, 0x63, 0x0e, 0x29, 0x27, 0x25, 0xdd, 0xf2, 0x05, 0x72, 0x4a, 0x55, - 0x6a, 0x1e, 0xbb, 0xd8, 0x05, 0xb0, 0x04, 0x18, 0xe7, 0x96, 0xdb, 0x4c, 0x6f, 0x77, 0x63, 0xa6, - 0x67, 0xfa, 0x37, 0xbf, 0xe9, 0x01, 0xbc, 0x4c, 0x89, 0x65, 0x10, 0x77, 0x64, 0x5a, 0x74, 0x4b, - 0xef, 0xf6, 0xcc, 0x2d, 0x7a, 0xe6, 0x10, 0x6f, 0xd3, 0x71, 0x6d, 0x6a, 0xa3, 0x95, 0xc9, 0xc7, - 0x4d, 0xf6, 0xb1, 0xfe, 0x4a, 0x48, 0xbb, 0xe7, 0x9e, 0x39, 0xd4, 0xde, 0x72, 0x5c, 0xdb, 0x3e, - 0x16, 0xfa, 0xf5, 0x2b, 0xa1, 0xcf, 0xdc, 0x4f, 0xd8, 0x5b, 0xe4, 0xab, 0x34, 0x7e, 0x4c, 0xce, - 0xfc, 0xaf, 0xaf, 0xcc, 0xd8, 0x3a, 0xba, 0xab, 0x8f, 0xfc, 0xcf, 0x1b, 0x7d, 0xdb, 0xee, 0x0f, - 0xc9, 0x16, 0xef, 0x75, 0xc7, 0xc7, 0x5b, 0xd4, 0x1c, 0x11, 0x8f, 0xea, 0x23, 0x47, 0x2a, 0xac, - 0xf5, 0xed, 0xbe, 0xcd, 0x9b, 0x5b, 0xac, 0x25, 0xa4, 0xea, 0x9f, 0xf3, 0x90, 0xc7, 0xe4, 0xb3, - 0x31, 0xf1, 0x28, 0xda, 0x86, 0x0c, 0xe9, 0x0d, 0xec, 0x5a, 0xf2, 0x6a, 0xf2, 0x8d, 0xe2, 0xf6, - 0x95, 0xcd, 0xa9, 0xc9, 0x6d, 0x4a, 0xbd, 0x56, 0x6f, 0x60, 0xb7, 0x13, 0x98, 0xeb, 0xa2, 0x5b, - 0x90, 0x3d, 0x1e, 0x8e, 0xbd, 0x41, 0x2d, 0xc5, 0x8d, 0x5e, 0x89, 0x33, 0xba, 0xc7, 0x94, 0xda, - 0x09, 0x2c, 0xb4, 0xd9, 0x4f, 0x99, 0xd6, 0xb1, 0x5d, 0x4b, 0x9f, 0xff, 0x53, 0xbb, 0xd6, 0x31, - 0xff, 0x29, 0xa6, 0x8b, 0x1a, 0x00, 0xa6, 0x65, 0x52, 0xad, 0x37, 0xd0, 0x4d, 0xab, 0x96, 0xe1, - 0x96, 0xaf, 0xc6, 0x5b, 0x9a, 0xb4, 0xc9, 0x14, 0xdb, 0x09, 0xac, 0x98, 0x7e, 0x87, 0x0d, 0xf7, - 0xb3, 0x31, 0x71, 0xcf, 0x6a, 0xd9, 0xf3, 0x87, 0xfb, 0x53, 0xa6, 0xc4, 0x86, 0xcb, 0xb5, 0x51, - 0x0b, 0x8a, 0x5d, 0xd2, 0x37, 0x2d, 0xad, 0x3b, 0xb4, 0x7b, 0x8f, 0x6b, 0x39, 0x6e, 0xac, 0xc6, - 0x19, 0x37, 0x98, 0x6a, 0x83, 0x69, 0xb6, 0x13, 0x18, 0xba, 0x41, 0x0f, 0x7d, 0x1f, 0x0a, 0xbd, - 0x01, 0xe9, 0x3d, 0xd6, 0xe8, 0x69, 0x2d, 0xcf, 0x7d, 0x6c, 0xc4, 0xf9, 0x68, 0x32, 0xbd, 0xce, - 0x69, 0x3b, 0x81, 0xf3, 0x3d, 0xd1, 0x64, 0xf3, 0x37, 0xc8, 0xd0, 0x3c, 0x21, 0x2e, 0xb3, 0x2f, - 0x9c, 0x3f, 0xff, 0xbb, 0x42, 0x93, 0x7b, 0x50, 0x0c, 0xbf, 0x83, 0x7e, 0x04, 0x0a, 0xb1, 0x0c, - 0x39, 0x0d, 0x85, 0xbb, 0xb8, 0x1a, 0xbb, 0xce, 0x96, 0xe1, 0x4f, 0xa2, 0x40, 0x64, 0x1b, 0xdd, - 0x81, 0x5c, 0xcf, 0x1e, 0x8d, 0x4c, 0x5a, 0x03, 0x6e, 0xbd, 0x1e, 0x3b, 0x01, 0xae, 0xd5, 0x4e, - 0x60, 0xa9, 0x8f, 0xf6, 0xa1, 0x32, 0x34, 0x3d, 0xaa, 0x79, 0x96, 0xee, 0x78, 0x03, 0x9b, 0x7a, - 0xb5, 0x22, 0xf7, 0xf0, 0x5a, 0x9c, 0x87, 0x3d, 0xd3, 0xa3, 0x47, 0xbe, 0x72, 0x3b, 0x81, 0xcb, - 0xc3, 0xb0, 0x80, 0xf9, 0xb3, 0x8f, 0x8f, 0x89, 0x1b, 0x38, 0xac, 0x95, 0xce, 0xf7, 0x77, 0xc0, - 0xb4, 0x7d, 0x7b, 0xe6, 0xcf, 0x0e, 0x0b, 0xd0, 0xcf, 0xe1, 0xd2, 0xd0, 0xd6, 0x8d, 0xc0, 0x9d, - 0xd6, 0x1b, 0x8c, 0xad, 0xc7, 0xb5, 0x32, 0x77, 0x7a, 0x3d, 0x76, 0x90, 0xb6, 0x6e, 0xf8, 0x2e, - 0x9a, 0xcc, 0xa0, 0x9d, 0xc0, 0xab, 0xc3, 0x69, 0x21, 0x7a, 0x04, 0x6b, 0xba, 0xe3, 0x0c, 0xcf, - 0xa6, 0xbd, 0x57, 0xb8, 0xf7, 0x1b, 0x71, 0xde, 0x77, 0x98, 0xcd, 0xb4, 0x7b, 0xa4, 0xcf, 0x48, - 0x1b, 0x79, 0xc8, 0x9e, 0xe8, 0xc3, 0x31, 0x51, 0xff, 0x0f, 0x8a, 0xa1, 0x34, 0x45, 0x35, 0xc8, - 0x8f, 0x88, 0xe7, 0xe9, 0x7d, 0xc2, 0xb3, 0x5a, 0xc1, 0x7e, 0x57, 0xad, 0x40, 0x29, 0x9c, 0x9a, - 0xea, 0xd3, 0x64, 0x60, 0xc9, 0xb2, 0x8e, 0x59, 0x9e, 0x10, 0xd7, 0x33, 0x6d, 0xcb, 0xb7, 0x94, - 0x5d, 0x74, 0x0d, 0xca, 0x7c, 0xff, 0x68, 0xfe, 0x77, 0x96, 0xfa, 0x19, 0x5c, 0xe2, 0xc2, 0x87, - 0x52, 0x69, 0x03, 0x8a, 0xce, 0xb6, 0x13, 0xa8, 0xa4, 0xb9, 0x0a, 0x38, 0xdb, 0x8e, 0xaf, 0xf0, - 0x2a, 0x94, 0xd8, 0x4c, 0x03, 0x8d, 0x0c, 0xff, 0x91, 0x22, 0x93, 0x49, 0x15, 0xf5, 0x4f, 0x29, - 0xa8, 0x4e, 0xa7, 0x33, 0xba, 0x03, 0x19, 0x86, 0x6c, 0x12, 0xa4, 0xea, 0x9b, 0x02, 0xf6, 0x36, - 0x7d, 0xd8, 0xdb, 0xec, 0xf8, 0xb0, 0xd7, 0x28, 0x7c, 0xfd, 0xed, 0x46, 0xe2, 0xe9, 0xdf, 0x36, - 0x92, 0x98, 0x5b, 0xa0, 0x97, 0x58, 0xf6, 0xe9, 0xa6, 0xa5, 0x99, 0x06, 0x1f, 0xb2, 0xc2, 0x52, - 0x4b, 0x37, 0xad, 0x5d, 0x03, 0xed, 0x41, 0xb5, 0x67, 0x5b, 0x1e, 0xb1, 0xbc, 0xb1, 0xa7, 0x09, - 0x58, 0x95, 0xd0, 0x14, 0x49, 0x30, 0x01, 0xd6, 0x4d, 0x5f, 0xf3, 0x90, 0x2b, 0xe2, 0x95, 0x5e, - 0x54, 0x80, 0xee, 0x01, 0x9c, 0xe8, 0x43, 0xd3, 0xd0, 0xa9, 0xed, 0x7a, 0xb5, 0xcc, 0xd5, 0xf4, - 0xdc, 0x2c, 0x7b, 0xe8, 0xab, 0x3c, 0x70, 0x0c, 0x9d, 0x92, 0x46, 0x86, 0x0d, 0x17, 0x87, 0x2c, - 0xd1, 0xeb, 0xb0, 0xa2, 0x3b, 0x8e, 0xe6, 0x51, 0x9d, 0x12, 0xad, 0x7b, 0x46, 0x89, 0xc7, 0x61, - 0xab, 0x84, 0xcb, 0xba, 0xe3, 0x1c, 0x31, 0x69, 0x83, 0x09, 0xd1, 0x6b, 0x50, 0x61, 0x08, 0x67, - 0xea, 0x43, 0x6d, 0x40, 0xcc, 0xfe, 0x80, 0x72, 0x80, 0x4a, 0xe3, 0xb2, 0x94, 0xb6, 0xb9, 0x50, - 0x35, 0x82, 0x15, 0xe7, 0xe8, 0x86, 0x10, 0x64, 0x0c, 0x9d, 0xea, 0x3c, 0x92, 0x25, 0xcc, 0xdb, - 0x4c, 0xe6, 0xe8, 0x74, 0x20, 0xe3, 0xc3, 0xdb, 0xe8, 0x32, 0xe4, 0xa4, 0xdb, 0x34, 0x77, 0x2b, - 0x7b, 0x68, 0x0d, 0xb2, 0x8e, 0x6b, 0x9f, 0x10, 0xbe, 0x74, 0x05, 0x2c, 0x3a, 0xea, 0xaf, 0x52, - 0xb0, 0x3a, 0x83, 0x83, 0xcc, 0xef, 0x40, 0xf7, 0x06, 0xfe, 0x6f, 0xb1, 0x36, 0xba, 0xcd, 0xfc, - 0xea, 0x06, 0x71, 0xe5, 0xd9, 0x51, 0x9b, 0x0d, 0x75, 0x9b, 0x7f, 0x97, 0xa1, 0x91, 0xda, 0xe8, - 0x00, 0xaa, 0x43, 0xdd, 0xa3, 0x9a, 0xc0, 0x15, 0x2d, 0x74, 0x8e, 0xcc, 0xa2, 0xe9, 0x9e, 0xee, - 0x23, 0x11, 0xdb, 0xd4, 0xd2, 0x51, 0x65, 0x18, 0x91, 0x22, 0x0c, 0x6b, 0xdd, 0xb3, 0xcf, 0x75, - 0x8b, 0x9a, 0x16, 0xd1, 0x66, 0x56, 0xee, 0xa5, 0x19, 0xa7, 0xad, 0x13, 0xd3, 0x20, 0x56, 0xcf, - 0x5f, 0xb2, 0x4b, 0x81, 0x71, 0xb0, 0xa4, 0x9e, 0x8a, 0xa1, 0x12, 0x45, 0x72, 0x54, 0x81, 0x14, - 0x3d, 0x95, 0x01, 0x48, 0xd1, 0x53, 0xf4, 0xff, 0x90, 0x61, 0x93, 0xe4, 0x93, 0xaf, 0xcc, 0x39, - 0x02, 0xa5, 0x5d, 0xe7, 0xcc, 0x21, 0x98, 0x6b, 0xaa, 0x6a, 0x90, 0x0e, 0x01, 0xba, 0x4f, 0x7b, - 0x55, 0xaf, 0xc3, 0xca, 0x14, 0x7c, 0x87, 0xd6, 0x2f, 0x19, 0x5e, 0x3f, 0x75, 0x05, 0xca, 0x11, - 0xac, 0x56, 0x2f, 0xc3, 0xda, 0x3c, 0xe8, 0x55, 0x07, 0x81, 0x3c, 0x02, 0xa1, 0xe8, 0x16, 0x14, - 0x02, 0xec, 0x15, 0xe9, 0x38, 0x1b, 0x2b, 0x5f, 0x19, 0x07, 0xaa, 0x2c, 0x0f, 0xd9, 0xb6, 0xe6, - 0xfb, 0x21, 0xc5, 0x07, 0x9e, 0xd7, 0x1d, 0xa7, 0xad, 0x7b, 0x03, 0xf5, 0x13, 0xa8, 0xc5, 0xe1, - 0xea, 0xd4, 0x34, 0x32, 0xc1, 0x36, 0xbc, 0x0c, 0xb9, 0x63, 0xdb, 0x1d, 0xe9, 0x94, 0x3b, 0x2b, - 0x63, 0xd9, 0x63, 0xdb, 0x53, 0x60, 0x6c, 0x9a, 0x8b, 0x45, 0x47, 0xd5, 0xe0, 0xa5, 0x58, 0x6c, - 0x65, 0x26, 0xa6, 0x65, 0x10, 0x11, 0xcf, 0x32, 0x16, 0x9d, 0x89, 0x23, 0x31, 0x58, 0xd1, 0x61, - 0x3f, 0xeb, 0xf1, 0xb9, 0x72, 0xff, 0x0a, 0x96, 0x3d, 0xf5, 0x77, 0x05, 0x28, 0x60, 0xe2, 0x39, - 0x0c, 0x13, 0x50, 0x03, 0x14, 0x72, 0xda, 0x23, 0x0e, 0xf5, 0x61, 0x74, 0x3e, 0x6b, 0x10, 0xda, - 0x2d, 0x5f, 0x93, 0x1d, 0xd9, 0x81, 0x19, 0xba, 0x29, 0x59, 0x59, 0x3c, 0xc1, 0x92, 0xe6, 0x61, - 0x5a, 0x76, 0xdb, 0xa7, 0x65, 0xe9, 0xd8, 0x53, 0x5a, 0x58, 0x4d, 0xf1, 0xb2, 0x9b, 0x92, 0x97, - 0x65, 0x16, 0xfc, 0x58, 0x84, 0x98, 0x35, 0x23, 0xc4, 0x2c, 0xbb, 0x60, 0x9a, 0x31, 0xcc, 0xec, - 0xb6, 0xcf, 0xcc, 0x72, 0x0b, 0x46, 0x3c, 0x45, 0xcd, 0xee, 0x45, 0xa9, 0x99, 0xa0, 0x55, 0xd7, - 0x62, 0xad, 0x63, 0xb9, 0xd9, 0x0f, 0x42, 0xdc, 0xac, 0x10, 0x4b, 0x8c, 0x84, 0x93, 0x39, 0xe4, - 0xac, 0x19, 0x21, 0x67, 0xca, 0x82, 0x18, 0xc4, 0xb0, 0xb3, 0xf7, 0xc3, 0xec, 0x0c, 0x62, 0x09, - 0x9e, 0x5c, 0xef, 0x79, 0xf4, 0xec, 0xdd, 0x80, 0x9e, 0x15, 0x63, 0xf9, 0xa5, 0x9c, 0xc3, 0x34, - 0x3f, 0x3b, 0x98, 0xe1, 0x67, 0x82, 0x4f, 0xbd, 0x1e, 0xeb, 0x62, 0x01, 0x41, 0x3b, 0x98, 0x21, - 0x68, 0xe5, 0x05, 0x0e, 0x17, 0x30, 0xb4, 0x5f, 0xcc, 0x67, 0x68, 0xf1, 0x1c, 0x4a, 0x0e, 0x73, - 0x39, 0x8a, 0xa6, 0xc5, 0x50, 0xb4, 0x15, 0xee, 0xfe, 0xcd, 0x58, 0xf7, 0x17, 0xe7, 0x68, 0xd7, - 0xd9, 0x09, 0x39, 0x95, 0xf3, 0x0c, 0x65, 0x88, 0xeb, 0xda, 0xae, 0x64, 0x5b, 0xa2, 0xa3, 0xbe, - 0xc1, 0xce, 0xec, 0x49, 0x7e, 0x9f, 0xc3, 0xe7, 0x38, 0x9a, 0x87, 0x72, 0x5a, 0xfd, 0x7d, 0x72, - 0x62, 0xcb, 0x8f, 0xb9, 0xf0, 0x79, 0xaf, 0xc8, 0xf3, 0x3e, 0xc4, 0xf2, 0x52, 0x51, 0x96, 0xb7, - 0x01, 0x45, 0x86, 0xd2, 0x53, 0x04, 0x4e, 0x77, 0x02, 0x02, 0x77, 0x03, 0x56, 0xf9, 0x31, 0x2c, - 0xb8, 0xa0, 0x84, 0xe6, 0x0c, 0x3f, 0x61, 0x56, 0xd8, 0x07, 0xb1, 0x39, 0x05, 0x46, 0xbf, 0x0d, - 0x97, 0x42, 0xba, 0x01, 0xfa, 0x0b, 0x36, 0x53, 0x0d, 0xb4, 0x77, 0xe4, 0x31, 0xf0, 0xc7, 0xe4, - 0x24, 0x42, 0x13, 0xe6, 0x37, 0x8f, 0xa4, 0x25, 0xff, 0x4b, 0x24, 0x2d, 0xf5, 0x1f, 0x93, 0xb4, - 0xf0, 0x69, 0x96, 0x8e, 0x9e, 0x66, 0xff, 0x4c, 0x4e, 0xd6, 0x24, 0xa0, 0x5c, 0x3d, 0xdb, 0x20, - 0xf2, 0x7c, 0xe1, 0x6d, 0x54, 0x85, 0xf4, 0xd0, 0xee, 0xcb, 0x53, 0x84, 0x35, 0x99, 0x56, 0x00, - 0xc2, 0x8a, 0xc4, 0xd8, 0xe0, 0x68, 0xca, 0xf2, 0x08, 0xcb, 0xa3, 0xa9, 0x0a, 0xe9, 0xc7, 0x44, - 0x40, 0x66, 0x09, 0xb3, 0x26, 0xd3, 0xe3, 0x9b, 0x8c, 0x03, 0x61, 0x09, 0x8b, 0x0e, 0xba, 0x03, - 0x0a, 0x2f, 0x43, 0x68, 0xb6, 0xe3, 0x49, 0x74, 0x7b, 0x39, 0x3c, 0x57, 0x51, 0x6d, 0xd8, 0x3c, - 0x64, 0x3a, 0x07, 0x8e, 0x87, 0x0b, 0x8e, 0x6c, 0x85, 0x4e, 0x5d, 0x25, 0x42, 0xfe, 0xae, 0x80, - 0xc2, 0x46, 0xef, 0x39, 0x7a, 0x8f, 0x70, 0xa8, 0x52, 0xf0, 0x44, 0xa0, 0x3e, 0x02, 0x34, 0x0b, - 0xb8, 0xa8, 0x0d, 0x39, 0x72, 0x42, 0x2c, 0xca, 0x96, 0x8d, 0x85, 0xfb, 0xf2, 0x1c, 0x66, 0x45, - 0x2c, 0xda, 0xa8, 0xb1, 0x20, 0xff, 0xe3, 0xdb, 0x8d, 0xaa, 0xd0, 0x7e, 0xcb, 0x1e, 0x99, 0x94, - 0x8c, 0x1c, 0x7a, 0x86, 0xa5, 0xbd, 0xfa, 0xd7, 0x14, 0xa3, 0x39, 0x11, 0x30, 0x9e, 0x1b, 0x5b, - 0x7f, 0xcb, 0xa7, 0x42, 0x14, 0x77, 0xb9, 0x78, 0xaf, 0x03, 0xf4, 0x75, 0x4f, 0x7b, 0xa2, 0x5b, - 0x94, 0x18, 0x32, 0xe8, 0x21, 0x09, 0xaa, 0x43, 0x81, 0xf5, 0xc6, 0x1e, 0x31, 0x24, 0xdb, 0x0e, - 0xfa, 0xa1, 0x79, 0xe6, 0xbf, 0xdb, 0x3c, 0xa3, 0x51, 0x2e, 0x4c, 0x45, 0x39, 0x44, 0x41, 0x94, - 0x30, 0x05, 0x61, 0x63, 0x73, 0x5c, 0xd3, 0x76, 0x4d, 0x7a, 0xc6, 0x97, 0x26, 0x8d, 0x83, 0x3e, - 0xbb, 0xbc, 0x8d, 0xc8, 0xc8, 0xb1, 0xed, 0xa1, 0x26, 0xe0, 0xa6, 0xc8, 0x4d, 0x4b, 0x52, 0xd8, - 0xe2, 0xa8, 0xf3, 0xeb, 0xd4, 0x24, 0xff, 0x26, 0x54, 0xf3, 0x7f, 0x2e, 0xc0, 0xea, 0x6f, 0xf8, - 0x05, 0x34, 0x7a, 0xdc, 0xa2, 0x23, 0x58, 0x0d, 0xd2, 0x5f, 0x1b, 0x73, 0x58, 0xf0, 0x37, 0xf4, - 0xb2, 0xf8, 0x51, 0x3d, 0x89, 0x8a, 0x3d, 0xf4, 0x11, 0xbc, 0x38, 0x85, 0x6d, 0x81, 0xeb, 0xd4, - 0xb2, 0x10, 0xf7, 0x42, 0x14, 0xe2, 0x7c, 0xd7, 0x93, 0x60, 0xa5, 0xbf, 0x63, 0xd6, 0xed, 0xb2, - 0x3b, 0x4d, 0x98, 0x3d, 0xcc, 0x5d, 0xfe, 0x6b, 0x50, 0x76, 0x09, 0x65, 0xf7, 0xec, 0xc8, 0xad, - 0xb1, 0x24, 0x84, 0xf2, 0x2e, 0x7a, 0x08, 0x2f, 0xcc, 0x65, 0x11, 0xe8, 0x7b, 0xa0, 0x4c, 0x08, - 0x48, 0x32, 0xe6, 0x02, 0x16, 0x5c, 0x2a, 0x26, 0xba, 0xea, 0x1f, 0x92, 0x13, 0x97, 0xd1, 0x6b, - 0x4a, 0x0b, 0x72, 0x2e, 0xf1, 0xc6, 0x43, 0x71, 0x71, 0xa8, 0x6c, 0xbf, 0xbd, 0x1c, 0xff, 0x60, - 0xd2, 0xf1, 0x90, 0x62, 0x69, 0xac, 0x3e, 0x82, 0x9c, 0x90, 0xa0, 0x22, 0xe4, 0x1f, 0xec, 0xdf, - 0xdf, 0x3f, 0xf8, 0x70, 0xbf, 0x9a, 0x40, 0x00, 0xb9, 0x9d, 0x66, 0xb3, 0x75, 0xd8, 0xa9, 0x26, - 0x91, 0x02, 0xd9, 0x9d, 0xc6, 0x01, 0xee, 0x54, 0x53, 0x4c, 0x8c, 0x5b, 0x1f, 0xb4, 0x9a, 0x9d, - 0x6a, 0x1a, 0xad, 0x42, 0x59, 0xb4, 0xb5, 0x7b, 0x07, 0xf8, 0x27, 0x3b, 0x9d, 0x6a, 0x26, 0x24, - 0x3a, 0x6a, 0xed, 0xdf, 0x6d, 0xe1, 0x6a, 0x56, 0x7d, 0x87, 0xdd, 0x4c, 0x62, 0x18, 0xcb, 0xe4, - 0x0e, 0x92, 0x0c, 0xdd, 0x41, 0xd4, 0xdf, 0xa6, 0xa0, 0x1e, 0x4f, 0x43, 0xd0, 0x07, 0x53, 0x13, - 0xdf, 0xbe, 0x00, 0x87, 0x99, 0x9a, 0x3d, 0x7a, 0x0d, 0x2a, 0x2e, 0x39, 0x26, 0xb4, 0x37, 0x10, - 0xb4, 0x48, 0x1c, 0x99, 0x65, 0x5c, 0x96, 0x52, 0x6e, 0xe4, 0x09, 0xb5, 0x4f, 0x49, 0x8f, 0x6a, - 0x02, 0x8b, 0xc4, 0xa6, 0x53, 0x98, 0x1a, 0x93, 0x1e, 0x09, 0xa1, 0xfa, 0xc9, 0x85, 0x62, 0xa9, - 0x40, 0x16, 0xb7, 0x3a, 0xf8, 0xa3, 0x6a, 0x1a, 0x21, 0xa8, 0xf0, 0xa6, 0x76, 0xb4, 0xbf, 0x73, - 0x78, 0xd4, 0x3e, 0x60, 0xb1, 0xbc, 0x04, 0x2b, 0x7e, 0x2c, 0x7d, 0x61, 0x56, 0xfd, 0x18, 0x2a, - 0xd1, 0xbb, 0x3f, 0x0b, 0xa1, 0x6b, 0x8f, 0x2d, 0x83, 0x07, 0x23, 0x8b, 0x45, 0x07, 0xdd, 0x82, - 0xec, 0x89, 0x2d, 0xd2, 0x6c, 0xfe, 0x5e, 0x7b, 0x68, 0x53, 0x12, 0xaa, 0x1d, 0x08, 0x6d, 0xf5, - 0x73, 0xc8, 0xf2, 0xac, 0x61, 0x19, 0xc0, 0x6f, 0xf1, 0x92, 0x54, 0xb1, 0x36, 0xfa, 0x18, 0x40, - 0xa7, 0xd4, 0x35, 0xbb, 0xe3, 0x89, 0xe3, 0x8d, 0xf9, 0x59, 0xb7, 0xe3, 0xeb, 0x35, 0xae, 0xc8, - 0xf4, 0x5b, 0x9b, 0x98, 0x86, 0x52, 0x30, 0xe4, 0x50, 0xdd, 0x87, 0x4a, 0xd4, 0xd6, 0xa7, 0x01, - 0x62, 0x0c, 0x51, 0x1a, 0x20, 0x58, 0x9d, 0xa4, 0x01, 0x01, 0x89, 0x48, 0x8b, 0x8a, 0x0d, 0xef, - 0xa8, 0x5f, 0x25, 0xa1, 0xd0, 0x39, 0x95, 0xeb, 0x11, 0x53, 0x2c, 0x98, 0x98, 0xa6, 0xc2, 0x57, - 0x63, 0x51, 0x7d, 0x48, 0x07, 0x35, 0x8d, 0xf7, 0x83, 0x1d, 0x97, 0x59, 0xf6, 0x06, 0xe4, 0x17, - 0x77, 0xe4, 0x3e, 0xbb, 0x06, 0x65, 0xdb, 0x35, 0xfb, 0xa6, 0xa5, 0x0f, 0xc3, 0x1c, 0xb1, 0xe4, - 0x0b, 0x39, 0xb1, 0x7a, 0x0f, 0x94, 0x00, 0x58, 0x19, 0x85, 0xd5, 0x0d, 0xc3, 0x25, 0x9e, 0x27, - 0x93, 0xc3, 0xef, 0xf2, 0x02, 0x95, 0xfd, 0x44, 0xde, 0xd0, 0xd3, 0x58, 0x74, 0x54, 0x03, 0x56, - 0xa6, 0x50, 0x19, 0xbd, 0x07, 0x79, 0x67, 0xdc, 0xd5, 0xfc, 0x18, 0x4e, 0x3d, 0x48, 0xf8, 0xe4, - 0x68, 0xdc, 0x1d, 0x9a, 0xbd, 0xfb, 0xe4, 0xcc, 0x1f, 0xb1, 0x33, 0xee, 0xde, 0x17, 0xa1, 0x16, - 0xbf, 0x92, 0x0a, 0xff, 0xca, 0x09, 0x14, 0xfc, 0x9d, 0x83, 0x7e, 0x08, 0x4a, 0x00, 0xf8, 0x41, - 0xdd, 0x32, 0xf6, 0xa4, 0x90, 0xee, 0x27, 0x26, 0x8c, 0x69, 0x7b, 0x66, 0xdf, 0x22, 0x86, 0x36, - 0x21, 0xd1, 0xfc, 0xd7, 0x0a, 0x78, 0x45, 0x7c, 0xd8, 0xf3, 0x19, 0xb4, 0xfa, 0xaf, 0x24, 0x14, - 0xfc, 0xfa, 0x14, 0x7a, 0x27, 0xb4, 0x39, 0x2b, 0x73, 0x6e, 0xf3, 0xbe, 0xe2, 0xa4, 0xc6, 0x14, - 0x1d, 0x6b, 0xea, 0xe2, 0x63, 0x8d, 0x2b, 0x16, 0xfa, 0x65, 0xdb, 0xcc, 0x85, 0xcb, 0xb6, 0x6f, - 0x01, 0xa2, 0x36, 0xd5, 0x87, 0xda, 0x89, 0x4d, 0x4d, 0xab, 0xaf, 0x89, 0x60, 0x0b, 0xc2, 0x50, - 0xe5, 0x5f, 0x1e, 0xf2, 0x0f, 0x87, 0x3c, 0xee, 0xbf, 0x4c, 0x42, 0x21, 0x40, 0xfe, 0x8b, 0x96, - 0x8c, 0x2e, 0x43, 0x4e, 0x82, 0x9b, 0xa8, 0x19, 0xc9, 0x5e, 0x50, 0xbd, 0xcc, 0x84, 0xaa, 0x97, - 0x75, 0x28, 0x8c, 0x08, 0xd5, 0xf9, 0xf1, 0x27, 0xf6, 0x68, 0xd0, 0xbf, 0xf1, 0x2e, 0x14, 0x43, - 0xd5, 0x3b, 0x96, 0x9e, 0xfb, 0xad, 0x0f, 0xab, 0x89, 0x7a, 0xfe, 0x8b, 0x2f, 0xaf, 0xa6, 0xf7, - 0xc9, 0x13, 0xb6, 0x67, 0x71, 0xab, 0xd9, 0x6e, 0x35, 0xef, 0x57, 0x93, 0xf5, 0xe2, 0x17, 0x5f, - 0x5e, 0xcd, 0x63, 0xc2, 0x2b, 0x09, 0x37, 0xda, 0x50, 0x0a, 0xaf, 0x4a, 0x14, 0x1f, 0x11, 0x54, - 0xee, 0x3e, 0x38, 0xdc, 0xdb, 0x6d, 0xee, 0x74, 0x5a, 0xda, 0xc3, 0x83, 0x4e, 0xab, 0x9a, 0x44, - 0x2f, 0xc2, 0xa5, 0xbd, 0xdd, 0x1f, 0xb7, 0x3b, 0x5a, 0x73, 0x6f, 0xb7, 0xb5, 0xdf, 0xd1, 0x76, - 0x3a, 0x9d, 0x9d, 0xe6, 0xfd, 0x6a, 0x6a, 0xfb, 0x2b, 0x05, 0x56, 0x76, 0x1a, 0xcd, 0x5d, 0x86, - 0xed, 0x66, 0x4f, 0xe7, 0x97, 0xcc, 0x26, 0x64, 0xf8, 0x35, 0xf2, 0xdc, 0xb7, 0xbd, 0xfa, 0xf9, - 0x35, 0x26, 0x74, 0x0f, 0xb2, 0xfc, 0x86, 0x89, 0xce, 0x7f, 0xec, 0xab, 0x2f, 0x28, 0x3a, 0xb1, - 0xc1, 0xf0, 0xf4, 0x38, 0xf7, 0xf5, 0xaf, 0x7e, 0x7e, 0x0d, 0x0a, 0x61, 0x50, 0x26, 0x0c, 0x75, - 0xf1, 0x6b, 0x58, 0x7d, 0x09, 0x44, 0x42, 0x7b, 0x90, 0xf7, 0x2f, 0x15, 0x8b, 0xde, 0xe7, 0xea, - 0x0b, 0x8b, 0x44, 0x2c, 0x5c, 0xe2, 0xf2, 0x77, 0xfe, 0x63, 0x63, 0x7d, 0x41, 0xc5, 0x0b, 0xed, - 0x42, 0x4e, 0xb2, 0xae, 0x05, 0x6f, 0x6e, 0xf5, 0x45, 0x45, 0x1f, 0x16, 0xb4, 0xc9, 0xb5, 0x7a, - 0xf1, 0x13, 0x6a, 0x7d, 0x89, 0x62, 0x1e, 0x7a, 0x00, 0x10, 0xba, 0xea, 0x2d, 0xf1, 0x36, 0x5a, - 0x5f, 0xa6, 0x48, 0x87, 0x0e, 0xa0, 0x10, 0x30, 0xef, 0x85, 0x2f, 0x95, 0xf5, 0xc5, 0xd5, 0x32, - 0xf4, 0x08, 0xca, 0x51, 0xc6, 0xb9, 0xdc, 0xfb, 0x63, 0x7d, 0xc9, 0x32, 0x18, 0xf3, 0x1f, 0xa5, - 0x9f, 0xcb, 0xbd, 0x47, 0xd6, 0x97, 0xac, 0x8a, 0xa1, 0x4f, 0x61, 0x75, 0x96, 0x1e, 0x2e, 0xff, - 0x3c, 0x59, 0xbf, 0x40, 0x9d, 0x0c, 0x8d, 0x00, 0xcd, 0xa1, 0x95, 0x17, 0x78, 0xad, 0xac, 0x5f, - 0xa4, 0x6c, 0xd6, 0x68, 0x7d, 0xfd, 0x6c, 0x3d, 0xf9, 0xcd, 0xb3, 0xf5, 0xe4, 0xdf, 0x9f, 0xad, - 0x27, 0x9f, 0x3e, 0x5f, 0x4f, 0x7c, 0xf3, 0x7c, 0x3d, 0xf1, 0x97, 0xe7, 0xeb, 0x89, 0x9f, 0xbd, - 0xd9, 0x37, 0xe9, 0x60, 0xdc, 0xdd, 0xec, 0xd9, 0xa3, 0xad, 0xf0, 0xdf, 0x20, 0xe6, 0xfd, 0x35, - 0xa3, 0x9b, 0xe3, 0x87, 0xca, 0xcd, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0xbd, 0x86, 0x4c, 0x97, - 0xba, 0x21, 0x00, 0x00, + 0xf1, 0xc7, 0x93, 0xc0, 0x36, 0x9e, 0x1a, 0xc9, 0x32, 0x0c, 0xcb, 0xa4, 0xbc, 0x2a, 0xbf, 0x64, + 0x9b, 0xfc, 0x9b, 0x2e, 0xf9, 0x6f, 0x97, 0xf3, 0x30, 0x01, 0x41, 0x01, 0x2d, 0x86, 0x64, 0x86, + 0x90, 0x5c, 0x4e, 0x62, 0xad, 0x17, 0xd8, 0x21, 0xb0, 0x16, 0xb0, 0xbb, 0xde, 0x1d, 0x50, 0xa4, + 0x8e, 0xa9, 0xe4, 0xe2, 0xca, 0xc1, 0x97, 0x54, 0xe5, 0xe2, 0x53, 0x3e, 0x40, 0xae, 0x39, 0xe5, + 0x94, 0x83, 0x0f, 0x39, 0xf8, 0x98, 0x43, 0xca, 0x49, 0x59, 0xb7, 0x7c, 0x01, 0x9f, 0x52, 0x95, + 0x9a, 0xc7, 0xbe, 0x00, 0x2c, 0x01, 0xda, 0xb9, 0xe5, 0x36, 0xd3, 0xdb, 0xdd, 0x98, 0xe9, 0x99, + 0xf9, 0xf5, 0x6f, 0x7a, 0x00, 0xcf, 0x52, 0x62, 0x19, 0xc4, 0x9d, 0x98, 0x16, 0xdd, 0xd2, 0xfb, + 0x03, 0x73, 0x8b, 0x9e, 0x39, 0xc4, 0xdb, 0x74, 0x5c, 0x9b, 0xda, 0xa8, 0x16, 0x7e, 0xdc, 0x64, + 0x1f, 0x9b, 0xcf, 0x45, 0xb4, 0x07, 0xee, 0x99, 0x43, 0xed, 0x2d, 0xc7, 0xb5, 0xed, 0x63, 0xa1, + 0xdf, 0xbc, 0x16, 0xf9, 0xcc, 0xfd, 0x44, 0xbd, 0xc5, 0xbe, 0x4a, 0xe3, 0x87, 0xe4, 0xcc, 0xff, + 0xfa, 0xdc, 0x9c, 0xad, 0xa3, 0xbb, 0xfa, 0xc4, 0xff, 0xbc, 0x31, 0xb4, 0xed, 0xe1, 0x98, 0x6c, + 0xf1, 0x5e, 0x7f, 0x7a, 0xbc, 0x45, 0xcd, 0x09, 0xf1, 0xa8, 0x3e, 0x71, 0xa4, 0xc2, 0x95, 0xa1, + 0x3d, 0xb4, 0x79, 0x73, 0x8b, 0xb5, 0x84, 0x54, 0xfd, 0x43, 0x11, 0x0a, 0x98, 0x7c, 0x3a, 0x25, + 0x1e, 0x45, 0xdb, 0x90, 0x23, 0x83, 0x91, 0xdd, 0x48, 0x5f, 0x4f, 0xbf, 0x5c, 0xda, 0xbe, 0xb6, + 0x39, 0x33, 0xb9, 0x4d, 0xa9, 0xd7, 0x19, 0x8c, 0xec, 0x6e, 0x0a, 0x73, 0x5d, 0x74, 0x0b, 0xf2, + 0xc7, 0xe3, 0xa9, 0x37, 0x6a, 0x64, 0xb8, 0xd1, 0x73, 0x49, 0x46, 0x77, 0x98, 0x52, 0x37, 0x85, + 0x85, 0x36, 0xfb, 0x29, 0xd3, 0x3a, 0xb6, 0x1b, 0xd9, 0xf3, 0x7f, 0x6a, 0xd7, 0x3a, 0xe6, 0x3f, + 0xc5, 0x74, 0x51, 0x0b, 0xc0, 0xb4, 0x4c, 0xaa, 0x0d, 0x46, 0xba, 0x69, 0x35, 0x72, 0xdc, 0xf2, + 0xf9, 0x64, 0x4b, 0x93, 0xb6, 0x99, 0x62, 0x37, 0x85, 0x15, 0xd3, 0xef, 0xb0, 0xe1, 0x7e, 0x3a, + 0x25, 0xee, 0x59, 0x23, 0x7f, 0xfe, 0x70, 0x7f, 0xc6, 0x94, 0xd8, 0x70, 0xb9, 0x36, 0xea, 0x40, + 0xa9, 0x4f, 0x86, 0xa6, 0xa5, 0xf5, 0xc7, 0xf6, 0xe0, 0x61, 0x63, 0x8d, 0x1b, 0xab, 0x49, 0xc6, + 0x2d, 0xa6, 0xda, 0x62, 0x9a, 0xdd, 0x14, 0x86, 0x7e, 0xd0, 0x43, 0x3f, 0x80, 0xe2, 0x60, 0x44, + 0x06, 0x0f, 0x35, 0x7a, 0xda, 0x28, 0x70, 0x1f, 0x1b, 0x49, 0x3e, 0xda, 0x4c, 0xaf, 0x77, 0xda, + 0x4d, 0xe1, 0xc2, 0x40, 0x34, 0xd9, 0xfc, 0x0d, 0x32, 0x36, 0x4f, 0x88, 0xcb, 0xec, 0x8b, 0xe7, + 0xcf, 0xff, 0xb6, 0xd0, 0xe4, 0x1e, 0x14, 0xc3, 0xef, 0xa0, 0x1f, 0x83, 0x42, 0x2c, 0x43, 0x4e, + 0x43, 0xe1, 0x2e, 0xae, 0x27, 0xae, 0xb3, 0x65, 0xf8, 0x93, 0x28, 0x12, 0xd9, 0x46, 0x6f, 0xc3, + 0xda, 0xc0, 0x9e, 0x4c, 0x4c, 0xda, 0x00, 0x6e, 0xbd, 0x9e, 0x38, 0x01, 0xae, 0xd5, 0x4d, 0x61, + 0xa9, 0x8f, 0xf6, 0xa1, 0x3a, 0x36, 0x3d, 0xaa, 0x79, 0x96, 0xee, 0x78, 0x23, 0x9b, 0x7a, 0x8d, + 0x12, 0xf7, 0xf0, 0x42, 0x92, 0x87, 0x3d, 0xd3, 0xa3, 0x47, 0xbe, 0x72, 0x37, 0x85, 0x2b, 0xe3, + 0xa8, 0x80, 0xf9, 0xb3, 0x8f, 0x8f, 0x89, 0x1b, 0x38, 0x6c, 0x94, 0xcf, 0xf7, 0x77, 0xc0, 0xb4, + 0x7d, 0x7b, 0xe6, 0xcf, 0x8e, 0x0a, 0xd0, 0x2f, 0xe0, 0xf2, 0xd8, 0xd6, 0x8d, 0xc0, 0x9d, 0x36, + 0x18, 0x4d, 0xad, 0x87, 0x8d, 0x0a, 0x77, 0xfa, 0x4a, 0xe2, 0x20, 0x6d, 0xdd, 0xf0, 0x5d, 0xb4, + 0x99, 0x41, 0x37, 0x85, 0x2f, 0x8d, 0x67, 0x85, 0xe8, 0x01, 0x5c, 0xd1, 0x1d, 0x67, 0x7c, 0x36, + 0xeb, 0xbd, 0xca, 0xbd, 0xdf, 0x4c, 0xf2, 0xbe, 0xc3, 0x6c, 0x66, 0xdd, 0x23, 0x7d, 0x4e, 0x8a, + 0x7a, 0x50, 0x77, 0x5c, 0xe2, 0xe8, 0x2e, 0xd1, 0x1c, 0xd7, 0x76, 0x6c, 0x4f, 0x1f, 0x37, 0x6a, + 0xdc, 0xf7, 0x4b, 0x49, 0xbe, 0x0f, 0x85, 0xfe, 0xa1, 0x54, 0xef, 0xa6, 0x70, 0xcd, 0x89, 0x8b, + 0x5a, 0x05, 0xc8, 0x9f, 0xe8, 0xe3, 0x29, 0x51, 0x5f, 0x82, 0x52, 0xe4, 0xf0, 0xa3, 0x06, 0x14, + 0x26, 0xc4, 0xf3, 0xf4, 0x21, 0xe1, 0x58, 0xa1, 0x60, 0xbf, 0xab, 0x56, 0xa1, 0x1c, 0x3d, 0xf0, + 0xea, 0xe7, 0xe9, 0xc0, 0x92, 0x9d, 0x65, 0x66, 0x79, 0x42, 0x5c, 0xcf, 0xb4, 0x2d, 0xdf, 0x52, + 0x76, 0xd1, 0x0d, 0xa8, 0xf0, 0x5d, 0xa9, 0xf9, 0xdf, 0x19, 0xa0, 0xe4, 0x70, 0x99, 0x0b, 0xef, + 0x4b, 0xa5, 0x0d, 0x28, 0x39, 0xdb, 0x4e, 0xa0, 0x92, 0xe5, 0x2a, 0xe0, 0x6c, 0x3b, 0xbe, 0xc2, + 0xf3, 0x50, 0x66, 0x73, 0x0c, 0x34, 0x72, 0xfc, 0x47, 0x4a, 0x4c, 0x26, 0x55, 0xd4, 0xbf, 0x66, + 0xa0, 0x3e, 0x0b, 0x12, 0xe8, 0x6d, 0xc8, 0x31, 0xbc, 0x94, 0xd0, 0xd7, 0xdc, 0x14, 0x60, 0xba, + 0xe9, 0x83, 0xe9, 0x66, 0xcf, 0x07, 0xd3, 0x56, 0xf1, 0xcb, 0xaf, 0x37, 0x52, 0x9f, 0xff, 0x63, + 0x23, 0x8d, 0xb9, 0x05, 0x7a, 0x86, 0x9d, 0x69, 0xdd, 0xb4, 0x34, 0xd3, 0xe0, 0x43, 0x56, 0xd8, + 0x81, 0xd5, 0x4d, 0x6b, 0xd7, 0x40, 0x7b, 0x50, 0x1f, 0xd8, 0x96, 0x47, 0x2c, 0x6f, 0xea, 0x69, + 0x02, 0xac, 0x25, 0xe0, 0xc5, 0x8e, 0xad, 0x48, 0x01, 0x6d, 0x5f, 0xf3, 0x90, 0x2b, 0xe2, 0xda, + 0x20, 0x2e, 0x40, 0x77, 0x00, 0x4e, 0xf4, 0xb1, 0x69, 0xe8, 0xd4, 0x76, 0xbd, 0x46, 0xee, 0x7a, + 0x76, 0xe1, 0xd9, 0xbd, 0xef, 0xab, 0xdc, 0x73, 0x0c, 0x9d, 0x92, 0x56, 0x8e, 0x0d, 0x17, 0x47, + 0x2c, 0xd1, 0x8b, 0x50, 0xd3, 0x1d, 0x47, 0xf3, 0xa8, 0x4e, 0x89, 0xd6, 0x3f, 0xa3, 0xc4, 0xe3, + 0x60, 0x58, 0xc6, 0x15, 0xdd, 0x71, 0x8e, 0x98, 0xb4, 0xc5, 0x84, 0xe8, 0x05, 0xa8, 0x32, 0xdc, + 0x34, 0xf5, 0xb1, 0x36, 0x22, 0xe6, 0x70, 0x44, 0x39, 0xec, 0x65, 0x71, 0x45, 0x4a, 0xbb, 0x5c, + 0xa8, 0x1a, 0xc1, 0x8a, 0x73, 0xcc, 0x44, 0x08, 0x72, 0x86, 0x4e, 0x75, 0x1e, 0xc9, 0x32, 0xe6, + 0x6d, 0x26, 0x73, 0x74, 0x3a, 0x92, 0xf1, 0xe1, 0x6d, 0x74, 0x15, 0xd6, 0xa4, 0xdb, 0x2c, 0x77, + 0x2b, 0x7b, 0xe8, 0x0a, 0xe4, 0x1d, 0xd7, 0x3e, 0x21, 0x7c, 0xe9, 0x8a, 0x58, 0x74, 0xd4, 0x5f, + 0x67, 0xe0, 0xd2, 0x1c, 0xba, 0x32, 0xbf, 0x23, 0xdd, 0x1b, 0xf9, 0xbf, 0xc5, 0xda, 0xe8, 0x2d, + 0xe6, 0x57, 0x37, 0x88, 0x2b, 0x33, 0x52, 0x63, 0x3e, 0xd4, 0x5d, 0xfe, 0x5d, 0x86, 0x46, 0x6a, + 0xa3, 0x03, 0xa8, 0x8f, 0x75, 0x8f, 0x6a, 0x02, 0xad, 0xb4, 0x48, 0x76, 0x9a, 0xc7, 0xe8, 0x3d, + 0xdd, 0xc7, 0x37, 0xb6, 0xa9, 0xa5, 0xa3, 0xea, 0x38, 0x26, 0x45, 0x18, 0xae, 0xf4, 0xcf, 0x1e, + 0xeb, 0x16, 0x35, 0x2d, 0xa2, 0xcd, 0xad, 0xdc, 0x33, 0x73, 0x4e, 0x3b, 0x27, 0xa6, 0x41, 0xac, + 0x81, 0xbf, 0x64, 0x97, 0x03, 0xe3, 0x60, 0x49, 0x3d, 0x15, 0x43, 0x35, 0x9e, 0x1f, 0x50, 0x15, + 0x32, 0xf4, 0x54, 0x06, 0x20, 0x43, 0x4f, 0xd1, 0xff, 0x41, 0x8e, 0x4d, 0x92, 0x4f, 0xbe, 0xba, + 0x20, 0xb1, 0x4a, 0xbb, 0xde, 0x99, 0x43, 0x30, 0xd7, 0x54, 0xd5, 0xe0, 0x38, 0x04, 0x39, 0x63, + 0xd6, 0xab, 0xfa, 0x0a, 0xd4, 0x66, 0x92, 0x42, 0x64, 0xfd, 0xd2, 0xd1, 0xf5, 0x53, 0x6b, 0x50, + 0x89, 0x65, 0x00, 0xf5, 0x2a, 0x5c, 0x59, 0x04, 0xe8, 0xea, 0x28, 0x90, 0xc7, 0x80, 0x19, 0xdd, + 0x82, 0x62, 0x80, 0xe8, 0xe2, 0x38, 0xce, 0xc7, 0xca, 0x57, 0xc6, 0x81, 0x2a, 0x3b, 0x87, 0x6c, + 0x5b, 0xf3, 0xfd, 0x90, 0xe1, 0x03, 0x2f, 0xe8, 0x8e, 0xd3, 0xd5, 0xbd, 0x91, 0xfa, 0x31, 0x34, + 0x92, 0xd0, 0x7a, 0x66, 0x1a, 0xb9, 0x60, 0x1b, 0x5e, 0x85, 0xb5, 0x63, 0xdb, 0x9d, 0xe8, 0x94, + 0x3b, 0xab, 0x60, 0xd9, 0x63, 0xdb, 0x53, 0x20, 0x77, 0x96, 0x8b, 0x45, 0x47, 0xd5, 0xe0, 0x99, + 0x44, 0xc4, 0x66, 0x26, 0xa6, 0x65, 0x10, 0x11, 0xcf, 0x0a, 0x16, 0x9d, 0xd0, 0x91, 0x18, 0xac, + 0xe8, 0xb0, 0x9f, 0xf5, 0xf8, 0x5c, 0xb9, 0x7f, 0x05, 0xcb, 0x9e, 0xfa, 0x08, 0xae, 0x2e, 0x86, + 0x6d, 0x74, 0x0b, 0x40, 0xe0, 0x66, 0x70, 0xea, 0x4a, 0xdb, 0x57, 0xe7, 0xf7, 0xfc, 0x6d, 0x9d, + 0xea, 0x58, 0xe1, 0x9a, 0xac, 0xc9, 0x50, 0x20, 0x34, 0xd3, 0x3c, 0xf3, 0xb1, 0xd8, 0x32, 0x59, + 0x5c, 0x09, 0x74, 0x8e, 0xcc, 0xc7, 0x44, 0xfd, 0xb6, 0x08, 0x45, 0x4c, 0x3c, 0x87, 0x81, 0x11, + 0x6a, 0x81, 0x42, 0x4e, 0x07, 0xc4, 0xa1, 0x3e, 0x7e, 0x2f, 0x26, 0x41, 0x42, 0xbb, 0xe3, 0x6b, + 0x32, 0x06, 0x12, 0x98, 0xa1, 0x37, 0x25, 0xc9, 0x4c, 0xe6, 0x8b, 0xd2, 0x3c, 0xca, 0x32, 0xdf, + 0xf2, 0x59, 0x66, 0x36, 0x91, 0x74, 0x08, 0xab, 0x19, 0x9a, 0xf9, 0xa6, 0xa4, 0x99, 0xb9, 0x25, + 0x3f, 0x16, 0xe3, 0x99, 0xed, 0x18, 0xcf, 0xcc, 0x2f, 0x99, 0x66, 0x02, 0xd1, 0x7c, 0xcb, 0x27, + 0x9a, 0x6b, 0x4b, 0x46, 0x3c, 0xc3, 0x34, 0xef, 0xc4, 0x99, 0xa6, 0x60, 0x89, 0x37, 0x12, 0xad, + 0x13, 0xa9, 0xe6, 0x0f, 0x23, 0x54, 0xb3, 0x98, 0xc8, 0xf3, 0x84, 0x93, 0x05, 0x5c, 0xb3, 0x1d, + 0xe3, 0x9a, 0xca, 0x92, 0x18, 0x24, 0x90, 0xcd, 0xf7, 0xa2, 0x64, 0x13, 0x12, 0xf9, 0xaa, 0x5c, + 0xef, 0x45, 0x6c, 0xf3, 0x9d, 0x80, 0x6d, 0x96, 0x12, 0xe9, 0xb2, 0x9c, 0xc3, 0x2c, 0xdd, 0x3c, + 0x98, 0xa3, 0x9b, 0x82, 0x1e, 0xbe, 0x98, 0xe8, 0x62, 0x09, 0xdf, 0x3c, 0x98, 0xe3, 0x9b, 0x95, + 0x25, 0x0e, 0x97, 0x10, 0xce, 0x5f, 0x2e, 0x26, 0x9c, 0xc9, 0x94, 0x50, 0x0e, 0x73, 0x35, 0xc6, + 0xa9, 0x25, 0x30, 0x4e, 0xc1, 0x0a, 0x5f, 0x4d, 0x74, 0xbf, 0x32, 0xe5, 0xbc, 0xb7, 0x80, 0x72, + 0xd6, 0xb9, 0xf3, 0x97, 0x13, 0x9d, 0x5f, 0x84, 0x73, 0xbe, 0xc2, 0x32, 0xfe, 0x0c, 0x94, 0x30, + 0xd4, 0x24, 0xae, 0x6b, 0xbb, 0x92, 0x3d, 0x8a, 0x8e, 0xfa, 0x32, 0xe3, 0x20, 0x21, 0x6c, 0x9c, + 0xc3, 0x4f, 0x79, 0x76, 0x8a, 0x40, 0x85, 0xfa, 0xa7, 0x74, 0x68, 0xcb, 0xd3, 0x76, 0x94, 0xbf, + 0x28, 0x92, 0xbf, 0x44, 0x58, 0x6b, 0x26, 0xce, 0x5a, 0x37, 0xa0, 0xc4, 0xb2, 0xce, 0x0c, 0x21, + 0xd5, 0x9d, 0x80, 0x90, 0xde, 0x84, 0x4b, 0x9c, 0x56, 0x08, 0xb0, 0x95, 0xa9, 0x26, 0xc7, 0x91, + 0xb6, 0xc6, 0x3e, 0x88, 0x3d, 0x2f, 0x72, 0xce, 0xeb, 0x70, 0x39, 0xa2, 0x1b, 0x64, 0x33, 0xc1, + 0xce, 0xea, 0x81, 0xf6, 0x8e, 0x4c, 0x6b, 0x7f, 0x49, 0x87, 0x11, 0x0a, 0x99, 0xec, 0x22, 0xd2, + 0x99, 0xfe, 0x2f, 0x91, 0xce, 0xcc, 0x77, 0x26, 0x9d, 0xd1, 0xec, 0x9c, 0x8d, 0x67, 0xe7, 0x6f, + 0xd3, 0xe1, 0x9a, 0x04, 0x14, 0x72, 0x60, 0x1b, 0x44, 0xe6, 0x4b, 0xde, 0x46, 0x75, 0xc8, 0x8e, + 0xed, 0xa1, 0xcc, 0x8a, 0xac, 0xc9, 0xb4, 0x02, 0x6c, 0x57, 0x24, 0x74, 0x07, 0xa9, 0x36, 0xcf, + 0x23, 0x2c, 0x53, 0x6d, 0x1d, 0xb2, 0x0f, 0x89, 0x40, 0xe2, 0x32, 0x66, 0x4d, 0xa6, 0xc7, 0x37, + 0x19, 0xc7, 0xd7, 0x32, 0x16, 0x1d, 0xf4, 0x36, 0x28, 0xbc, 0x58, 0xa3, 0xd9, 0x8e, 0x27, 0x41, + 0xf3, 0xd9, 0xe8, 0x5c, 0x45, 0x4d, 0x66, 0xf3, 0x90, 0xe9, 0x1c, 0x38, 0x1e, 0x2e, 0x3a, 0xb2, + 0x15, 0x61, 0x11, 0x4a, 0x8c, 0xcc, 0x5e, 0x03, 0x85, 0x8d, 0xde, 0x73, 0xf4, 0x01, 0xe1, 0x08, + 0xa8, 0xe0, 0x50, 0xa0, 0x3e, 0x00, 0x34, 0x8f, 0xe3, 0xa8, 0x0b, 0x6b, 0xe4, 0x84, 0x58, 0x94, + 0x2d, 0x5b, 0x76, 0x36, 0x99, 0x4b, 0xa6, 0x48, 0x2c, 0xda, 0x6a, 0xb0, 0x20, 0xff, 0xeb, 0xeb, + 0x8d, 0xba, 0xd0, 0x7e, 0xcd, 0x9e, 0x98, 0x94, 0x4c, 0x1c, 0x7a, 0x86, 0xa5, 0xbd, 0xfa, 0xf7, + 0x0c, 0xa3, 0x6d, 0x31, 0x8c, 0x5f, 0x18, 0x5b, 0x7f, 0xcb, 0x67, 0x22, 0x94, 0x7d, 0xb5, 0x78, + 0xaf, 0x03, 0x0c, 0x75, 0x4f, 0x7b, 0xa4, 0x5b, 0x94, 0x18, 0x32, 0xe8, 0x11, 0x09, 0x6a, 0x42, + 0x91, 0xf5, 0xa6, 0x1e, 0x31, 0xe4, 0xed, 0x21, 0xe8, 0x47, 0xe6, 0x59, 0xf8, 0x7e, 0xf3, 0x8c, + 0x47, 0xb9, 0x38, 0x13, 0xe5, 0x08, 0xa5, 0x52, 0xa2, 0x94, 0x8a, 0x8d, 0xcd, 0x71, 0x4d, 0xdb, + 0x35, 0xe9, 0x19, 0x5f, 0x9a, 0x2c, 0x0e, 0xfa, 0xec, 0x32, 0x3a, 0x21, 0x13, 0xc7, 0xb6, 0xc7, + 0x9a, 0x80, 0x9b, 0x12, 0x37, 0x2d, 0x4b, 0x61, 0x87, 0xa3, 0xce, 0x6f, 0x32, 0xe1, 0xf9, 0x0b, + 0xa9, 0xf3, 0xff, 0x5c, 0x80, 0xd5, 0xdf, 0xf2, 0x0b, 0x75, 0x3c, 0x8b, 0xa3, 0x23, 0xb8, 0x14, + 0x1c, 0x7f, 0x6d, 0xca, 0x61, 0xc1, 0xdf, 0xd0, 0xab, 0xe2, 0x47, 0xfd, 0x24, 0x2e, 0xf6, 0xd0, + 0x87, 0xf0, 0xf4, 0x0c, 0xb6, 0x05, 0xae, 0x33, 0xab, 0x42, 0xdc, 0x53, 0x71, 0x88, 0xf3, 0x5d, + 0x87, 0xc1, 0xca, 0x7e, 0xcf, 0x53, 0xb7, 0xcb, 0xee, 0x68, 0x51, 0x52, 0xb2, 0x70, 0xf9, 0x6f, + 0x40, 0xc5, 0x25, 0x54, 0x37, 0x2d, 0x2d, 0x76, 0x0b, 0x2e, 0x0b, 0xa1, 0xbc, 0x5b, 0x1f, 0xc2, + 0x53, 0x0b, 0xc9, 0x09, 0xfa, 0x7f, 0x50, 0x42, 0x5e, 0x93, 0x4e, 0xb8, 0x50, 0x06, 0x97, 0xa4, + 0x50, 0x57, 0xfd, 0x73, 0x3a, 0x74, 0x19, 0xbf, 0x76, 0x75, 0x60, 0xcd, 0x25, 0xde, 0x74, 0x2c, + 0x2e, 0x42, 0xd5, 0xed, 0xd7, 0x57, 0xa3, 0x35, 0x4c, 0x3a, 0x1d, 0x53, 0x2c, 0x8d, 0xd5, 0x07, + 0xb0, 0x26, 0x24, 0xa8, 0x04, 0x85, 0x7b, 0xfb, 0x77, 0xf7, 0x0f, 0x3e, 0xd8, 0xaf, 0xa7, 0x10, + 0xc0, 0xda, 0x4e, 0xbb, 0xdd, 0x39, 0xec, 0xd5, 0xd3, 0x48, 0x81, 0xfc, 0x4e, 0xeb, 0x00, 0xf7, + 0xea, 0x19, 0x26, 0xc6, 0x9d, 0xf7, 0x3b, 0xed, 0x5e, 0x3d, 0x8b, 0x2e, 0x41, 0x45, 0xb4, 0xb5, + 0x3b, 0x07, 0xf8, 0xa7, 0x3b, 0xbd, 0x7a, 0x2e, 0x22, 0x3a, 0xea, 0xec, 0xdf, 0xee, 0xe0, 0x7a, + 0x5e, 0x7d, 0x83, 0xdd, 0xb4, 0x12, 0x88, 0x50, 0x78, 0xa7, 0x4a, 0x47, 0xee, 0x54, 0xea, 0xef, + 0x33, 0xd0, 0x4c, 0x66, 0x37, 0xe8, 0xfd, 0x99, 0x89, 0x6f, 0x5f, 0x80, 0x1a, 0xcd, 0xcc, 0x1e, + 0xbd, 0x00, 0x55, 0x97, 0x1c, 0x13, 0x3a, 0x18, 0x09, 0xb6, 0x25, 0x52, 0x66, 0x05, 0x57, 0xa4, + 0x94, 0x1b, 0x79, 0x42, 0xed, 0x13, 0x32, 0xa0, 0x9a, 0xc0, 0x22, 0xb1, 0xe9, 0x14, 0xa6, 0xc6, + 0xa4, 0x47, 0x42, 0xa8, 0x7e, 0x7c, 0xa1, 0x58, 0x2a, 0x90, 0xc7, 0x9d, 0x1e, 0xfe, 0xb0, 0x9e, + 0x45, 0x08, 0xaa, 0xbc, 0xa9, 0x1d, 0xed, 0xef, 0x1c, 0x1e, 0x75, 0x0f, 0x58, 0x2c, 0x2f, 0x43, + 0xcd, 0x8f, 0xa5, 0x2f, 0xcc, 0xab, 0x87, 0xf0, 0x74, 0x02, 0x35, 0xfb, 0x8e, 0xf7, 0x4a, 0xf5, + 0x23, 0xa8, 0xc6, 0xab, 0x23, 0x6c, 0x51, 0x5c, 0x7b, 0x6a, 0x19, 0xdc, 0x47, 0x1e, 0x8b, 0x0e, + 0xba, 0x05, 0xf9, 0x13, 0x5b, 0x1c, 0xdc, 0xc5, 0xbb, 0xf7, 0xbe, 0x4d, 0x49, 0xa4, 0xba, 0x22, + 0xb4, 0xd5, 0xc7, 0x90, 0xe7, 0xe7, 0x90, 0x9d, 0x29, 0x5e, 0xe7, 0x90, 0x34, 0x8d, 0xb5, 0xd1, + 0x47, 0x00, 0x3a, 0xa5, 0xae, 0xd9, 0x9f, 0x86, 0x8e, 0x37, 0x16, 0x9f, 0xe3, 0x1d, 0x5f, 0xaf, + 0x75, 0x4d, 0x1e, 0xe8, 0x2b, 0xa1, 0x69, 0xe4, 0x50, 0x47, 0x1c, 0xaa, 0xfb, 0x50, 0x8d, 0xdb, + 0xfa, 0xc4, 0x42, 0x8c, 0x21, 0x4e, 0x2c, 0x04, 0x4f, 0x94, 0xc4, 0x22, 0xa0, 0x25, 0x59, 0x51, + 0xd3, 0xe2, 0x1d, 0xf5, 0x8f, 0x69, 0x28, 0xf6, 0x4e, 0xe5, 0x0a, 0x27, 0x94, 0x53, 0x42, 0xd3, + 0x4c, 0xb4, 0x78, 0x20, 0xea, 0x33, 0xd9, 0xa0, 0xea, 0xf3, 0x5e, 0xb0, 0x87, 0x73, 0xab, 0x5e, + 0xd5, 0xfc, 0xf2, 0x97, 0xdc, 0xb9, 0x37, 0xa0, 0x62, 0xbb, 0xe6, 0xd0, 0xb4, 0xf4, 0x71, 0x94, + 0x75, 0x96, 0x7d, 0x21, 0xa7, 0x6a, 0xef, 0x82, 0x12, 0x40, 0x35, 0x23, 0xc5, 0xba, 0x61, 0xb8, + 0xc4, 0xf3, 0xe4, 0x71, 0xf3, 0xbb, 0xbc, 0x84, 0x67, 0x3f, 0x92, 0x35, 0x8c, 0x2c, 0x16, 0x1d, + 0xd5, 0x80, 0xda, 0x0c, 0xce, 0xa3, 0x77, 0xa1, 0xe0, 0x4c, 0xfb, 0x9a, 0x1f, 0xc3, 0x99, 0x87, + 0x20, 0x9f, 0x6e, 0x4d, 0xfb, 0x63, 0x73, 0x70, 0x97, 0x9c, 0xf9, 0x23, 0x76, 0xa6, 0xfd, 0xbb, + 0x22, 0xd4, 0xe2, 0x57, 0x32, 0xd1, 0x5f, 0x39, 0x81, 0xa2, 0xbf, 0x73, 0xd0, 0x8f, 0x40, 0x09, + 0x52, 0x48, 0x50, 0xd9, 0x4d, 0xcc, 0x3d, 0xd2, 0x7d, 0x68, 0xc2, 0xb8, 0xbb, 0x67, 0x0e, 0x2d, + 0x62, 0x68, 0x21, 0x2d, 0xe7, 0xbf, 0x56, 0xc4, 0x35, 0xf1, 0x61, 0xcf, 0xe7, 0xe4, 0xea, 0xbf, + 0xd3, 0x50, 0xf4, 0x2b, 0x78, 0xe8, 0x8d, 0xc8, 0xe6, 0xac, 0x2e, 0x28, 0x3b, 0xf8, 0x8a, 0x61, + 0x15, 0x2e, 0x3e, 0xd6, 0xcc, 0xc5, 0xc7, 0x9a, 0x54, 0x4e, 0xf5, 0x0b, 0xdb, 0xb9, 0x0b, 0x17, + 0xb6, 0x5f, 0x03, 0x44, 0x6d, 0xaa, 0x8f, 0xb5, 0x13, 0x9b, 0x9a, 0xd6, 0x50, 0x13, 0xc1, 0x16, + 0x14, 0xa4, 0xce, 0xbf, 0xdc, 0xe7, 0x1f, 0x0e, 0x79, 0xdc, 0x7f, 0x95, 0x86, 0x62, 0x90, 0x4b, + 0x2e, 0x5a, 0x54, 0xbb, 0x0a, 0x6b, 0x12, 0x2e, 0x45, 0x55, 0x4d, 0xf6, 0x82, 0xfa, 0x6e, 0x2e, + 0x52, 0xdf, 0x6d, 0x42, 0x71, 0x42, 0xa8, 0xce, 0x51, 0x49, 0xec, 0xd1, 0xa0, 0x7f, 0xf3, 0x1d, + 0x28, 0x45, 0xea, 0x9b, 0xec, 0x78, 0xee, 0x77, 0x3e, 0xa8, 0xa7, 0x9a, 0x85, 0xcf, 0xbe, 0xb8, + 0x9e, 0xdd, 0x27, 0x8f, 0xd8, 0x9e, 0xc5, 0x9d, 0x76, 0xb7, 0xd3, 0xbe, 0x5b, 0x4f, 0x37, 0x4b, + 0x9f, 0x7d, 0x71, 0xbd, 0x80, 0x09, 0x2f, 0x79, 0xdc, 0xec, 0x42, 0x39, 0xba, 0x2a, 0x71, 0xc4, + 0x45, 0x50, 0xbd, 0x7d, 0xef, 0x70, 0x6f, 0xb7, 0xbd, 0xd3, 0xeb, 0x68, 0xf7, 0x0f, 0x7a, 0x9d, + 0x7a, 0x1a, 0x3d, 0x0d, 0x97, 0xf7, 0x76, 0x7f, 0xd2, 0xed, 0x69, 0xed, 0xbd, 0xdd, 0xce, 0x7e, + 0x4f, 0xdb, 0xe9, 0xf5, 0x76, 0xda, 0x77, 0xeb, 0x99, 0xed, 0xdf, 0x01, 0xd4, 0x76, 0x5a, 0xed, + 0x5d, 0x96, 0x2d, 0xcc, 0x81, 0xce, 0xaf, 0xad, 0x6d, 0xc8, 0xf1, 0x8b, 0xe9, 0xb9, 0x6f, 0xaa, + 0xcd, 0xf3, 0x8b, 0x61, 0xe8, 0x0e, 0xe4, 0xf9, 0x9d, 0x15, 0x9d, 0xff, 0xc8, 0xda, 0x5c, 0x52, + 0x1d, 0x63, 0x83, 0xe1, 0xc7, 0xe3, 0xdc, 0x57, 0xd7, 0xe6, 0xf9, 0xc5, 0x32, 0x84, 0x41, 0x09, + 0x39, 0xef, 0xf2, 0x57, 0xc8, 0xe6, 0x0a, 0x88, 0x84, 0xf6, 0xa0, 0xe0, 0x5f, 0x53, 0x96, 0xbd, + 0x8b, 0x36, 0x97, 0x56, 0xb3, 0x58, 0xb8, 0xc4, 0x75, 0xf2, 0xfc, 0x47, 0xde, 0xe6, 0x92, 0xd2, + 0x1c, 0xda, 0x85, 0x35, 0xc9, 0xe3, 0x96, 0xbc, 0x75, 0x36, 0x97, 0x55, 0xa7, 0x58, 0xd0, 0xc2, + 0x8b, 0xfa, 0xf2, 0xa7, 0xeb, 0xe6, 0x0a, 0x55, 0x47, 0x74, 0x0f, 0x20, 0x72, 0x79, 0x5c, 0xe1, + 0x4d, 0xba, 0xb9, 0x4a, 0x35, 0x11, 0x1d, 0x40, 0x31, 0xe0, 0xf2, 0x4b, 0x5f, 0x88, 0x9b, 0xcb, + 0xcb, 0x7a, 0xe8, 0x01, 0x54, 0xe2, 0x1c, 0x76, 0xb5, 0x77, 0xdf, 0xe6, 0x8a, 0xf5, 0x3a, 0xe6, + 0x3f, 0x4e, 0x68, 0x57, 0x7b, 0x07, 0x6e, 0xae, 0x58, 0xbe, 0x43, 0x9f, 0xc0, 0xa5, 0x79, 0xc2, + 0xb9, 0xfa, 0xb3, 0x70, 0xf3, 0x02, 0x05, 0x3d, 0x34, 0x01, 0xb4, 0x80, 0xa8, 0x5e, 0xe0, 0x95, + 0xb8, 0x79, 0x91, 0xfa, 0x1e, 0x32, 0xa0, 0x36, 0xcb, 0xfe, 0x56, 0x7d, 0x35, 0x6e, 0xae, 0x5c, + 0xeb, 0x6b, 0x75, 0xbe, 0xfc, 0x66, 0x3d, 0xfd, 0xd5, 0x37, 0xeb, 0xe9, 0x7f, 0x7e, 0xb3, 0x9e, + 0xfe, 0xfc, 0xc9, 0x7a, 0xea, 0xab, 0x27, 0xeb, 0xa9, 0xbf, 0x3d, 0x59, 0x4f, 0xfd, 0xfc, 0xd5, + 0xa1, 0x49, 0x47, 0xd3, 0xfe, 0xe6, 0xc0, 0x9e, 0x6c, 0x45, 0xff, 0xe4, 0xb2, 0xe8, 0x8f, 0x37, + 0xfd, 0x35, 0x9e, 0xba, 0xde, 0xfc, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1c, 0xcf, 0x70, 0x68, + 0x98, 0x23, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3167,6 +3302,7 @@ type ABCIApplicationClient interface { OfferSnapshot(ctx context.Context, in *RequestOfferSnapshot, opts ...grpc.CallOption) (*ResponseOfferSnapshot, error) LoadSnapshotChunk(ctx context.Context, in *RequestLoadSnapshotChunk, opts ...grpc.CallOption) (*ResponseLoadSnapshotChunk, error) ApplySnapshotChunk(ctx context.Context, in *RequestApplySnapshotChunk, opts ...grpc.CallOption) (*ResponseApplySnapshotChunk, error) + PrepareProposal(ctx context.Context, in *RequestPrepareProposal, opts ...grpc.CallOption) (*ResponsePrepareProposal, error) } type aBCIApplicationClient struct { @@ -3303,6 +3439,15 @@ func (c *aBCIApplicationClient) ApplySnapshotChunk(ctx context.Context, in *Requ return out, nil } +func (c *aBCIApplicationClient) PrepareProposal(ctx context.Context, in *RequestPrepareProposal, opts ...grpc.CallOption) (*ResponsePrepareProposal, error) { + out := new(ResponsePrepareProposal) + err := c.cc.Invoke(ctx, "/tendermint.abci.ABCIApplication/PrepareProposal", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ABCIApplicationServer is the server API for ABCIApplication service. type ABCIApplicationServer interface { Echo(context.Context, *RequestEcho) (*ResponseEcho, error) @@ -3319,6 +3464,7 @@ type ABCIApplicationServer interface { OfferSnapshot(context.Context, *RequestOfferSnapshot) (*ResponseOfferSnapshot, error) LoadSnapshotChunk(context.Context, *RequestLoadSnapshotChunk) (*ResponseLoadSnapshotChunk, error) ApplySnapshotChunk(context.Context, *RequestApplySnapshotChunk) (*ResponseApplySnapshotChunk, error) + PrepareProposal(context.Context, *RequestPrepareProposal) (*ResponsePrepareProposal, error) } // UnimplementedABCIApplicationServer can be embedded to have forward compatible implementations. @@ -3367,6 +3513,9 @@ func (*UnimplementedABCIApplicationServer) LoadSnapshotChunk(ctx context.Context func (*UnimplementedABCIApplicationServer) ApplySnapshotChunk(ctx context.Context, req *RequestApplySnapshotChunk) (*ResponseApplySnapshotChunk, error) { return nil, status.Errorf(codes.Unimplemented, "method ApplySnapshotChunk not implemented") } +func (*UnimplementedABCIApplicationServer) PrepareProposal(ctx context.Context, req *RequestPrepareProposal) (*ResponsePrepareProposal, error) { + return nil, status.Errorf(codes.Unimplemented, "method PrepareProposal not implemented") +} func RegisterABCIApplicationServer(s *grpc.Server, srv ABCIApplicationServer) { s.RegisterService(&_ABCIApplication_serviceDesc, srv) @@ -3624,6 +3773,24 @@ func _ABCIApplication_ApplySnapshotChunk_Handler(srv interface{}, ctx context.Co return interceptor(ctx, in, info, handler) } +func _ABCIApplication_PrepareProposal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RequestPrepareProposal) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ABCIApplicationServer).PrepareProposal(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.abci.ABCIApplication/PrepareProposal", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ABCIApplicationServer).PrepareProposal(ctx, req.(*RequestPrepareProposal)) + } + return interceptor(ctx, in, info, handler) +} + var _ABCIApplication_serviceDesc = grpc.ServiceDesc{ ServiceName: "tendermint.abci.ABCIApplication", HandlerType: (*ABCIApplicationServer)(nil), @@ -3684,6 +3851,10 @@ var _ABCIApplication_serviceDesc = grpc.ServiceDesc{ MethodName: "ApplySnapshotChunk", Handler: _ABCIApplication_ApplySnapshotChunk_Handler, }, + { + MethodName: "PrepareProposal", + Handler: _ABCIApplication_PrepareProposal_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "tendermint/abci/types.proto", @@ -4015,6 +4186,27 @@ func (m *Request_ApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, err } return len(dAtA) - i, nil } +func (m *Request_PrepareProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Request_PrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.PrepareProposal != nil { + { + size, err := m.PrepareProposal.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x7a + } + return len(dAtA) - i, nil +} func (m *RequestEcho) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4180,12 +4372,12 @@ func (m *RequestInitChain) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - n16, err16 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) - if err16 != nil { - return 0, err16 + n17, err17 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) + if err17 != nil { + return 0, err17 } - i -= n16 - i = encodeVarintTypes(dAtA, i, uint64(n16)) + i -= n17 + i = encodeVarintTypes(dAtA, i, uint64(n17)) i-- dAtA[i] = 0xa return len(dAtA) - i, nil @@ -4568,6 +4760,46 @@ func (m *RequestApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } +func (m *RequestPrepareProposal) 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 *RequestPrepareProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RequestPrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.BlockDataSize != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.BlockDataSize)) + i-- + dAtA[i] = 0x10 + } + if m.BlockData != nil { + { + size, err := m.BlockData.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *Response) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4915,6 +5147,29 @@ func (m *Response_ApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, er } return len(dAtA) - i, nil } +func (m *Response_PrepareProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Response_PrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.PrepareProposal != nil { + { + size, err := m.PrepareProposal.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } + return len(dAtA) - i, nil +} func (m *ResponseException) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -5632,20 +5887,20 @@ func (m *ResponseApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, err } } if len(m.RefetchChunks) > 0 { - dAtA39 := make([]byte, len(m.RefetchChunks)*10) - var j38 int + dAtA42 := make([]byte, len(m.RefetchChunks)*10) + var j41 int for _, num := range m.RefetchChunks { for num >= 1<<7 { - dAtA39[j38] = uint8(uint64(num)&0x7f | 0x80) + dAtA42[j41] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j38++ + j41++ } - dAtA39[j38] = uint8(num) - j38++ + dAtA42[j41] = uint8(num) + j41++ } - i -= j38 - copy(dAtA[i:], dAtA39[:j38]) - i = encodeVarintTypes(dAtA, i, uint64(j38)) + i -= j41 + copy(dAtA[i:], dAtA42[:j41]) + i = encodeVarintTypes(dAtA, i, uint64(j41)) i-- dAtA[i] = 0x12 } @@ -5657,6 +5912,41 @@ func (m *ResponseApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, err return len(dAtA) - i, nil } +func (m *ResponsePrepareProposal) 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 *ResponsePrepareProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResponsePrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.BlockData != nil { + { + size, err := m.BlockData.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *LastCommitInfo) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -5988,12 +6278,12 @@ func (m *Evidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x28 } - n43, err43 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) - if err43 != nil { - return 0, err43 + n47, err47 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) + if err47 != nil { + return 0, err47 } - i -= n43 - i = encodeVarintTypes(dAtA, i, uint64(n43)) + i -= n47 + i = encodeVarintTypes(dAtA, i, uint64(n47)) i-- dAtA[i] = 0x22 if m.Height != 0 { @@ -6262,6 +6552,18 @@ func (m *Request_ApplySnapshotChunk) Size() (n int) { } return n } +func (m *Request_PrepareProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PrepareProposal != nil { + l = m.PrepareProposal.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} func (m *RequestEcho) Size() (n int) { if m == nil { return 0 @@ -6499,6 +6801,22 @@ func (m *RequestApplySnapshotChunk) Size() (n int) { return n } +func (m *RequestPrepareProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BlockData != nil { + l = m.BlockData.Size() + n += 1 + l + sovTypes(uint64(l)) + } + if m.BlockDataSize != 0 { + n += 1 + sovTypes(uint64(m.BlockDataSize)) + } + return n +} + func (m *Response) Size() (n int) { if m == nil { return 0 @@ -6691,6 +7009,18 @@ func (m *Response_ApplySnapshotChunk) Size() (n int) { } return n } +func (m *Response_PrepareProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PrepareProposal != nil { + l = m.PrepareProposal.Size() + n += 2 + l + sovTypes(uint64(l)) + } + return n +} func (m *ResponseException) Size() (n int) { if m == nil { return 0 @@ -7030,6 +7360,19 @@ func (m *ResponseApplySnapshotChunk) Size() (n int) { return n } +func (m *ResponsePrepareProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BlockData != nil { + l = m.BlockData.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + func (m *LastCommitInfo) Size() (n int) { if m == nil { return 0 @@ -7729,6 +8072,41 @@ func (m *Request) Unmarshal(dAtA []byte) error { } m.Value = &Request_ApplySnapshotChunk{v} iNdEx = postIndex + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PrepareProposal", 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 + } + v := &RequestPrepareProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Value = &Request_PrepareProposal{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -9329,6 +9707,111 @@ func (m *RequestApplySnapshotChunk) Unmarshal(dAtA []byte) error { } return nil } +func (m *RequestPrepareProposal) 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: RequestPrepareProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RequestPrepareProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockData", 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.BlockData == nil { + m.BlockData = &types1.Data{} + } + if err := m.BlockData.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockDataSize", wireType) + } + m.BlockDataSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlockDataSize |= int64(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 *Response) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -9883,6 +10366,41 @@ func (m *Response) Unmarshal(dAtA []byte) error { } m.Value = &Response_ApplySnapshotChunk{v} iNdEx = postIndex + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PrepareProposal", 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 + } + v := &ResponsePrepareProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Value = &Response_PrepareProposal{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -12145,6 +12663,92 @@ func (m *ResponseApplySnapshotChunk) Unmarshal(dAtA []byte) error { } return nil } +func (m *ResponsePrepareProposal) 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: ResponsePrepareProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResponsePrepareProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockData", 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.BlockData == nil { + m.BlockData = &types1.Data{} + } + if err := m.BlockData.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 *LastCommitInfo) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/internal/consensus/mempool_test.go b/internal/consensus/mempool_test.go index 558dbd4b34..24eb0150da 100644 --- a/internal/consensus/mempool_test.go +++ b/internal/consensus/mempool_test.go @@ -272,3 +272,8 @@ func (app *CounterApplication) Commit() abci.ResponseCommit { binary.BigEndian.PutUint64(hash, uint64(app.txCount)) return abci.ResponseCommit{Data: hash} } + +func (app *CounterApplication) PrepareProposal( + req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + return abci.ResponsePrepareProposal{BlockData: req.BlockData} +} diff --git a/internal/proxy/app_conn.go b/internal/proxy/app_conn.go index 54ce61dac8..775f946e4c 100644 --- a/internal/proxy/app_conn.go +++ b/internal/proxy/app_conn.go @@ -19,6 +19,7 @@ type AppConnConsensus interface { Error() error InitChainSync(context.Context, types.RequestInitChain) (*types.ResponseInitChain, error) + PrepareProposalSync(context.Context, types.RequestPrepareProposal) (*types.ResponsePrepareProposal, error) BeginBlockSync(context.Context, types.RequestBeginBlock) (*types.ResponseBeginBlock, error) DeliverTxAsync(context.Context, types.RequestDeliverTx) (*abciclient.ReqRes, error) @@ -85,6 +86,13 @@ func (app *appConnConsensus) InitChainSync( return app.appConn.InitChainSync(ctx, req) } +func (app *appConnConsensus) PrepareProposalSync( + ctx context.Context, + req types.RequestPrepareProposal, +) (*types.ResponsePrepareProposal, error) { + return app.appConn.PrepareProposalSync(ctx, req) +} + func (app *appConnConsensus) BeginBlockSync( ctx context.Context, req types.RequestBeginBlock, diff --git a/internal/proxy/mocks/app_conn_consensus.go b/internal/proxy/mocks/app_conn_consensus.go index 391785adbb..d8a764542c 100644 --- a/internal/proxy/mocks/app_conn_consensus.go +++ b/internal/proxy/mocks/app_conn_consensus.go @@ -148,6 +148,29 @@ func (_m *AppConnConsensus) InitChainSync(_a0 context.Context, _a1 types.Request return r0, r1 } +// PrepareProposalSync provides a mock function with given fields: _a0, _a1 +func (_m *AppConnConsensus) PrepareProposalSync(_a0 context.Context, _a1 types.RequestPrepareProposal) (*types.ResponsePrepareProposal, error) { + ret := _m.Called(_a0, _a1) + + var r0 *types.ResponsePrepareProposal + if rf, ok := ret.Get(0).(func(context.Context, types.RequestPrepareProposal) *types.ResponsePrepareProposal); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.ResponsePrepareProposal) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, types.RequestPrepareProposal) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // SetResponseCallback provides a mock function with given fields: _a0 func (_m *AppConnConsensus) SetResponseCallback(_a0 abciclient.Callback) { _m.Called(_a0) diff --git a/internal/state/execution.go b/internal/state/execution.go index 2108c9b94e..25a65bc15f 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -13,6 +13,7 @@ import ( "github.com/tendermint/tendermint/internal/proxy" "github.com/tendermint/tendermint/libs/log" tmstate "github.com/tendermint/tendermint/proto/tendermint/state" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/types" ) @@ -99,6 +100,8 @@ func (blockExec *BlockExecutor) SetEventBus(eventBus types.BlockEventPublisher) // and txs from the mempool. The max bytes must be big enough to fit the commit. // Up to 1/10th of the block space is allcoated for maximum sized evidence. // The rest is given to txs, up to the max gas. +// +// Contract: application will not return more bytes than are sent over the wire. func (blockExec *BlockExecutor) CreateProposalBlock( height int64, state State, commit *types.Commit, @@ -110,12 +113,70 @@ func (blockExec *BlockExecutor) CreateProposalBlock( evidence, evSize := blockExec.evpool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes) + evdData := types.EvidenceData{Evidence: evidence} + pevdData, err := evdData.ToProto() + if err != nil { + // todo(evan): see if we can get rid of this panic + panic(err) + } + // Fetch a limited amount of valid txs maxDataBytes := types.MaxDataBytes(maxBytes, evSize, state.Validators.Size()) + // TODO(ismail): reaping the mempool has to happen in relation to a max + // allowed square size instead of (only) Gas / bytes + // maybe the mempool actually should track things separately + // meaning that CheckTx should already do the mapping: + // Tx -> Txs, Message + // https://github.com/tendermint/tendermint/issues/77 txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas) + l := len(txs) + bzs := make([][]byte, l) + for i := 0; i < l; i++ { + bzs[i] = txs[i] + } - return state.MakeBlock(height, txs, commit, evidence, nil, proposerAddr) + preparedProposal, err := blockExec.proxyApp.PrepareProposalSync( + context.TODO(), + abci.RequestPrepareProposal{ + BlockData: &tmproto.Data{Txs: txs.ToSliceOfBytes(), Evidence: *pevdData}, + BlockDataSize: maxDataBytes}, + ) + if err != nil { + // The App MUST ensure that only valid (and hence 'processable') transactions + // enter the mempool. Hence, at this point, we can't have any non-processable + // transaction causing an error. + // + // Also, the App can simply skip any transaction that could cause any kind of trouble. + // Either way, we can not recover in a meaningful way, unless we skip proposing + // this block, repair what caused the error and try again. Hence, we panic on + // purpose for now. + panic(err) + } + rawNewData := preparedProposal.GetBlockData() + var txSize int + for _, tx := range rawNewData.GetTxs() { + txSize += len(tx) + + if maxDataBytes < int64(txSize) { + panic("block data exceeds max amount of allowed bytes") + } + } + + newData, err := types.DataFromProto(rawNewData) + if err != nil { + // todo(evan): see if we can get rid of this panic + panic(err) + } + + return state.MakeBlock( + height, + newData.Txs, + commit, + newData.Evidence.Evidence, + newData.Messages.MessagesList, + proposerAddr, + ) } // ValidateBlock validates the given block against the given state. diff --git a/pkg/prove/proof_test.go b/pkg/prove/proof_test.go index cdf97c9d89..f3d9521382 100644 --- a/pkg/prove/proof_test.go +++ b/pkg/prove/proof_test.go @@ -137,7 +137,7 @@ func Test_genOrigRowShares(t *testing.T) { Messages: generateRandomlySizedMessages(10, 1500), } - allShares, _, _ := typicalBlockData.ComputeShares(64) + allShares, _, _ := typicalBlockData.ComputeShares(8) rawShares := allShares.RawShares() genShares := genOrigRowShares(typicalBlockData, 8, 0, 7) diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 8d1392bd40..33b6a5fce8 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -35,6 +35,7 @@ message Request { RequestOfferSnapshot offer_snapshot = 12; RequestLoadSnapshotChunk load_snapshot_chunk = 13; RequestApplySnapshotChunk apply_snapshot_chunk = 14; + RequestPrepareProposal prepare_proposal = 15; } } @@ -117,6 +118,15 @@ message RequestApplySnapshotChunk { string sender = 3; } +message RequestPrepareProposal { + // block_data is an array of transactions that will be included in a block, + // sent to the app for possible modifications. + // applications can not exceed the size of the data passed to it. + tendermint.types.Data block_data = 1; + // If an application decides to populate block_data with extra information, they can not exceed this value. + int64 block_data_size = 2; +} + //---------------------------------------- // Response types @@ -137,6 +147,7 @@ message Response { ResponseOfferSnapshot offer_snapshot = 13; ResponseLoadSnapshotChunk load_snapshot_chunk = 14; ResponseApplySnapshotChunk apply_snapshot_chunk = 15; + ResponsePrepareProposal prepare_proposal = 16; } } @@ -262,6 +273,10 @@ message ResponseApplySnapshotChunk { } } +message ResponsePrepareProposal { + tendermint.types.Data block_data = 1; +} + //---------------------------------------- // Misc. @@ -367,4 +382,5 @@ service ABCIApplication { rpc OfferSnapshot(RequestOfferSnapshot) returns (ResponseOfferSnapshot); rpc LoadSnapshotChunk(RequestLoadSnapshotChunk) returns (ResponseLoadSnapshotChunk); rpc ApplySnapshotChunk(RequestApplySnapshotChunk) returns (ResponseApplySnapshotChunk); + rpc PrepareProposal(RequestPrepareProposal) returns (ResponsePrepareProposal); } diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index 5a782fa337..1eaab99755 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -271,6 +271,11 @@ func (app *Application) Rollback() error { return app.state.Rollback() } +func (app *Application) PrepareProposal( + req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + return abci.ResponsePrepareProposal{BlockData: req.BlockData} +} + // validatorUpdates generates a validator set update. func (app *Application) validatorUpdates(height uint64) (abci.ValidatorUpdates, error) { updates := app.cfg.ValidatorUpdates[fmt.Sprintf("%v", height)] diff --git a/types/tx.go b/types/tx.go index ec6f868a1d..d2cce07bb4 100644 --- a/types/tx.go +++ b/types/tx.go @@ -183,6 +183,15 @@ func ToTxs(txs [][]byte) Txs { return txBzs } +// ToSliceOfBytes converts a Txs to slice of byte slices. +func (txs Txs) ToSliceOfBytes() [][]byte { + txBzs := make([][]byte, len(txs)) + for i := 0; i < len(txs); i++ { + txBzs[i] = txs[i] + } + return txBzs +} + // UnwrapMalleatedTx attempts to unmarshal the provided transaction into a malleated // transaction wrapper, if this an be done, then it returns true. A malleated // transaction is a normal transaction that has been derived (malleated) from a diff --git a/types/tx_test.go b/types/tx_test.go index 1366b88029..d77ba00e8f 100644 --- a/types/tx_test.go +++ b/types/tx_test.go @@ -1,7 +1,6 @@ package types import ( - mrand "math/rand" "testing" "github.com/stretchr/testify/assert" @@ -17,11 +16,6 @@ func makeTxs(cnt, size int) Txs { return txs } -func randInt(low, high int) int { - off := mrand.Int() % (high - low) - return low + off -} - func TestTxIndex(t *testing.T) { for i := 0; i < 20; i++ { txs := makeTxs(15, 60) From 2c9552db09841f2bbebc1ec34653b2441def9f13 Mon Sep 17 00:00:00 2001 From: mconcat Date: Sat, 9 Oct 2021 04:33:50 +0900 Subject: [PATCH 17/31] add processproposal proto/boilerplate/logic mockery fix test gofmt fix test gofmt move UNKNOWN response behaviour to reject update mocks fix naming of some fields in RoundState fix base abci app to pass data and accept blocks --- abci/client/client.go | 2 + abci/client/grpc_client.go | 34 + abci/client/local_client.go | 25 + abci/client/mocks/client.go | 46 + abci/client/socket_client.go | 19 + abci/example/kvstore/persistent_kvstore.go | 10 + abci/types/application.go | 13 +- abci/types/messages.go | 12 + abci/types/result.go | 17 + abci/types/types.pb.go | 1151 ++++++++++++++++---- internal/consensus/state.go | 13 + internal/proxy/app_conn.go | 8 + internal/proxy/mocks/app_conn_consensus.go | 23 + internal/state/execution.go | 17 + internal/state/execution_test.go | 33 + internal/state/helpers_test.go | 9 + proto/tendermint/abci/types.proto | 19 + 17 files changed, 1211 insertions(+), 240 deletions(-) diff --git a/abci/client/client.go b/abci/client/client.go index 24ff4467c6..5f35cb9630 100644 --- a/abci/client/client.go +++ b/abci/client/client.go @@ -47,6 +47,7 @@ type Client interface { LoadSnapshotChunkAsync(context.Context, types.RequestLoadSnapshotChunk) (*ReqRes, error) ApplySnapshotChunkAsync(context.Context, types.RequestApplySnapshotChunk) (*ReqRes, error) PrepareProposalAsync(context.Context, types.RequestPrepareProposal) (*ReqRes, error) + ProcessProposalAsync(context.Context, types.RequestProcessProposal) (*ReqRes, error) // Synchronous requests FlushSync(context.Context) error @@ -64,6 +65,7 @@ type Client interface { LoadSnapshotChunkSync(context.Context, types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error) ApplySnapshotChunkSync(context.Context, types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error) PrepareProposalSync(context.Context, types.RequestPrepareProposal) (*types.ResponsePrepareProposal, error) + ProcessProposalSync(context.Context, types.RequestProcessProposal) (*types.ResponseProcessProposal, error) } //---------------------------------------- diff --git a/abci/client/grpc_client.go b/abci/client/grpc_client.go index 483e4e523b..e1e79ebec1 100644 --- a/abci/client/grpc_client.go +++ b/abci/client/grpc_client.go @@ -336,6 +336,28 @@ func (cli *grpcClient) PrepareProposalAsync( ) } +func (cli *grpcClient) ProcessProposalAsync( + ctx context.Context, + params types.RequestProcessProposal, +) (*ReqRes, error) { + + req := types.ToRequestProcessProposal(params) + res, err := cli.client.ProcessProposal(ctx, req.GetProcessProposal(), grpc.WaitForReady(true)) + if err != nil { + return nil, err + } + + return cli.finishAsyncCall( + ctx, + req, + &types.Response{ + Value: &types.Response_ProcessProposal{ + ProcessProposal: res, + }, + }, + ) +} + // finishAsyncCall creates a ReqRes for an async call, and immediately populates it // with the response. We don't complete it until it's been ordered via the channel. func (cli *grpcClient) finishAsyncCall(ctx context.Context, req *types.Request, res *types.Response) (*ReqRes, error) { @@ -538,3 +560,15 @@ func (cli *grpcClient) PrepareProposalSync( } return cli.finishSyncCall(reqres).GetPrepareProposal(), cli.Error() } + +func (cli *grpcClient) ProcessProposalSync( + ctx context.Context, + params types.RequestProcessProposal, +) (*types.ResponseProcessProposal, error) { + + reqres, err := cli.ProcessProposalAsync(ctx, params) + if err != nil { + return nil, err + } + return cli.finishSyncCall(reqres).GetProcessProposal(), cli.Error() +} diff --git a/abci/client/local_client.go b/abci/client/local_client.go index 9a72dae784..776fc3dd80 100644 --- a/abci/client/local_client.go +++ b/abci/client/local_client.go @@ -216,6 +216,20 @@ func (app *localClient) PrepareProposalAsync( ), nil } +func (app *localClient) ProcessProposalAsync( + ctx context.Context, + req types.RequestProcessProposal, +) (*ReqRes, error) { + app.mtx.Lock() + defer app.mtx.Unlock() + + res := app.Application.ProcessProposal(req) + return app.callback( + types.ToRequestProcessProposal(req), + types.ToResponseProcessProposal(res), + ), nil +} + //------------------------------------------------------- func (app *localClient) FlushSync(ctx context.Context) error { @@ -370,6 +384,17 @@ func (app *localClient) PrepareProposalSync( return &res, nil } +func (app *localClient) ProcessProposalSync( + ctx context.Context, + req types.RequestProcessProposal, +) (*types.ResponseProcessProposal, error) { + app.mtx.Lock() + defer app.mtx.Unlock() + + res := app.Application.ProcessProposal(req) + return &res, nil +} + //------------------------------------------------------- func (app *localClient) callback(req *types.Request, res *types.Response) *ReqRes { diff --git a/abci/client/mocks/client.go b/abci/client/mocks/client.go index 830516985a..a8cba43b54 100644 --- a/abci/client/mocks/client.go +++ b/abci/client/mocks/client.go @@ -717,6 +717,52 @@ func (_m *Client) PrepareProposalSync(_a0 context.Context, _a1 types.RequestPrep return r0, r1 } +// ProcessProposalAsync provides a mock function with given fields: _a0, _a1 +func (_m *Client) ProcessProposalAsync(_a0 context.Context, _a1 types.RequestProcessProposal) (*abciclient.ReqRes, error) { + ret := _m.Called(_a0, _a1) + + var r0 *abciclient.ReqRes + if rf, ok := ret.Get(0).(func(context.Context, types.RequestProcessProposal) *abciclient.ReqRes); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*abciclient.ReqRes) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, types.RequestProcessProposal) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProcessProposalSync provides a mock function with given fields: _a0, _a1 +func (_m *Client) ProcessProposalSync(_a0 context.Context, _a1 types.RequestProcessProposal) (*types.ResponseProcessProposal, error) { + ret := _m.Called(_a0, _a1) + + var r0 *types.ResponseProcessProposal + if rf, ok := ret.Get(0).(func(context.Context, types.RequestProcessProposal) *types.ResponseProcessProposal); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.ResponseProcessProposal) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, types.RequestProcessProposal) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // QueryAsync provides a mock function with given fields: _a0, _a1 func (_m *Client) QueryAsync(_a0 context.Context, _a1 types.RequestQuery) (*abciclient.ReqRes, error) { ret := _m.Called(_a0, _a1) diff --git a/abci/client/socket_client.go b/abci/client/socket_client.go index 9ccefaed94..89c8e080fa 100644 --- a/abci/client/socket_client.go +++ b/abci/client/socket_client.go @@ -283,6 +283,13 @@ func (cli *socketClient) PrepareProposalAsync( return cli.queueRequestAsync(ctx, types.ToRequestPrepareProposal(req)) } +func (cli *socketClient) ProcessProposalAsync( + ctx context.Context, + req types.RequestProcessProposal, +) (*ReqRes, error) { + return cli.queueRequestAsync(ctx, types.ToRequestProcessProposal(req)) +} + //---------------------------------------- func (cli *socketClient) FlushSync(ctx context.Context) error { @@ -465,6 +472,18 @@ func (cli *socketClient) PrepareProposalSync( return reqres.Response.GetPrepareProposal(), nil } +func (cli *socketClient) ProcessProposalSync( + ctx context.Context, + req types.RequestProcessProposal, +) (*types.ResponseProcessProposal, error) { + + reqres, err := cli.queueRequestAndFlushSync(ctx, types.ToRequestProcessProposal(req)) + if err != nil { + return nil, err + } + return reqres.Response.GetProcessProposal(), nil +} + //---------------------------------------- // queueRequest enqueues req onto the queue. The request can break early if the diff --git a/abci/example/kvstore/persistent_kvstore.go b/abci/example/kvstore/persistent_kvstore.go index b98ae0c505..5e5975ff4a 100644 --- a/abci/example/kvstore/persistent_kvstore.go +++ b/abci/example/kvstore/persistent_kvstore.go @@ -179,6 +179,16 @@ func (app *PersistentKVStoreApplication) PrepareProposal( return types.ResponsePrepareProposal{BlockData: req.BlockData} } +func (app *PersistentKVStoreApplication) ProcessProposal( + req types.RequestProcessProposal) types.ResponseProcessProposal { + for _, tx := range req.Txs { + if len(tx) == 0 { + return types.ResponseProcessProposal{Result: types.ResponseProcessProposal_REJECT} + } + } + return types.ResponseProcessProposal{Result: types.ResponseProcessProposal_ACCEPT} +} + //--------------------------------------------- // update validators diff --git a/abci/types/application.go b/abci/types/application.go index 4a74c78526..61b8f68c6c 100644 --- a/abci/types/application.go +++ b/abci/types/application.go @@ -23,6 +23,7 @@ type Application interface { DeliverTx(RequestDeliverTx) ResponseDeliverTx // Deliver a tx for full processing EndBlock(RequestEndBlock) ResponseEndBlock // Signals the end of a block, returns changes to the validator set Commit() ResponseCommit // Commit the state and return the application Merkle root hash + ProcessProposal(RequestProcessProposal) ResponseProcessProposal // State Sync Connection ListSnapshots(RequestListSnapshots) ResponseListSnapshots // List available snapshots @@ -92,7 +93,11 @@ func (BaseApplication) ApplySnapshotChunk(req RequestApplySnapshotChunk) Respons } func (BaseApplication) PrepareProposal(req RequestPrepareProposal) ResponsePrepareProposal { - return ResponsePrepareProposal{} + return ResponsePrepareProposal{BlockData: req.BlockData} +} + +func (BaseApplication) ProcessProposal(req RequestProcessProposal) ResponseProcessProposal { + return ResponseProcessProposal{Result: ResponseProcessProposal_ACCEPT} } //------------------------------------------------------- @@ -183,3 +188,9 @@ func (app *GRPCApplication) PrepareProposal( res := app.app.PrepareProposal(*req) return &res, nil } + +func (app *GRPCApplication) ProcessProposal( + ctx context.Context, req *RequestProcessProposal) (*ResponseProcessProposal, error) { + res := app.app.ProcessProposal(*req) + return &res, nil +} diff --git a/abci/types/messages.go b/abci/types/messages.go index 8c17baeb3a..9098437bd3 100644 --- a/abci/types/messages.go +++ b/abci/types/messages.go @@ -116,6 +116,12 @@ func ToRequestPrepareProposal(req RequestPrepareProposal) *Request { } } +func ToRequestProcessProposal(req RequestProcessProposal) *Request { + return &Request{ + Value: &Request_ProcessProposal{&req}, + } +} + //---------------------------------------- func ToResponseException(errStr string) *Response { @@ -212,3 +218,9 @@ func ToResponsePrepareProposal(res ResponsePrepareProposal) *Response { Value: &Response_PrepareProposal{&res}, } } + +func ToResponseProcessProposal(res ResponseProcessProposal) *Response { + return &Response{ + Value: &Response_ProcessProposal{&res}, + } +} diff --git a/abci/types/result.go b/abci/types/result.go index dba6bfd159..a071d303a4 100644 --- a/abci/types/result.go +++ b/abci/types/result.go @@ -41,6 +41,23 @@ func (r ResponseQuery) IsErr() bool { return r.Code != CodeTypeOK } +// IsOK returns true if Code is OK + +// IsUnknown returns true if Code is Unknown +func (r ResponseProcessProposal) IsUnknown() bool { + return r.Result == ResponseProcessProposal_UNKNOWN +} + +// IsOK returns true if Code is OK +func (r ResponseProcessProposal) IsOK() bool { + return r.Result == ResponseProcessProposal_ACCEPT +} + +// IsErr returns true if Code is something other than OK. +func (r ResponseProcessProposal) IsErr() bool { + return r.Result != ResponseProcessProposal_ACCEPT +} + //--------------------------------------------------------------------------- // override JSON marshaling so we emit defaults (ie. disable omitempty) diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 125bd7ed51..e6fbde8566 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -120,7 +120,7 @@ func (x ResponseOfferSnapshot_Result) String() string { } func (ResponseOfferSnapshot_Result) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{29, 0} + return fileDescriptor_252557cfdd89a31a, []int{30, 0} } type ResponseApplySnapshotChunk_Result int32 @@ -157,7 +157,35 @@ func (x ResponseApplySnapshotChunk_Result) String() string { } func (ResponseApplySnapshotChunk_Result) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{31, 0} + return fileDescriptor_252557cfdd89a31a, []int{32, 0} +} + +type ResponseProcessProposal_Result int32 + +const ( + ResponseProcessProposal_UNKNOWN ResponseProcessProposal_Result = 0 + ResponseProcessProposal_ACCEPT ResponseProcessProposal_Result = 1 + ResponseProcessProposal_REJECT ResponseProcessProposal_Result = 2 +) + +var ResponseProcessProposal_Result_name = map[int32]string{ + 0: "UNKNOWN", + 1: "ACCEPT", + 2: "REJECT", +} + +var ResponseProcessProposal_Result_value = map[string]int32{ + "UNKNOWN": 0, + "ACCEPT": 1, + "REJECT": 2, +} + +func (x ResponseProcessProposal_Result) String() string { + return proto.EnumName(ResponseProcessProposal_Result_name, int32(x)) +} + +func (ResponseProcessProposal_Result) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{34, 0} } type Request struct { @@ -177,6 +205,7 @@ type Request struct { // *Request_LoadSnapshotChunk // *Request_ApplySnapshotChunk // *Request_PrepareProposal + // *Request_ProcessProposal Value isRequest_Value `protobuf_oneof:"value"` } @@ -264,6 +293,9 @@ type Request_ApplySnapshotChunk struct { type Request_PrepareProposal struct { PrepareProposal *RequestPrepareProposal `protobuf:"bytes,15,opt,name=prepare_proposal,json=prepareProposal,proto3,oneof" json:"prepare_proposal,omitempty"` } +type Request_ProcessProposal struct { + ProcessProposal *RequestProcessProposal `protobuf:"bytes,16,opt,name=process_proposal,json=processProposal,proto3,oneof" json:"process_proposal,omitempty"` +} func (*Request_Echo) isRequest_Value() {} func (*Request_Flush) isRequest_Value() {} @@ -280,6 +312,7 @@ func (*Request_OfferSnapshot) isRequest_Value() {} func (*Request_LoadSnapshotChunk) isRequest_Value() {} func (*Request_ApplySnapshotChunk) isRequest_Value() {} func (*Request_PrepareProposal) isRequest_Value() {} +func (*Request_ProcessProposal) isRequest_Value() {} func (m *Request) GetValue() isRequest_Value { if m != nil { @@ -393,6 +426,13 @@ func (m *Request) GetPrepareProposal() *RequestPrepareProposal { return nil } +func (m *Request) GetProcessProposal() *RequestProcessProposal { + if x, ok := m.GetValue().(*Request_ProcessProposal); ok { + return x.ProcessProposal + } + return nil +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*Request) XXX_OneofWrappers() []interface{} { return []interface{}{ @@ -411,6 +451,7 @@ func (*Request) XXX_OneofWrappers() []interface{} { (*Request_LoadSnapshotChunk)(nil), (*Request_ApplySnapshotChunk)(nil), (*Request_PrepareProposal)(nil), + (*Request_ProcessProposal)(nil), } } @@ -1226,6 +1267,58 @@ func (m *RequestPrepareProposal) GetBlockDataSize() int64 { return 0 } +type RequestProcessProposal struct { + Header types1.Header `protobuf:"bytes,1,opt,name=header,proto3" json:"header"` + Txs [][]byte `protobuf:"bytes,2,rep,name=txs,proto3" json:"txs,omitempty"` +} + +func (m *RequestProcessProposal) Reset() { *m = RequestProcessProposal{} } +func (m *RequestProcessProposal) String() string { return proto.CompactTextString(m) } +func (*RequestProcessProposal) ProtoMessage() {} +func (*RequestProcessProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{16} +} +func (m *RequestProcessProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RequestProcessProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RequestProcessProposal.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 *RequestProcessProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_RequestProcessProposal.Merge(m, src) +} +func (m *RequestProcessProposal) XXX_Size() int { + return m.Size() +} +func (m *RequestProcessProposal) XXX_DiscardUnknown() { + xxx_messageInfo_RequestProcessProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_RequestProcessProposal proto.InternalMessageInfo + +func (m *RequestProcessProposal) GetHeader() types1.Header { + if m != nil { + return m.Header + } + return types1.Header{} +} + +func (m *RequestProcessProposal) GetTxs() [][]byte { + if m != nil { + return m.Txs + } + return nil +} + type Response struct { // Types that are valid to be assigned to Value: // *Response_Exception @@ -1244,6 +1337,7 @@ type Response struct { // *Response_LoadSnapshotChunk // *Response_ApplySnapshotChunk // *Response_PrepareProposal + // *Response_ProcessProposal Value isResponse_Value `protobuf_oneof:"value"` } @@ -1251,7 +1345,7 @@ func (m *Response) Reset() { *m = Response{} } func (m *Response) String() string { return proto.CompactTextString(m) } func (*Response) ProtoMessage() {} func (*Response) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{16} + return fileDescriptor_252557cfdd89a31a, []int{17} } func (m *Response) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1334,6 +1428,9 @@ type Response_ApplySnapshotChunk struct { type Response_PrepareProposal struct { PrepareProposal *ResponsePrepareProposal `protobuf:"bytes,16,opt,name=prepare_proposal,json=prepareProposal,proto3,oneof" json:"prepare_proposal,omitempty"` } +type Response_ProcessProposal struct { + ProcessProposal *ResponseProcessProposal `protobuf:"bytes,17,opt,name=process_proposal,json=processProposal,proto3,oneof" json:"process_proposal,omitempty"` +} func (*Response_Exception) isResponse_Value() {} func (*Response_Echo) isResponse_Value() {} @@ -1351,6 +1448,7 @@ func (*Response_OfferSnapshot) isResponse_Value() {} func (*Response_LoadSnapshotChunk) isResponse_Value() {} func (*Response_ApplySnapshotChunk) isResponse_Value() {} func (*Response_PrepareProposal) isResponse_Value() {} +func (*Response_ProcessProposal) isResponse_Value() {} func (m *Response) GetValue() isResponse_Value { if m != nil { @@ -1471,6 +1569,13 @@ func (m *Response) GetPrepareProposal() *ResponsePrepareProposal { return nil } +func (m *Response) GetProcessProposal() *ResponseProcessProposal { + if x, ok := m.GetValue().(*Response_ProcessProposal); ok { + return x.ProcessProposal + } + return nil +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*Response) XXX_OneofWrappers() []interface{} { return []interface{}{ @@ -1490,6 +1595,7 @@ func (*Response) XXX_OneofWrappers() []interface{} { (*Response_LoadSnapshotChunk)(nil), (*Response_ApplySnapshotChunk)(nil), (*Response_PrepareProposal)(nil), + (*Response_ProcessProposal)(nil), } } @@ -1502,7 +1608,7 @@ func (m *ResponseException) Reset() { *m = ResponseException{} } func (m *ResponseException) String() string { return proto.CompactTextString(m) } func (*ResponseException) ProtoMessage() {} func (*ResponseException) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{17} + return fileDescriptor_252557cfdd89a31a, []int{18} } func (m *ResponseException) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1546,7 +1652,7 @@ func (m *ResponseEcho) Reset() { *m = ResponseEcho{} } func (m *ResponseEcho) String() string { return proto.CompactTextString(m) } func (*ResponseEcho) ProtoMessage() {} func (*ResponseEcho) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{18} + return fileDescriptor_252557cfdd89a31a, []int{19} } func (m *ResponseEcho) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1589,7 +1695,7 @@ func (m *ResponseFlush) Reset() { *m = ResponseFlush{} } func (m *ResponseFlush) String() string { return proto.CompactTextString(m) } func (*ResponseFlush) ProtoMessage() {} func (*ResponseFlush) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{19} + return fileDescriptor_252557cfdd89a31a, []int{20} } func (m *ResponseFlush) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1631,7 +1737,7 @@ func (m *ResponseInfo) Reset() { *m = ResponseInfo{} } func (m *ResponseInfo) String() string { return proto.CompactTextString(m) } func (*ResponseInfo) ProtoMessage() {} func (*ResponseInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{20} + return fileDescriptor_252557cfdd89a31a, []int{21} } func (m *ResponseInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1705,7 +1811,7 @@ func (m *ResponseInitChain) Reset() { *m = ResponseInitChain{} } func (m *ResponseInitChain) String() string { return proto.CompactTextString(m) } func (*ResponseInitChain) ProtoMessage() {} func (*ResponseInitChain) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{21} + return fileDescriptor_252557cfdd89a31a, []int{22} } func (m *ResponseInitChain) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1772,7 +1878,7 @@ func (m *ResponseQuery) Reset() { *m = ResponseQuery{} } func (m *ResponseQuery) String() string { return proto.CompactTextString(m) } func (*ResponseQuery) ProtoMessage() {} func (*ResponseQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{22} + return fileDescriptor_252557cfdd89a31a, []int{23} } func (m *ResponseQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1872,7 +1978,7 @@ func (m *ResponseBeginBlock) Reset() { *m = ResponseBeginBlock{} } func (m *ResponseBeginBlock) String() string { return proto.CompactTextString(m) } func (*ResponseBeginBlock) ProtoMessage() {} func (*ResponseBeginBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{23} + return fileDescriptor_252557cfdd89a31a, []int{24} } func (m *ResponseBeginBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1928,7 +2034,7 @@ func (m *ResponseCheckTx) Reset() { *m = ResponseCheckTx{} } func (m *ResponseCheckTx) String() string { return proto.CompactTextString(m) } func (*ResponseCheckTx) ProtoMessage() {} func (*ResponseCheckTx) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{24} + return fileDescriptor_252557cfdd89a31a, []int{25} } func (m *ResponseCheckTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2049,7 +2155,7 @@ func (m *ResponseDeliverTx) Reset() { *m = ResponseDeliverTx{} } func (m *ResponseDeliverTx) String() string { return proto.CompactTextString(m) } func (*ResponseDeliverTx) ProtoMessage() {} func (*ResponseDeliverTx) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{25} + return fileDescriptor_252557cfdd89a31a, []int{26} } func (m *ResponseDeliverTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2144,7 +2250,7 @@ func (m *ResponseEndBlock) Reset() { *m = ResponseEndBlock{} } func (m *ResponseEndBlock) String() string { return proto.CompactTextString(m) } func (*ResponseEndBlock) ProtoMessage() {} func (*ResponseEndBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{26} + return fileDescriptor_252557cfdd89a31a, []int{27} } func (m *ResponseEndBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2204,7 +2310,7 @@ func (m *ResponseCommit) Reset() { *m = ResponseCommit{} } func (m *ResponseCommit) String() string { return proto.CompactTextString(m) } func (*ResponseCommit) ProtoMessage() {} func (*ResponseCommit) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{27} + return fileDescriptor_252557cfdd89a31a, []int{28} } func (m *ResponseCommit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2255,7 +2361,7 @@ func (m *ResponseListSnapshots) Reset() { *m = ResponseListSnapshots{} } func (m *ResponseListSnapshots) String() string { return proto.CompactTextString(m) } func (*ResponseListSnapshots) ProtoMessage() {} func (*ResponseListSnapshots) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{28} + return fileDescriptor_252557cfdd89a31a, []int{29} } func (m *ResponseListSnapshots) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2299,7 +2405,7 @@ func (m *ResponseOfferSnapshot) Reset() { *m = ResponseOfferSnapshot{} } func (m *ResponseOfferSnapshot) String() string { return proto.CompactTextString(m) } func (*ResponseOfferSnapshot) ProtoMessage() {} func (*ResponseOfferSnapshot) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{29} + return fileDescriptor_252557cfdd89a31a, []int{30} } func (m *ResponseOfferSnapshot) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2343,7 +2449,7 @@ func (m *ResponseLoadSnapshotChunk) Reset() { *m = ResponseLoadSnapshotC func (m *ResponseLoadSnapshotChunk) String() string { return proto.CompactTextString(m) } func (*ResponseLoadSnapshotChunk) ProtoMessage() {} func (*ResponseLoadSnapshotChunk) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{30} + return fileDescriptor_252557cfdd89a31a, []int{31} } func (m *ResponseLoadSnapshotChunk) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2389,7 +2495,7 @@ func (m *ResponseApplySnapshotChunk) Reset() { *m = ResponseApplySnapsho func (m *ResponseApplySnapshotChunk) String() string { return proto.CompactTextString(m) } func (*ResponseApplySnapshotChunk) ProtoMessage() {} func (*ResponseApplySnapshotChunk) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{31} + return fileDescriptor_252557cfdd89a31a, []int{32} } func (m *ResponseApplySnapshotChunk) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2447,7 +2553,7 @@ func (m *ResponsePrepareProposal) Reset() { *m = ResponsePrepareProposal func (m *ResponsePrepareProposal) String() string { return proto.CompactTextString(m) } func (*ResponsePrepareProposal) ProtoMessage() {} func (*ResponsePrepareProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{32} + return fileDescriptor_252557cfdd89a31a, []int{33} } func (m *ResponsePrepareProposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2483,6 +2589,58 @@ func (m *ResponsePrepareProposal) GetBlockData() *types1.Data { return nil } +type ResponseProcessProposal struct { + Result ResponseProcessProposal_Result `protobuf:"varint,1,opt,name=result,proto3,enum=tendermint.abci.ResponseProcessProposal_Result" json:"result,omitempty"` + Evidence [][]byte `protobuf:"bytes,2,rep,name=evidence,proto3" json:"evidence,omitempty"` +} + +func (m *ResponseProcessProposal) Reset() { *m = ResponseProcessProposal{} } +func (m *ResponseProcessProposal) String() string { return proto.CompactTextString(m) } +func (*ResponseProcessProposal) ProtoMessage() {} +func (*ResponseProcessProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{34} +} +func (m *ResponseProcessProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResponseProcessProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResponseProcessProposal.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 *ResponseProcessProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResponseProcessProposal.Merge(m, src) +} +func (m *ResponseProcessProposal) XXX_Size() int { + return m.Size() +} +func (m *ResponseProcessProposal) XXX_DiscardUnknown() { + xxx_messageInfo_ResponseProcessProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_ResponseProcessProposal proto.InternalMessageInfo + +func (m *ResponseProcessProposal) GetResult() ResponseProcessProposal_Result { + if m != nil { + return m.Result + } + return ResponseProcessProposal_UNKNOWN +} + +func (m *ResponseProcessProposal) GetEvidence() [][]byte { + if m != nil { + return m.Evidence + } + return nil +} + type LastCommitInfo struct { Round int32 `protobuf:"varint,1,opt,name=round,proto3" json:"round,omitempty"` Votes []VoteInfo `protobuf:"bytes,2,rep,name=votes,proto3" json:"votes"` @@ -2492,7 +2650,7 @@ func (m *LastCommitInfo) Reset() { *m = LastCommitInfo{} } func (m *LastCommitInfo) String() string { return proto.CompactTextString(m) } func (*LastCommitInfo) ProtoMessage() {} func (*LastCommitInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{33} + return fileDescriptor_252557cfdd89a31a, []int{35} } func (m *LastCommitInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2547,7 +2705,7 @@ func (m *Event) Reset() { *m = Event{} } func (m *Event) String() string { return proto.CompactTextString(m) } func (*Event) ProtoMessage() {} func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{34} + return fileDescriptor_252557cfdd89a31a, []int{36} } func (m *Event) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2601,7 +2759,7 @@ func (m *EventAttribute) Reset() { *m = EventAttribute{} } func (m *EventAttribute) String() string { return proto.CompactTextString(m) } func (*EventAttribute) ProtoMessage() {} func (*EventAttribute) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{35} + return fileDescriptor_252557cfdd89a31a, []int{37} } func (m *EventAttribute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2666,7 +2824,7 @@ func (m *TxResult) Reset() { *m = TxResult{} } func (m *TxResult) String() string { return proto.CompactTextString(m) } func (*TxResult) ProtoMessage() {} func (*TxResult) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{36} + return fileDescriptor_252557cfdd89a31a, []int{38} } func (m *TxResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2741,7 +2899,7 @@ func (m *Validator) Reset() { *m = Validator{} } func (m *Validator) String() string { return proto.CompactTextString(m) } func (*Validator) ProtoMessage() {} func (*Validator) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{37} + return fileDescriptor_252557cfdd89a31a, []int{39} } func (m *Validator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2794,7 +2952,7 @@ func (m *ValidatorUpdate) Reset() { *m = ValidatorUpdate{} } func (m *ValidatorUpdate) String() string { return proto.CompactTextString(m) } func (*ValidatorUpdate) ProtoMessage() {} func (*ValidatorUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{38} + return fileDescriptor_252557cfdd89a31a, []int{40} } func (m *ValidatorUpdate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2847,7 +3005,7 @@ func (m *VoteInfo) Reset() { *m = VoteInfo{} } func (m *VoteInfo) String() string { return proto.CompactTextString(m) } func (*VoteInfo) ProtoMessage() {} func (*VoteInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{39} + return fileDescriptor_252557cfdd89a31a, []int{41} } func (m *VoteInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2908,7 +3066,7 @@ func (m *Evidence) Reset() { *m = Evidence{} } func (m *Evidence) String() string { return proto.CompactTextString(m) } func (*Evidence) ProtoMessage() {} func (*Evidence) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{40} + return fileDescriptor_252557cfdd89a31a, []int{42} } func (m *Evidence) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2984,7 +3142,7 @@ func (m *Snapshot) Reset() { *m = Snapshot{} } func (m *Snapshot) String() string { return proto.CompactTextString(m) } func (*Snapshot) ProtoMessage() {} func (*Snapshot) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{41} + return fileDescriptor_252557cfdd89a31a, []int{43} } func (m *Snapshot) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3053,6 +3211,7 @@ func init() { proto.RegisterEnum("tendermint.abci.EvidenceType", EvidenceType_name, EvidenceType_value) proto.RegisterEnum("tendermint.abci.ResponseOfferSnapshot_Result", ResponseOfferSnapshot_Result_name, ResponseOfferSnapshot_Result_value) proto.RegisterEnum("tendermint.abci.ResponseApplySnapshotChunk_Result", ResponseApplySnapshotChunk_Result_name, ResponseApplySnapshotChunk_Result_value) + proto.RegisterEnum("tendermint.abci.ResponseProcessProposal_Result", ResponseProcessProposal_Result_name, ResponseProcessProposal_Result_value) proto.RegisterType((*Request)(nil), "tendermint.abci.Request") proto.RegisterType((*RequestEcho)(nil), "tendermint.abci.RequestEcho") proto.RegisterType((*RequestFlush)(nil), "tendermint.abci.RequestFlush") @@ -3069,6 +3228,7 @@ func init() { proto.RegisterType((*RequestLoadSnapshotChunk)(nil), "tendermint.abci.RequestLoadSnapshotChunk") proto.RegisterType((*RequestApplySnapshotChunk)(nil), "tendermint.abci.RequestApplySnapshotChunk") proto.RegisterType((*RequestPrepareProposal)(nil), "tendermint.abci.RequestPrepareProposal") + proto.RegisterType((*RequestProcessProposal)(nil), "tendermint.abci.RequestProcessProposal") proto.RegisterType((*Response)(nil), "tendermint.abci.Response") proto.RegisterType((*ResponseException)(nil), "tendermint.abci.ResponseException") proto.RegisterType((*ResponseEcho)(nil), "tendermint.abci.ResponseEcho") @@ -3086,6 +3246,7 @@ func init() { proto.RegisterType((*ResponseLoadSnapshotChunk)(nil), "tendermint.abci.ResponseLoadSnapshotChunk") proto.RegisterType((*ResponseApplySnapshotChunk)(nil), "tendermint.abci.ResponseApplySnapshotChunk") proto.RegisterType((*ResponsePrepareProposal)(nil), "tendermint.abci.ResponsePrepareProposal") + proto.RegisterType((*ResponseProcessProposal)(nil), "tendermint.abci.ResponseProcessProposal") proto.RegisterType((*LastCommitInfo)(nil), "tendermint.abci.LastCommitInfo") proto.RegisterType((*Event)(nil), "tendermint.abci.Event") proto.RegisterType((*EventAttribute)(nil), "tendermint.abci.EventAttribute") @@ -3100,180 +3261,186 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 2756 bytes of a gzipped FileDescriptorProto + // 2856 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0x4b, 0x73, 0x1b, 0xc7, - 0xf1, 0xc7, 0x93, 0xc0, 0x36, 0x9e, 0x1a, 0xc9, 0x32, 0x0c, 0xcb, 0xa4, 0xbc, 0x2a, 0xbf, 0x64, - 0x9b, 0xfc, 0x9b, 0x2e, 0xf9, 0x6f, 0x97, 0xf3, 0x30, 0x01, 0x41, 0x01, 0x2d, 0x86, 0x64, 0x86, - 0x90, 0x5c, 0x4e, 0x62, 0xad, 0x17, 0xd8, 0x21, 0xb0, 0x16, 0xb0, 0xbb, 0xde, 0x1d, 0x50, 0xa4, - 0x8e, 0xa9, 0xe4, 0xe2, 0xca, 0xc1, 0x97, 0x54, 0xe5, 0xe2, 0x53, 0x3e, 0x40, 0xae, 0x39, 0xe5, - 0x94, 0x83, 0x0f, 0x39, 0xf8, 0x98, 0x43, 0xca, 0x49, 0x59, 0xb7, 0x7c, 0x01, 0x9f, 0x52, 0x95, - 0x9a, 0xc7, 0xbe, 0x00, 0x2c, 0x01, 0xda, 0xb9, 0xe5, 0x36, 0xd3, 0xdb, 0xdd, 0x98, 0xe9, 0x99, - 0xf9, 0xf5, 0x6f, 0x7a, 0x00, 0xcf, 0x52, 0x62, 0x19, 0xc4, 0x9d, 0x98, 0x16, 0xdd, 0xd2, 0xfb, - 0x03, 0x73, 0x8b, 0x9e, 0x39, 0xc4, 0xdb, 0x74, 0x5c, 0x9b, 0xda, 0xa8, 0x16, 0x7e, 0xdc, 0x64, - 0x1f, 0x9b, 0xcf, 0x45, 0xb4, 0x07, 0xee, 0x99, 0x43, 0xed, 0x2d, 0xc7, 0xb5, 0xed, 0x63, 0xa1, - 0xdf, 0xbc, 0x16, 0xf9, 0xcc, 0xfd, 0x44, 0xbd, 0xc5, 0xbe, 0x4a, 0xe3, 0x87, 0xe4, 0xcc, 0xff, - 0xfa, 0xdc, 0x9c, 0xad, 0xa3, 0xbb, 0xfa, 0xc4, 0xff, 0xbc, 0x31, 0xb4, 0xed, 0xe1, 0x98, 0x6c, - 0xf1, 0x5e, 0x7f, 0x7a, 0xbc, 0x45, 0xcd, 0x09, 0xf1, 0xa8, 0x3e, 0x71, 0xa4, 0xc2, 0x95, 0xa1, - 0x3d, 0xb4, 0x79, 0x73, 0x8b, 0xb5, 0x84, 0x54, 0xfd, 0x43, 0x11, 0x0a, 0x98, 0x7c, 0x3a, 0x25, - 0x1e, 0x45, 0xdb, 0x90, 0x23, 0x83, 0x91, 0xdd, 0x48, 0x5f, 0x4f, 0xbf, 0x5c, 0xda, 0xbe, 0xb6, - 0x39, 0x33, 0xb9, 0x4d, 0xa9, 0xd7, 0x19, 0x8c, 0xec, 0x6e, 0x0a, 0x73, 0x5d, 0x74, 0x0b, 0xf2, - 0xc7, 0xe3, 0xa9, 0x37, 0x6a, 0x64, 0xb8, 0xd1, 0x73, 0x49, 0x46, 0x77, 0x98, 0x52, 0x37, 0x85, - 0x85, 0x36, 0xfb, 0x29, 0xd3, 0x3a, 0xb6, 0x1b, 0xd9, 0xf3, 0x7f, 0x6a, 0xd7, 0x3a, 0xe6, 0x3f, - 0xc5, 0x74, 0x51, 0x0b, 0xc0, 0xb4, 0x4c, 0xaa, 0x0d, 0x46, 0xba, 0x69, 0x35, 0x72, 0xdc, 0xf2, - 0xf9, 0x64, 0x4b, 0x93, 0xb6, 0x99, 0x62, 0x37, 0x85, 0x15, 0xd3, 0xef, 0xb0, 0xe1, 0x7e, 0x3a, - 0x25, 0xee, 0x59, 0x23, 0x7f, 0xfe, 0x70, 0x7f, 0xc6, 0x94, 0xd8, 0x70, 0xb9, 0x36, 0xea, 0x40, - 0xa9, 0x4f, 0x86, 0xa6, 0xa5, 0xf5, 0xc7, 0xf6, 0xe0, 0x61, 0x63, 0x8d, 0x1b, 0xab, 0x49, 0xc6, - 0x2d, 0xa6, 0xda, 0x62, 0x9a, 0xdd, 0x14, 0x86, 0x7e, 0xd0, 0x43, 0x3f, 0x80, 0xe2, 0x60, 0x44, - 0x06, 0x0f, 0x35, 0x7a, 0xda, 0x28, 0x70, 0x1f, 0x1b, 0x49, 0x3e, 0xda, 0x4c, 0xaf, 0x77, 0xda, - 0x4d, 0xe1, 0xc2, 0x40, 0x34, 0xd9, 0xfc, 0x0d, 0x32, 0x36, 0x4f, 0x88, 0xcb, 0xec, 0x8b, 0xe7, - 0xcf, 0xff, 0xb6, 0xd0, 0xe4, 0x1e, 0x14, 0xc3, 0xef, 0xa0, 0x1f, 0x83, 0x42, 0x2c, 0x43, 0x4e, - 0x43, 0xe1, 0x2e, 0xae, 0x27, 0xae, 0xb3, 0x65, 0xf8, 0x93, 0x28, 0x12, 0xd9, 0x46, 0x6f, 0xc3, - 0xda, 0xc0, 0x9e, 0x4c, 0x4c, 0xda, 0x00, 0x6e, 0xbd, 0x9e, 0x38, 0x01, 0xae, 0xd5, 0x4d, 0x61, - 0xa9, 0x8f, 0xf6, 0xa1, 0x3a, 0x36, 0x3d, 0xaa, 0x79, 0x96, 0xee, 0x78, 0x23, 0x9b, 0x7a, 0x8d, - 0x12, 0xf7, 0xf0, 0x42, 0x92, 0x87, 0x3d, 0xd3, 0xa3, 0x47, 0xbe, 0x72, 0x37, 0x85, 0x2b, 0xe3, - 0xa8, 0x80, 0xf9, 0xb3, 0x8f, 0x8f, 0x89, 0x1b, 0x38, 0x6c, 0x94, 0xcf, 0xf7, 0x77, 0xc0, 0xb4, - 0x7d, 0x7b, 0xe6, 0xcf, 0x8e, 0x0a, 0xd0, 0x2f, 0xe0, 0xf2, 0xd8, 0xd6, 0x8d, 0xc0, 0x9d, 0x36, - 0x18, 0x4d, 0xad, 0x87, 0x8d, 0x0a, 0x77, 0xfa, 0x4a, 0xe2, 0x20, 0x6d, 0xdd, 0xf0, 0x5d, 0xb4, - 0x99, 0x41, 0x37, 0x85, 0x2f, 0x8d, 0x67, 0x85, 0xe8, 0x01, 0x5c, 0xd1, 0x1d, 0x67, 0x7c, 0x36, - 0xeb, 0xbd, 0xca, 0xbd, 0xdf, 0x4c, 0xf2, 0xbe, 0xc3, 0x6c, 0x66, 0xdd, 0x23, 0x7d, 0x4e, 0x8a, - 0x7a, 0x50, 0x77, 0x5c, 0xe2, 0xe8, 0x2e, 0xd1, 0x1c, 0xd7, 0x76, 0x6c, 0x4f, 0x1f, 0x37, 0x6a, - 0xdc, 0xf7, 0x4b, 0x49, 0xbe, 0x0f, 0x85, 0xfe, 0xa1, 0x54, 0xef, 0xa6, 0x70, 0xcd, 0x89, 0x8b, - 0x5a, 0x05, 0xc8, 0x9f, 0xe8, 0xe3, 0x29, 0x51, 0x5f, 0x82, 0x52, 0xe4, 0xf0, 0xa3, 0x06, 0x14, - 0x26, 0xc4, 0xf3, 0xf4, 0x21, 0xe1, 0x58, 0xa1, 0x60, 0xbf, 0xab, 0x56, 0xa1, 0x1c, 0x3d, 0xf0, - 0xea, 0xe7, 0xe9, 0xc0, 0x92, 0x9d, 0x65, 0x66, 0x79, 0x42, 0x5c, 0xcf, 0xb4, 0x2d, 0xdf, 0x52, - 0x76, 0xd1, 0x0d, 0xa8, 0xf0, 0x5d, 0xa9, 0xf9, 0xdf, 0x19, 0xa0, 0xe4, 0x70, 0x99, 0x0b, 0xef, - 0x4b, 0xa5, 0x0d, 0x28, 0x39, 0xdb, 0x4e, 0xa0, 0x92, 0xe5, 0x2a, 0xe0, 0x6c, 0x3b, 0xbe, 0xc2, - 0xf3, 0x50, 0x66, 0x73, 0x0c, 0x34, 0x72, 0xfc, 0x47, 0x4a, 0x4c, 0x26, 0x55, 0xd4, 0xbf, 0x66, - 0xa0, 0x3e, 0x0b, 0x12, 0xe8, 0x6d, 0xc8, 0x31, 0xbc, 0x94, 0xd0, 0xd7, 0xdc, 0x14, 0x60, 0xba, - 0xe9, 0x83, 0xe9, 0x66, 0xcf, 0x07, 0xd3, 0x56, 0xf1, 0xcb, 0xaf, 0x37, 0x52, 0x9f, 0xff, 0x63, - 0x23, 0x8d, 0xb9, 0x05, 0x7a, 0x86, 0x9d, 0x69, 0xdd, 0xb4, 0x34, 0xd3, 0xe0, 0x43, 0x56, 0xd8, - 0x81, 0xd5, 0x4d, 0x6b, 0xd7, 0x40, 0x7b, 0x50, 0x1f, 0xd8, 0x96, 0x47, 0x2c, 0x6f, 0xea, 0x69, - 0x02, 0xac, 0x25, 0xe0, 0xc5, 0x8e, 0xad, 0x48, 0x01, 0x6d, 0x5f, 0xf3, 0x90, 0x2b, 0xe2, 0xda, - 0x20, 0x2e, 0x40, 0x77, 0x00, 0x4e, 0xf4, 0xb1, 0x69, 0xe8, 0xd4, 0x76, 0xbd, 0x46, 0xee, 0x7a, - 0x76, 0xe1, 0xd9, 0xbd, 0xef, 0xab, 0xdc, 0x73, 0x0c, 0x9d, 0x92, 0x56, 0x8e, 0x0d, 0x17, 0x47, - 0x2c, 0xd1, 0x8b, 0x50, 0xd3, 0x1d, 0x47, 0xf3, 0xa8, 0x4e, 0x89, 0xd6, 0x3f, 0xa3, 0xc4, 0xe3, - 0x60, 0x58, 0xc6, 0x15, 0xdd, 0x71, 0x8e, 0x98, 0xb4, 0xc5, 0x84, 0xe8, 0x05, 0xa8, 0x32, 0xdc, - 0x34, 0xf5, 0xb1, 0x36, 0x22, 0xe6, 0x70, 0x44, 0x39, 0xec, 0x65, 0x71, 0x45, 0x4a, 0xbb, 0x5c, - 0xa8, 0x1a, 0xc1, 0x8a, 0x73, 0xcc, 0x44, 0x08, 0x72, 0x86, 0x4e, 0x75, 0x1e, 0xc9, 0x32, 0xe6, - 0x6d, 0x26, 0x73, 0x74, 0x3a, 0x92, 0xf1, 0xe1, 0x6d, 0x74, 0x15, 0xd6, 0xa4, 0xdb, 0x2c, 0x77, - 0x2b, 0x7b, 0xe8, 0x0a, 0xe4, 0x1d, 0xd7, 0x3e, 0x21, 0x7c, 0xe9, 0x8a, 0x58, 0x74, 0xd4, 0x5f, - 0x67, 0xe0, 0xd2, 0x1c, 0xba, 0x32, 0xbf, 0x23, 0xdd, 0x1b, 0xf9, 0xbf, 0xc5, 0xda, 0xe8, 0x2d, - 0xe6, 0x57, 0x37, 0x88, 0x2b, 0x33, 0x52, 0x63, 0x3e, 0xd4, 0x5d, 0xfe, 0x5d, 0x86, 0x46, 0x6a, - 0xa3, 0x03, 0xa8, 0x8f, 0x75, 0x8f, 0x6a, 0x02, 0xad, 0xb4, 0x48, 0x76, 0x9a, 0xc7, 0xe8, 0x3d, - 0xdd, 0xc7, 0x37, 0xb6, 0xa9, 0xa5, 0xa3, 0xea, 0x38, 0x26, 0x45, 0x18, 0xae, 0xf4, 0xcf, 0x1e, - 0xeb, 0x16, 0x35, 0x2d, 0xa2, 0xcd, 0xad, 0xdc, 0x33, 0x73, 0x4e, 0x3b, 0x27, 0xa6, 0x41, 0xac, - 0x81, 0xbf, 0x64, 0x97, 0x03, 0xe3, 0x60, 0x49, 0x3d, 0x15, 0x43, 0x35, 0x9e, 0x1f, 0x50, 0x15, - 0x32, 0xf4, 0x54, 0x06, 0x20, 0x43, 0x4f, 0xd1, 0xff, 0x41, 0x8e, 0x4d, 0x92, 0x4f, 0xbe, 0xba, - 0x20, 0xb1, 0x4a, 0xbb, 0xde, 0x99, 0x43, 0x30, 0xd7, 0x54, 0xd5, 0xe0, 0x38, 0x04, 0x39, 0x63, - 0xd6, 0xab, 0xfa, 0x0a, 0xd4, 0x66, 0x92, 0x42, 0x64, 0xfd, 0xd2, 0xd1, 0xf5, 0x53, 0x6b, 0x50, - 0x89, 0x65, 0x00, 0xf5, 0x2a, 0x5c, 0x59, 0x04, 0xe8, 0xea, 0x28, 0x90, 0xc7, 0x80, 0x19, 0xdd, - 0x82, 0x62, 0x80, 0xe8, 0xe2, 0x38, 0xce, 0xc7, 0xca, 0x57, 0xc6, 0x81, 0x2a, 0x3b, 0x87, 0x6c, - 0x5b, 0xf3, 0xfd, 0x90, 0xe1, 0x03, 0x2f, 0xe8, 0x8e, 0xd3, 0xd5, 0xbd, 0x91, 0xfa, 0x31, 0x34, - 0x92, 0xd0, 0x7a, 0x66, 0x1a, 0xb9, 0x60, 0x1b, 0x5e, 0x85, 0xb5, 0x63, 0xdb, 0x9d, 0xe8, 0x94, - 0x3b, 0xab, 0x60, 0xd9, 0x63, 0xdb, 0x53, 0x20, 0x77, 0x96, 0x8b, 0x45, 0x47, 0xd5, 0xe0, 0x99, - 0x44, 0xc4, 0x66, 0x26, 0xa6, 0x65, 0x10, 0x11, 0xcf, 0x0a, 0x16, 0x9d, 0xd0, 0x91, 0x18, 0xac, - 0xe8, 0xb0, 0x9f, 0xf5, 0xf8, 0x5c, 0xb9, 0x7f, 0x05, 0xcb, 0x9e, 0xfa, 0x08, 0xae, 0x2e, 0x86, - 0x6d, 0x74, 0x0b, 0x40, 0xe0, 0x66, 0x70, 0xea, 0x4a, 0xdb, 0x57, 0xe7, 0xf7, 0xfc, 0x6d, 0x9d, - 0xea, 0x58, 0xe1, 0x9a, 0xac, 0xc9, 0x50, 0x20, 0x34, 0xd3, 0x3c, 0xf3, 0xb1, 0xd8, 0x32, 0x59, - 0x5c, 0x09, 0x74, 0x8e, 0xcc, 0xc7, 0x44, 0xfd, 0xb6, 0x08, 0x45, 0x4c, 0x3c, 0x87, 0x81, 0x11, - 0x6a, 0x81, 0x42, 0x4e, 0x07, 0xc4, 0xa1, 0x3e, 0x7e, 0x2f, 0x26, 0x41, 0x42, 0xbb, 0xe3, 0x6b, - 0x32, 0x06, 0x12, 0x98, 0xa1, 0x37, 0x25, 0xc9, 0x4c, 0xe6, 0x8b, 0xd2, 0x3c, 0xca, 0x32, 0xdf, - 0xf2, 0x59, 0x66, 0x36, 0x91, 0x74, 0x08, 0xab, 0x19, 0x9a, 0xf9, 0xa6, 0xa4, 0x99, 0xb9, 0x25, - 0x3f, 0x16, 0xe3, 0x99, 0xed, 0x18, 0xcf, 0xcc, 0x2f, 0x99, 0x66, 0x02, 0xd1, 0x7c, 0xcb, 0x27, - 0x9a, 0x6b, 0x4b, 0x46, 0x3c, 0xc3, 0x34, 0xef, 0xc4, 0x99, 0xa6, 0x60, 0x89, 0x37, 0x12, 0xad, - 0x13, 0xa9, 0xe6, 0x0f, 0x23, 0x54, 0xb3, 0x98, 0xc8, 0xf3, 0x84, 0x93, 0x05, 0x5c, 0xb3, 0x1d, - 0xe3, 0x9a, 0xca, 0x92, 0x18, 0x24, 0x90, 0xcd, 0xf7, 0xa2, 0x64, 0x13, 0x12, 0xf9, 0xaa, 0x5c, - 0xef, 0x45, 0x6c, 0xf3, 0x9d, 0x80, 0x6d, 0x96, 0x12, 0xe9, 0xb2, 0x9c, 0xc3, 0x2c, 0xdd, 0x3c, - 0x98, 0xa3, 0x9b, 0x82, 0x1e, 0xbe, 0x98, 0xe8, 0x62, 0x09, 0xdf, 0x3c, 0x98, 0xe3, 0x9b, 0x95, - 0x25, 0x0e, 0x97, 0x10, 0xce, 0x5f, 0x2e, 0x26, 0x9c, 0xc9, 0x94, 0x50, 0x0e, 0x73, 0x35, 0xc6, - 0xa9, 0x25, 0x30, 0x4e, 0xc1, 0x0a, 0x5f, 0x4d, 0x74, 0xbf, 0x32, 0xe5, 0xbc, 0xb7, 0x80, 0x72, - 0xd6, 0xb9, 0xf3, 0x97, 0x13, 0x9d, 0x5f, 0x84, 0x73, 0xbe, 0xc2, 0x32, 0xfe, 0x0c, 0x94, 0x30, - 0xd4, 0x24, 0xae, 0x6b, 0xbb, 0x92, 0x3d, 0x8a, 0x8e, 0xfa, 0x32, 0xe3, 0x20, 0x21, 0x6c, 0x9c, - 0xc3, 0x4f, 0x79, 0x76, 0x8a, 0x40, 0x85, 0xfa, 0xa7, 0x74, 0x68, 0xcb, 0xd3, 0x76, 0x94, 0xbf, - 0x28, 0x92, 0xbf, 0x44, 0x58, 0x6b, 0x26, 0xce, 0x5a, 0x37, 0xa0, 0xc4, 0xb2, 0xce, 0x0c, 0x21, - 0xd5, 0x9d, 0x80, 0x90, 0xde, 0x84, 0x4b, 0x9c, 0x56, 0x08, 0xb0, 0x95, 0xa9, 0x26, 0xc7, 0x91, - 0xb6, 0xc6, 0x3e, 0x88, 0x3d, 0x2f, 0x72, 0xce, 0xeb, 0x70, 0x39, 0xa2, 0x1b, 0x64, 0x33, 0xc1, - 0xce, 0xea, 0x81, 0xf6, 0x8e, 0x4c, 0x6b, 0x7f, 0x49, 0x87, 0x11, 0x0a, 0x99, 0xec, 0x22, 0xd2, - 0x99, 0xfe, 0x2f, 0x91, 0xce, 0xcc, 0x77, 0x26, 0x9d, 0xd1, 0xec, 0x9c, 0x8d, 0x67, 0xe7, 0x6f, - 0xd3, 0xe1, 0x9a, 0x04, 0x14, 0x72, 0x60, 0x1b, 0x44, 0xe6, 0x4b, 0xde, 0x46, 0x75, 0xc8, 0x8e, - 0xed, 0xa1, 0xcc, 0x8a, 0xac, 0xc9, 0xb4, 0x02, 0x6c, 0x57, 0x24, 0x74, 0x07, 0xa9, 0x36, 0xcf, - 0x23, 0x2c, 0x53, 0x6d, 0x1d, 0xb2, 0x0f, 0x89, 0x40, 0xe2, 0x32, 0x66, 0x4d, 0xa6, 0xc7, 0x37, - 0x19, 0xc7, 0xd7, 0x32, 0x16, 0x1d, 0xf4, 0x36, 0x28, 0xbc, 0x58, 0xa3, 0xd9, 0x8e, 0x27, 0x41, - 0xf3, 0xd9, 0xe8, 0x5c, 0x45, 0x4d, 0x66, 0xf3, 0x90, 0xe9, 0x1c, 0x38, 0x1e, 0x2e, 0x3a, 0xb2, - 0x15, 0x61, 0x11, 0x4a, 0x8c, 0xcc, 0x5e, 0x03, 0x85, 0x8d, 0xde, 0x73, 0xf4, 0x01, 0xe1, 0x08, - 0xa8, 0xe0, 0x50, 0xa0, 0x3e, 0x00, 0x34, 0x8f, 0xe3, 0xa8, 0x0b, 0x6b, 0xe4, 0x84, 0x58, 0x94, - 0x2d, 0x5b, 0x76, 0x36, 0x99, 0x4b, 0xa6, 0x48, 0x2c, 0xda, 0x6a, 0xb0, 0x20, 0xff, 0xeb, 0xeb, - 0x8d, 0xba, 0xd0, 0x7e, 0xcd, 0x9e, 0x98, 0x94, 0x4c, 0x1c, 0x7a, 0x86, 0xa5, 0xbd, 0xfa, 0xf7, - 0x0c, 0xa3, 0x6d, 0x31, 0x8c, 0x5f, 0x18, 0x5b, 0x7f, 0xcb, 0x67, 0x22, 0x94, 0x7d, 0xb5, 0x78, - 0xaf, 0x03, 0x0c, 0x75, 0x4f, 0x7b, 0xa4, 0x5b, 0x94, 0x18, 0x32, 0xe8, 0x11, 0x09, 0x6a, 0x42, - 0x91, 0xf5, 0xa6, 0x1e, 0x31, 0xe4, 0xed, 0x21, 0xe8, 0x47, 0xe6, 0x59, 0xf8, 0x7e, 0xf3, 0x8c, - 0x47, 0xb9, 0x38, 0x13, 0xe5, 0x08, 0xa5, 0x52, 0xa2, 0x94, 0x8a, 0x8d, 0xcd, 0x71, 0x4d, 0xdb, - 0x35, 0xe9, 0x19, 0x5f, 0x9a, 0x2c, 0x0e, 0xfa, 0xec, 0x32, 0x3a, 0x21, 0x13, 0xc7, 0xb6, 0xc7, - 0x9a, 0x80, 0x9b, 0x12, 0x37, 0x2d, 0x4b, 0x61, 0x87, 0xa3, 0xce, 0x6f, 0x32, 0xe1, 0xf9, 0x0b, - 0xa9, 0xf3, 0xff, 0x5c, 0x80, 0xd5, 0xdf, 0xf2, 0x0b, 0x75, 0x3c, 0x8b, 0xa3, 0x23, 0xb8, 0x14, - 0x1c, 0x7f, 0x6d, 0xca, 0x61, 0xc1, 0xdf, 0xd0, 0xab, 0xe2, 0x47, 0xfd, 0x24, 0x2e, 0xf6, 0xd0, - 0x87, 0xf0, 0xf4, 0x0c, 0xb6, 0x05, 0xae, 0x33, 0xab, 0x42, 0xdc, 0x53, 0x71, 0x88, 0xf3, 0x5d, - 0x87, 0xc1, 0xca, 0x7e, 0xcf, 0x53, 0xb7, 0xcb, 0xee, 0x68, 0x51, 0x52, 0xb2, 0x70, 0xf9, 0x6f, - 0x40, 0xc5, 0x25, 0x54, 0x37, 0x2d, 0x2d, 0x76, 0x0b, 0x2e, 0x0b, 0xa1, 0xbc, 0x5b, 0x1f, 0xc2, - 0x53, 0x0b, 0xc9, 0x09, 0xfa, 0x7f, 0x50, 0x42, 0x5e, 0x93, 0x4e, 0xb8, 0x50, 0x06, 0x97, 0xa4, - 0x50, 0x57, 0xfd, 0x73, 0x3a, 0x74, 0x19, 0xbf, 0x76, 0x75, 0x60, 0xcd, 0x25, 0xde, 0x74, 0x2c, - 0x2e, 0x42, 0xd5, 0xed, 0xd7, 0x57, 0xa3, 0x35, 0x4c, 0x3a, 0x1d, 0x53, 0x2c, 0x8d, 0xd5, 0x07, - 0xb0, 0x26, 0x24, 0xa8, 0x04, 0x85, 0x7b, 0xfb, 0x77, 0xf7, 0x0f, 0x3e, 0xd8, 0xaf, 0xa7, 0x10, - 0xc0, 0xda, 0x4e, 0xbb, 0xdd, 0x39, 0xec, 0xd5, 0xd3, 0x48, 0x81, 0xfc, 0x4e, 0xeb, 0x00, 0xf7, - 0xea, 0x19, 0x26, 0xc6, 0x9d, 0xf7, 0x3b, 0xed, 0x5e, 0x3d, 0x8b, 0x2e, 0x41, 0x45, 0xb4, 0xb5, - 0x3b, 0x07, 0xf8, 0xa7, 0x3b, 0xbd, 0x7a, 0x2e, 0x22, 0x3a, 0xea, 0xec, 0xdf, 0xee, 0xe0, 0x7a, - 0x5e, 0x7d, 0x83, 0xdd, 0xb4, 0x12, 0x88, 0x50, 0x78, 0xa7, 0x4a, 0x47, 0xee, 0x54, 0xea, 0xef, - 0x33, 0xd0, 0x4c, 0x66, 0x37, 0xe8, 0xfd, 0x99, 0x89, 0x6f, 0x5f, 0x80, 0x1a, 0xcd, 0xcc, 0x1e, - 0xbd, 0x00, 0x55, 0x97, 0x1c, 0x13, 0x3a, 0x18, 0x09, 0xb6, 0x25, 0x52, 0x66, 0x05, 0x57, 0xa4, - 0x94, 0x1b, 0x79, 0x42, 0xed, 0x13, 0x32, 0xa0, 0x9a, 0xc0, 0x22, 0xb1, 0xe9, 0x14, 0xa6, 0xc6, - 0xa4, 0x47, 0x42, 0xa8, 0x7e, 0x7c, 0xa1, 0x58, 0x2a, 0x90, 0xc7, 0x9d, 0x1e, 0xfe, 0xb0, 0x9e, - 0x45, 0x08, 0xaa, 0xbc, 0xa9, 0x1d, 0xed, 0xef, 0x1c, 0x1e, 0x75, 0x0f, 0x58, 0x2c, 0x2f, 0x43, - 0xcd, 0x8f, 0xa5, 0x2f, 0xcc, 0xab, 0x87, 0xf0, 0x74, 0x02, 0x35, 0xfb, 0x8e, 0xf7, 0x4a, 0xf5, - 0x23, 0xa8, 0xc6, 0xab, 0x23, 0x6c, 0x51, 0x5c, 0x7b, 0x6a, 0x19, 0xdc, 0x47, 0x1e, 0x8b, 0x0e, - 0xba, 0x05, 0xf9, 0x13, 0x5b, 0x1c, 0xdc, 0xc5, 0xbb, 0xf7, 0xbe, 0x4d, 0x49, 0xa4, 0xba, 0x22, - 0xb4, 0xd5, 0xc7, 0x90, 0xe7, 0xe7, 0x90, 0x9d, 0x29, 0x5e, 0xe7, 0x90, 0x34, 0x8d, 0xb5, 0xd1, - 0x47, 0x00, 0x3a, 0xa5, 0xae, 0xd9, 0x9f, 0x86, 0x8e, 0x37, 0x16, 0x9f, 0xe3, 0x1d, 0x5f, 0xaf, - 0x75, 0x4d, 0x1e, 0xe8, 0x2b, 0xa1, 0x69, 0xe4, 0x50, 0x47, 0x1c, 0xaa, 0xfb, 0x50, 0x8d, 0xdb, - 0xfa, 0xc4, 0x42, 0x8c, 0x21, 0x4e, 0x2c, 0x04, 0x4f, 0x94, 0xc4, 0x22, 0xa0, 0x25, 0x59, 0x51, - 0xd3, 0xe2, 0x1d, 0xf5, 0x8f, 0x69, 0x28, 0xf6, 0x4e, 0xe5, 0x0a, 0x27, 0x94, 0x53, 0x42, 0xd3, - 0x4c, 0xb4, 0x78, 0x20, 0xea, 0x33, 0xd9, 0xa0, 0xea, 0xf3, 0x5e, 0xb0, 0x87, 0x73, 0xab, 0x5e, - 0xd5, 0xfc, 0xf2, 0x97, 0xdc, 0xb9, 0x37, 0xa0, 0x62, 0xbb, 0xe6, 0xd0, 0xb4, 0xf4, 0x71, 0x94, - 0x75, 0x96, 0x7d, 0x21, 0xa7, 0x6a, 0xef, 0x82, 0x12, 0x40, 0x35, 0x23, 0xc5, 0xba, 0x61, 0xb8, - 0xc4, 0xf3, 0xe4, 0x71, 0xf3, 0xbb, 0xbc, 0x84, 0x67, 0x3f, 0x92, 0x35, 0x8c, 0x2c, 0x16, 0x1d, - 0xd5, 0x80, 0xda, 0x0c, 0xce, 0xa3, 0x77, 0xa1, 0xe0, 0x4c, 0xfb, 0x9a, 0x1f, 0xc3, 0x99, 0x87, - 0x20, 0x9f, 0x6e, 0x4d, 0xfb, 0x63, 0x73, 0x70, 0x97, 0x9c, 0xf9, 0x23, 0x76, 0xa6, 0xfd, 0xbb, - 0x22, 0xd4, 0xe2, 0x57, 0x32, 0xd1, 0x5f, 0x39, 0x81, 0xa2, 0xbf, 0x73, 0xd0, 0x8f, 0x40, 0x09, - 0x52, 0x48, 0x50, 0xd9, 0x4d, 0xcc, 0x3d, 0xd2, 0x7d, 0x68, 0xc2, 0xb8, 0xbb, 0x67, 0x0e, 0x2d, - 0x62, 0x68, 0x21, 0x2d, 0xe7, 0xbf, 0x56, 0xc4, 0x35, 0xf1, 0x61, 0xcf, 0xe7, 0xe4, 0xea, 0xbf, - 0xd3, 0x50, 0xf4, 0x2b, 0x78, 0xe8, 0x8d, 0xc8, 0xe6, 0xac, 0x2e, 0x28, 0x3b, 0xf8, 0x8a, 0x61, - 0x15, 0x2e, 0x3e, 0xd6, 0xcc, 0xc5, 0xc7, 0x9a, 0x54, 0x4e, 0xf5, 0x0b, 0xdb, 0xb9, 0x0b, 0x17, - 0xb6, 0x5f, 0x03, 0x44, 0x6d, 0xaa, 0x8f, 0xb5, 0x13, 0x9b, 0x9a, 0xd6, 0x50, 0x13, 0xc1, 0x16, - 0x14, 0xa4, 0xce, 0xbf, 0xdc, 0xe7, 0x1f, 0x0e, 0x79, 0xdc, 0x7f, 0x95, 0x86, 0x62, 0x90, 0x4b, - 0x2e, 0x5a, 0x54, 0xbb, 0x0a, 0x6b, 0x12, 0x2e, 0x45, 0x55, 0x4d, 0xf6, 0x82, 0xfa, 0x6e, 0x2e, - 0x52, 0xdf, 0x6d, 0x42, 0x71, 0x42, 0xa8, 0xce, 0x51, 0x49, 0xec, 0xd1, 0xa0, 0x7f, 0xf3, 0x1d, - 0x28, 0x45, 0xea, 0x9b, 0xec, 0x78, 0xee, 0x77, 0x3e, 0xa8, 0xa7, 0x9a, 0x85, 0xcf, 0xbe, 0xb8, - 0x9e, 0xdd, 0x27, 0x8f, 0xd8, 0x9e, 0xc5, 0x9d, 0x76, 0xb7, 0xd3, 0xbe, 0x5b, 0x4f, 0x37, 0x4b, - 0x9f, 0x7d, 0x71, 0xbd, 0x80, 0x09, 0x2f, 0x79, 0xdc, 0xec, 0x42, 0x39, 0xba, 0x2a, 0x71, 0xc4, - 0x45, 0x50, 0xbd, 0x7d, 0xef, 0x70, 0x6f, 0xb7, 0xbd, 0xd3, 0xeb, 0x68, 0xf7, 0x0f, 0x7a, 0x9d, - 0x7a, 0x1a, 0x3d, 0x0d, 0x97, 0xf7, 0x76, 0x7f, 0xd2, 0xed, 0x69, 0xed, 0xbd, 0xdd, 0xce, 0x7e, - 0x4f, 0xdb, 0xe9, 0xf5, 0x76, 0xda, 0x77, 0xeb, 0x99, 0xed, 0xdf, 0x01, 0xd4, 0x76, 0x5a, 0xed, - 0x5d, 0x96, 0x2d, 0xcc, 0x81, 0xce, 0xaf, 0xad, 0x6d, 0xc8, 0xf1, 0x8b, 0xe9, 0xb9, 0x6f, 0xaa, - 0xcd, 0xf3, 0x8b, 0x61, 0xe8, 0x0e, 0xe4, 0xf9, 0x9d, 0x15, 0x9d, 0xff, 0xc8, 0xda, 0x5c, 0x52, - 0x1d, 0x63, 0x83, 0xe1, 0xc7, 0xe3, 0xdc, 0x57, 0xd7, 0xe6, 0xf9, 0xc5, 0x32, 0x84, 0x41, 0x09, - 0x39, 0xef, 0xf2, 0x57, 0xc8, 0xe6, 0x0a, 0x88, 0x84, 0xf6, 0xa0, 0xe0, 0x5f, 0x53, 0x96, 0xbd, - 0x8b, 0x36, 0x97, 0x56, 0xb3, 0x58, 0xb8, 0xc4, 0x75, 0xf2, 0xfc, 0x47, 0xde, 0xe6, 0x92, 0xd2, - 0x1c, 0xda, 0x85, 0x35, 0xc9, 0xe3, 0x96, 0xbc, 0x75, 0x36, 0x97, 0x55, 0xa7, 0x58, 0xd0, 0xc2, - 0x8b, 0xfa, 0xf2, 0xa7, 0xeb, 0xe6, 0x0a, 0x55, 0x47, 0x74, 0x0f, 0x20, 0x72, 0x79, 0x5c, 0xe1, - 0x4d, 0xba, 0xb9, 0x4a, 0x35, 0x11, 0x1d, 0x40, 0x31, 0xe0, 0xf2, 0x4b, 0x5f, 0x88, 0x9b, 0xcb, - 0xcb, 0x7a, 0xe8, 0x01, 0x54, 0xe2, 0x1c, 0x76, 0xb5, 0x77, 0xdf, 0xe6, 0x8a, 0xf5, 0x3a, 0xe6, - 0x3f, 0x4e, 0x68, 0x57, 0x7b, 0x07, 0x6e, 0xae, 0x58, 0xbe, 0x43, 0x9f, 0xc0, 0xa5, 0x79, 0xc2, - 0xb9, 0xfa, 0xb3, 0x70, 0xf3, 0x02, 0x05, 0x3d, 0x34, 0x01, 0xb4, 0x80, 0xa8, 0x5e, 0xe0, 0x95, - 0xb8, 0x79, 0x91, 0xfa, 0x1e, 0x32, 0xa0, 0x36, 0xcb, 0xfe, 0x56, 0x7d, 0x35, 0x6e, 0xae, 0x5c, - 0xeb, 0x6b, 0x75, 0xbe, 0xfc, 0x66, 0x3d, 0xfd, 0xd5, 0x37, 0xeb, 0xe9, 0x7f, 0x7e, 0xb3, 0x9e, - 0xfe, 0xfc, 0xc9, 0x7a, 0xea, 0xab, 0x27, 0xeb, 0xa9, 0xbf, 0x3d, 0x59, 0x4f, 0xfd, 0xfc, 0xd5, - 0xa1, 0x49, 0x47, 0xd3, 0xfe, 0xe6, 0xc0, 0x9e, 0x6c, 0x45, 0xff, 0xe4, 0xb2, 0xe8, 0x8f, 0x37, - 0xfd, 0x35, 0x9e, 0xba, 0xde, 0xfc, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1c, 0xcf, 0x70, 0x68, - 0x98, 0x23, 0x00, 0x00, + 0xf1, 0xc7, 0x93, 0x04, 0x1a, 0x4f, 0x8e, 0x64, 0x19, 0x5e, 0xcb, 0xa4, 0xbc, 0x2a, 0xdb, 0xb2, + 0x6c, 0x93, 0x7f, 0xd3, 0x25, 0xff, 0xed, 0x72, 0x1e, 0x26, 0x20, 0xc8, 0xa0, 0xc5, 0x90, 0xcc, + 0x10, 0x92, 0xcb, 0x49, 0xac, 0xf5, 0x02, 0x3b, 0x04, 0xd6, 0x02, 0x76, 0xd7, 0xbb, 0x03, 0x8a, + 0xd4, 0x31, 0x95, 0x5c, 0x5c, 0x39, 0xf8, 0x98, 0x8b, 0x3f, 0x42, 0x2a, 0xd7, 0x9c, 0x72, 0xca, + 0xc1, 0x87, 0x54, 0xca, 0xc7, 0x1c, 0x52, 0x4e, 0xca, 0xba, 0xe5, 0x0b, 0xa4, 0x52, 0xa9, 0x54, + 0xa5, 0xe6, 0xb1, 0x2f, 0x00, 0x4b, 0x80, 0x76, 0x6e, 0xb9, 0xcd, 0xf4, 0x76, 0xf7, 0xce, 0xf4, + 0xcc, 0xfe, 0xfa, 0x37, 0x3d, 0x0b, 0xcf, 0x52, 0x62, 0x19, 0xc4, 0x1d, 0x9b, 0x16, 0xdd, 0xd2, + 0x7b, 0x7d, 0x73, 0x8b, 0x9e, 0x39, 0xc4, 0xdb, 0x74, 0x5c, 0x9b, 0xda, 0xa8, 0x16, 0x3e, 0xdc, + 0x64, 0x0f, 0x95, 0xe7, 0x22, 0xda, 0x7d, 0xf7, 0xcc, 0xa1, 0xf6, 0x96, 0xe3, 0xda, 0xf6, 0xb1, + 0xd0, 0x57, 0xae, 0x46, 0x1e, 0x73, 0x3f, 0x51, 0x6f, 0xb1, 0xa7, 0xd2, 0xf8, 0x21, 0x39, 0xf3, + 0x9f, 0x3e, 0x37, 0x63, 0xeb, 0xe8, 0xae, 0x3e, 0xf6, 0x1f, 0x6f, 0x0c, 0x6c, 0x7b, 0x30, 0x22, + 0x5b, 0xbc, 0xd7, 0x9b, 0x1c, 0x6f, 0x51, 0x73, 0x4c, 0x3c, 0xaa, 0x8f, 0x1d, 0xa9, 0x70, 0x79, + 0x60, 0x0f, 0x6c, 0xde, 0xdc, 0x62, 0x2d, 0x21, 0x55, 0xff, 0x59, 0x80, 0x55, 0x4c, 0x3e, 0x9d, + 0x10, 0x8f, 0xa2, 0x6d, 0xc8, 0x91, 0xfe, 0xd0, 0x6e, 0xa4, 0xaf, 0xa5, 0x6f, 0x94, 0xb6, 0xaf, + 0x6e, 0x4e, 0x4d, 0x6e, 0x53, 0xea, 0xb5, 0xfb, 0x43, 0xbb, 0x93, 0xc2, 0x5c, 0x17, 0xdd, 0x82, + 0xfc, 0xf1, 0x68, 0xe2, 0x0d, 0x1b, 0x19, 0x6e, 0xf4, 0x5c, 0x92, 0xd1, 0x1d, 0xa6, 0xd4, 0x49, + 0x61, 0xa1, 0xcd, 0x5e, 0x65, 0x5a, 0xc7, 0x76, 0x23, 0x7b, 0xfe, 0xab, 0x76, 0xad, 0x63, 0xfe, + 0x2a, 0xa6, 0x8b, 0x9a, 0x00, 0xa6, 0x65, 0x52, 0xad, 0x3f, 0xd4, 0x4d, 0xab, 0x91, 0xe3, 0x96, + 0xcf, 0x27, 0x5b, 0x9a, 0xb4, 0xc5, 0x14, 0x3b, 0x29, 0x5c, 0x34, 0xfd, 0x0e, 0x1b, 0xee, 0xa7, + 0x13, 0xe2, 0x9e, 0x35, 0xf2, 0xe7, 0x0f, 0xf7, 0xc7, 0x4c, 0x89, 0x0d, 0x97, 0x6b, 0xa3, 0x36, + 0x94, 0x7a, 0x64, 0x60, 0x5a, 0x5a, 0x6f, 0x64, 0xf7, 0x1f, 0x36, 0x56, 0xb8, 0xb1, 0x9a, 0x64, + 0xdc, 0x64, 0xaa, 0x4d, 0xa6, 0xd9, 0x49, 0x61, 0xe8, 0x05, 0x3d, 0xf4, 0x3d, 0x28, 0xf4, 0x87, + 0xa4, 0xff, 0x50, 0xa3, 0xa7, 0x8d, 0x55, 0xee, 0x63, 0x23, 0xc9, 0x47, 0x8b, 0xe9, 0x75, 0x4f, + 0x3b, 0x29, 0xbc, 0xda, 0x17, 0x4d, 0x36, 0x7f, 0x83, 0x8c, 0xcc, 0x13, 0xe2, 0x32, 0xfb, 0xc2, + 0xf9, 0xf3, 0xbf, 0x2d, 0x34, 0xb9, 0x87, 0xa2, 0xe1, 0x77, 0xd0, 0x0f, 0xa1, 0x48, 0x2c, 0x43, + 0x4e, 0xa3, 0xc8, 0x5d, 0x5c, 0x4b, 0x5c, 0x67, 0xcb, 0xf0, 0x27, 0x51, 0x20, 0xb2, 0x8d, 0xde, + 0x82, 0x95, 0xbe, 0x3d, 0x1e, 0x9b, 0xb4, 0x01, 0xdc, 0x7a, 0x3d, 0x71, 0x02, 0x5c, 0xab, 0x93, + 0xc2, 0x52, 0x1f, 0xed, 0x43, 0x75, 0x64, 0x7a, 0x54, 0xf3, 0x2c, 0xdd, 0xf1, 0x86, 0x36, 0xf5, + 0x1a, 0x25, 0xee, 0xe1, 0x85, 0x24, 0x0f, 0x7b, 0xa6, 0x47, 0x8f, 0x7c, 0xe5, 0x4e, 0x0a, 0x57, + 0x46, 0x51, 0x01, 0xf3, 0x67, 0x1f, 0x1f, 0x13, 0x37, 0x70, 0xd8, 0x28, 0x9f, 0xef, 0xef, 0x80, + 0x69, 0xfb, 0xf6, 0xcc, 0x9f, 0x1d, 0x15, 0xa0, 0x9f, 0xc2, 0xa5, 0x91, 0xad, 0x1b, 0x81, 0x3b, + 0xad, 0x3f, 0x9c, 0x58, 0x0f, 0x1b, 0x15, 0xee, 0xf4, 0xe5, 0xc4, 0x41, 0xda, 0xba, 0xe1, 0xbb, + 0x68, 0x31, 0x83, 0x4e, 0x0a, 0xaf, 0x8d, 0xa6, 0x85, 0xe8, 0x01, 0x5c, 0xd6, 0x1d, 0x67, 0x74, + 0x36, 0xed, 0xbd, 0xca, 0xbd, 0xdf, 0x4c, 0xf2, 0xbe, 0xc3, 0x6c, 0xa6, 0xdd, 0x23, 0x7d, 0x46, + 0x8a, 0xba, 0x50, 0x77, 0x5c, 0xe2, 0xe8, 0x2e, 0xd1, 0x1c, 0xd7, 0x76, 0x6c, 0x4f, 0x1f, 0x35, + 0x6a, 0xdc, 0xf7, 0x4b, 0x49, 0xbe, 0x0f, 0x85, 0xfe, 0xa1, 0x54, 0xef, 0xa4, 0x70, 0xcd, 0x89, + 0x8b, 0x84, 0x57, 0xbb, 0x4f, 0x3c, 0x2f, 0xf4, 0x5a, 0x5f, 0xe4, 0x95, 0xeb, 0xc7, 0xbd, 0xc6, + 0x44, 0xcd, 0x55, 0xc8, 0x9f, 0xe8, 0xa3, 0x09, 0x51, 0x5f, 0x82, 0x52, 0x04, 0x52, 0x50, 0x03, + 0x56, 0xc7, 0xc4, 0xf3, 0xf4, 0x01, 0xe1, 0x08, 0x54, 0xc4, 0x7e, 0x57, 0xad, 0x42, 0x39, 0x0a, + 0x23, 0xea, 0xe7, 0xe9, 0xc0, 0x92, 0x21, 0x04, 0xb3, 0x3c, 0x21, 0xae, 0x67, 0xda, 0x96, 0x6f, + 0x29, 0xbb, 0xe8, 0x3a, 0x54, 0xf8, 0x5e, 0xd7, 0xfc, 0xe7, 0x0c, 0xa6, 0x72, 0xb8, 0xcc, 0x85, + 0xf7, 0xa5, 0xd2, 0x06, 0x94, 0x9c, 0x6d, 0x27, 0x50, 0xc9, 0x72, 0x15, 0x70, 0xb6, 0x1d, 0x5f, + 0xe1, 0x79, 0x28, 0xb3, 0x39, 0x06, 0x1a, 0x39, 0xfe, 0x92, 0x12, 0x93, 0x49, 0x15, 0xf5, 0x8f, + 0x19, 0xa8, 0x4f, 0x43, 0x0f, 0x7a, 0x0b, 0x72, 0x0c, 0x85, 0x25, 0xa0, 0x2a, 0x9b, 0x02, 0xa2, + 0x37, 0x7d, 0x88, 0xde, 0xec, 0xfa, 0x10, 0xdd, 0x2c, 0x7c, 0xf9, 0xf5, 0x46, 0xea, 0xf3, 0xbf, + 0x6e, 0xa4, 0x31, 0xb7, 0x40, 0xcf, 0x30, 0xa4, 0xd0, 0x4d, 0x4b, 0x33, 0x0d, 0x3e, 0xe4, 0x22, + 0x83, 0x01, 0xdd, 0xb4, 0x76, 0x0d, 0xb4, 0x07, 0xf5, 0xbe, 0x6d, 0x79, 0xc4, 0xf2, 0x26, 0x9e, + 0x26, 0x52, 0x80, 0x84, 0xd1, 0x18, 0x18, 0x88, 0xc4, 0xd2, 0xf2, 0x35, 0x0f, 0xb9, 0x22, 0xae, + 0xf5, 0xe3, 0x02, 0x74, 0x07, 0xe0, 0x44, 0x1f, 0x99, 0x86, 0x4e, 0x6d, 0xd7, 0x6b, 0xe4, 0xae, + 0x65, 0xe7, 0x22, 0xc2, 0x7d, 0x5f, 0xe5, 0x9e, 0x63, 0xe8, 0x94, 0x34, 0x73, 0x6c, 0xb8, 0x38, + 0x62, 0x89, 0x5e, 0x84, 0x9a, 0xee, 0x38, 0x9a, 0x47, 0x75, 0x4a, 0xb4, 0xde, 0x19, 0x25, 0x1e, + 0x87, 0xd8, 0x32, 0xae, 0xe8, 0x8e, 0x73, 0xc4, 0xa4, 0x4d, 0x26, 0x44, 0x2f, 0x40, 0x95, 0xa1, + 0xb1, 0xa9, 0x8f, 0xb4, 0x21, 0x31, 0x07, 0x43, 0xca, 0xc1, 0x34, 0x8b, 0x2b, 0x52, 0xda, 0xe1, + 0x42, 0xd5, 0x08, 0x56, 0x9c, 0x23, 0x31, 0x42, 0x90, 0x33, 0x74, 0xaa, 0xf3, 0x48, 0x96, 0x31, + 0x6f, 0x33, 0x99, 0xa3, 0xd3, 0xa1, 0x8c, 0x0f, 0x6f, 0xa3, 0x2b, 0xb0, 0x22, 0xdd, 0x66, 0xb9, + 0x5b, 0xd9, 0x43, 0x97, 0x21, 0xef, 0xb8, 0xf6, 0x09, 0xe1, 0x4b, 0x57, 0xc0, 0xa2, 0xa3, 0xfe, + 0x22, 0x03, 0x6b, 0x33, 0x98, 0xcd, 0xfc, 0x0e, 0x75, 0x6f, 0xe8, 0xbf, 0x8b, 0xb5, 0xd1, 0x9b, + 0xcc, 0xaf, 0x6e, 0x10, 0x57, 0xe6, 0xb9, 0xc6, 0x6c, 0xa8, 0x3b, 0xfc, 0xb9, 0x0c, 0x8d, 0xd4, + 0x46, 0x07, 0x50, 0x1f, 0xe9, 0x1e, 0xd5, 0x04, 0x06, 0x6a, 0x91, 0x9c, 0x37, 0x8b, 0xfc, 0x7b, + 0xba, 0x8f, 0x9a, 0x6c, 0x53, 0x4b, 0x47, 0xd5, 0x51, 0x4c, 0x8a, 0x30, 0x5c, 0xee, 0x9d, 0x3d, + 0xd6, 0x2d, 0x6a, 0x5a, 0x44, 0x9b, 0x59, 0xb9, 0x67, 0x66, 0x9c, 0xb6, 0x4f, 0x4c, 0x83, 0x58, + 0x7d, 0x7f, 0xc9, 0x2e, 0x05, 0xc6, 0xc1, 0x92, 0x7a, 0x2a, 0x86, 0x6a, 0x3c, 0xeb, 0xa0, 0x2a, + 0x64, 0xe8, 0xa9, 0x0c, 0x40, 0x86, 0x9e, 0xa2, 0xff, 0x83, 0x1c, 0x9b, 0x24, 0x9f, 0x7c, 0x75, + 0x4e, 0xba, 0x96, 0x76, 0xdd, 0x33, 0x87, 0x60, 0xae, 0xa9, 0xaa, 0xc1, 0xe7, 0x10, 0x64, 0xa2, + 0x69, 0xaf, 0xea, 0xcb, 0x50, 0x9b, 0x4a, 0x35, 0x91, 0xf5, 0x4b, 0x47, 0xd7, 0x4f, 0xad, 0x41, + 0x25, 0x96, 0x57, 0xd4, 0x2b, 0x70, 0x79, 0x5e, 0x9a, 0x50, 0x87, 0x81, 0x3c, 0x06, 0xf7, 0xe8, + 0x16, 0x14, 0x82, 0x3c, 0x21, 0x3e, 0xc7, 0xd9, 0x58, 0xf9, 0xca, 0x38, 0x50, 0x65, 0xdf, 0x21, + 0xdb, 0xd6, 0x7c, 0x3f, 0x64, 0xf8, 0xc0, 0x57, 0x75, 0xc7, 0xe9, 0xe8, 0xde, 0x50, 0xfd, 0x18, + 0x1a, 0x49, 0x39, 0x60, 0x6a, 0x1a, 0xb9, 0x60, 0x1b, 0x5e, 0x81, 0x95, 0x63, 0xdb, 0x1d, 0xeb, + 0x94, 0x3b, 0xab, 0x60, 0xd9, 0x63, 0xdb, 0x53, 0xe4, 0x83, 0x2c, 0x17, 0x8b, 0x8e, 0xaa, 0xc1, + 0x33, 0x89, 0x79, 0x80, 0x99, 0x98, 0x96, 0x41, 0x44, 0x3c, 0x2b, 0x58, 0x74, 0x42, 0x47, 0x62, + 0xb0, 0xa2, 0xc3, 0x5e, 0xeb, 0xf1, 0xb9, 0x72, 0xff, 0x45, 0x2c, 0x7b, 0xea, 0x23, 0xb8, 0x32, + 0x3f, 0x19, 0xa0, 0x5b, 0x00, 0x02, 0x37, 0x83, 0xaf, 0xae, 0xb4, 0x7d, 0x65, 0x76, 0xcf, 0xdf, + 0xd6, 0xa9, 0x8e, 0x8b, 0x5c, 0x93, 0x35, 0x19, 0x0a, 0x84, 0x66, 0x9a, 0x67, 0x3e, 0x16, 0x5b, + 0x26, 0x8b, 0x2b, 0x81, 0xce, 0x91, 0xf9, 0x98, 0xa8, 0xbd, 0xc8, 0x8b, 0x63, 0xc9, 0x21, 0xf2, + 0xa1, 0xa5, 0x2f, 0xf4, 0xa1, 0xd5, 0x21, 0x4b, 0x4f, 0xbd, 0x46, 0xe6, 0x5a, 0xf6, 0x46, 0x19, + 0xb3, 0xa6, 0xfa, 0xa7, 0x22, 0x14, 0x30, 0xf1, 0x1c, 0x06, 0x78, 0xa8, 0x09, 0x45, 0x72, 0xda, + 0x27, 0x0e, 0xf5, 0x73, 0xc4, 0x7c, 0xfa, 0x26, 0xb4, 0xdb, 0xbe, 0x26, 0xe3, 0x4e, 0x81, 0x19, + 0x7a, 0x43, 0xd2, 0xe3, 0x64, 0xa6, 0x2b, 0xcd, 0xa3, 0xfc, 0xf8, 0x4d, 0x9f, 0x1f, 0x67, 0x13, + 0xe9, 0x92, 0xb0, 0x9a, 0x22, 0xc8, 0x6f, 0x48, 0x82, 0x9c, 0x5b, 0xf0, 0xb2, 0x18, 0x43, 0x6e, + 0xc5, 0x18, 0x72, 0x7e, 0xc1, 0x34, 0x13, 0x28, 0xf2, 0x9b, 0x3e, 0x45, 0x5e, 0x59, 0x30, 0xe2, + 0x29, 0x8e, 0x7c, 0x27, 0xce, 0x91, 0x05, 0xbf, 0xbd, 0x9e, 0x68, 0x9d, 0x48, 0x92, 0xbf, 0x1f, + 0x21, 0xc9, 0x85, 0x44, 0x86, 0x2a, 0x9c, 0xcc, 0x61, 0xc9, 0xad, 0x18, 0x4b, 0x2e, 0x2e, 0x88, + 0x41, 0x02, 0x4d, 0x7e, 0x37, 0x4a, 0x93, 0x21, 0x91, 0x69, 0xcb, 0xf5, 0x9e, 0xc7, 0x93, 0xdf, + 0x0e, 0x78, 0x72, 0x29, 0x91, 0xe8, 0xcb, 0x39, 0x4c, 0x13, 0xe5, 0x83, 0x19, 0xa2, 0x2c, 0x88, + 0xed, 0x8b, 0x89, 0x2e, 0x16, 0x30, 0xe5, 0x83, 0x19, 0xa6, 0x5c, 0x59, 0xe0, 0x70, 0x01, 0x55, + 0xfe, 0xd9, 0x7c, 0xaa, 0x9c, 0x4c, 0x66, 0xe5, 0x30, 0x97, 0xe3, 0xca, 0x5a, 0x02, 0x57, 0x16, + 0x7c, 0xf6, 0x95, 0x44, 0xf7, 0x4b, 0x93, 0xe5, 0x7b, 0x73, 0xc8, 0xb2, 0xa0, 0xb5, 0x37, 0x12, + 0x9d, 0x2f, 0xc1, 0x96, 0xef, 0xcd, 0x61, 0xcb, 0x6b, 0x0b, 0xdd, 0x2e, 0x4f, 0x97, 0x5f, 0x66, + 0x64, 0x65, 0x0a, 0xa1, 0x18, 0xe0, 0x13, 0xd7, 0xb5, 0x5d, 0x49, 0x7c, 0x45, 0x47, 0xbd, 0xc1, + 0xe8, 0x53, 0x88, 0x46, 0xe7, 0x50, 0x6b, 0x9e, 0x58, 0x23, 0x08, 0xa4, 0xfe, 0x2e, 0x1d, 0xda, + 0x72, 0xc6, 0x11, 0xa5, 0x5e, 0x45, 0x49, 0xbd, 0x22, 0x84, 0x3b, 0x13, 0x27, 0xdc, 0x1b, 0x50, + 0x62, 0x09, 0x73, 0x8a, 0x4b, 0xeb, 0x4e, 0xc0, 0xa5, 0x6f, 0xc2, 0x1a, 0x67, 0x44, 0x22, 0x4f, + 0xc8, 0x2c, 0x99, 0xe3, 0x49, 0xa2, 0xc6, 0x1e, 0x88, 0x4f, 0x49, 0xa4, 0xcb, 0xd7, 0xe0, 0x52, + 0x44, 0x37, 0x48, 0xc4, 0x82, 0x58, 0xd6, 0x03, 0xed, 0x1d, 0x99, 0x91, 0xff, 0x90, 0x0e, 0x23, + 0x14, 0x92, 0xf0, 0x79, 0x7c, 0x39, 0xfd, 0x5f, 0xe2, 0xcb, 0x99, 0x6f, 0xcd, 0x97, 0xa3, 0xc4, + 0x22, 0x1b, 0x27, 0x16, 0xff, 0x48, 0x87, 0x6b, 0x12, 0xb0, 0xdf, 0xbe, 0x6d, 0x10, 0x99, 0xea, + 0x79, 0x9b, 0x25, 0xbc, 0x91, 0x3d, 0x90, 0x09, 0x9d, 0x35, 0x99, 0x56, 0x90, 0x32, 0x8a, 0x32, + 0x23, 0x04, 0x2c, 0x21, 0xcf, 0x23, 0x2c, 0x59, 0x42, 0x1d, 0xb2, 0x0f, 0x89, 0x00, 0xf8, 0x32, + 0x66, 0x4d, 0xa6, 0xc7, 0x37, 0x19, 0x87, 0xed, 0x32, 0x16, 0x1d, 0xf4, 0x16, 0x14, 0x79, 0xf5, + 0x4a, 0xb3, 0x1d, 0x4f, 0x62, 0xf1, 0xb3, 0xd1, 0xb9, 0x8a, 0x22, 0xd5, 0xe6, 0x21, 0xd3, 0x39, + 0x70, 0x3c, 0x5c, 0x70, 0x64, 0x2b, 0x42, 0x80, 0x8a, 0x31, 0x1e, 0x7e, 0x15, 0x8a, 0x6c, 0xf4, + 0x9e, 0xa3, 0xf7, 0x09, 0x07, 0xd6, 0x22, 0x0e, 0x05, 0xea, 0x03, 0x40, 0xb3, 0xe9, 0x01, 0x75, + 0x60, 0x85, 0x9c, 0x10, 0x8b, 0xb2, 0x65, 0xcb, 0x4e, 0xf3, 0x10, 0x49, 0x72, 0x89, 0x45, 0x9b, + 0x0d, 0x16, 0xe4, 0xbf, 0x7f, 0xbd, 0x51, 0x17, 0xda, 0xaf, 0xda, 0x63, 0x93, 0x92, 0xb1, 0x43, + 0xcf, 0xb0, 0xb4, 0x57, 0xff, 0x92, 0x61, 0x8c, 0x33, 0x96, 0x3a, 0xe6, 0xc6, 0xd6, 0xdf, 0xf2, + 0x99, 0xc8, 0x69, 0x63, 0xb9, 0x78, 0xaf, 0x03, 0x0c, 0x74, 0x4f, 0x7b, 0xa4, 0x5b, 0x94, 0x18, + 0x32, 0xe8, 0x11, 0x09, 0x52, 0xa0, 0xc0, 0x7a, 0x13, 0x8f, 0x18, 0xf2, 0xe0, 0x13, 0xf4, 0x23, + 0xf3, 0x5c, 0xfd, 0x6e, 0xf3, 0x8c, 0x47, 0xb9, 0x30, 0x15, 0xe5, 0x08, 0x1b, 0x2c, 0x46, 0xd9, + 0x20, 0x1b, 0x9b, 0xe3, 0x9a, 0xb6, 0x6b, 0xd2, 0x33, 0xbe, 0x34, 0x59, 0x1c, 0xf4, 0xd9, 0x39, + 0x7a, 0x4c, 0xc6, 0x8e, 0x6d, 0x8f, 0x34, 0x01, 0x37, 0x25, 0x6e, 0x5a, 0x96, 0xc2, 0x36, 0x47, + 0x9d, 0x5f, 0x66, 0xc2, 0xef, 0x2f, 0x64, 0xfd, 0xff, 0x73, 0x01, 0x56, 0x7f, 0xc5, 0x6b, 0x01, + 0x71, 0x72, 0x80, 0x8e, 0x60, 0x2d, 0xf8, 0xfc, 0xb5, 0x09, 0x87, 0x05, 0x7f, 0x43, 0x2f, 0x8b, + 0x1f, 0xf5, 0x93, 0xb8, 0xd8, 0x43, 0x1f, 0xc2, 0xd3, 0x53, 0xd8, 0x16, 0xb8, 0xce, 0x2c, 0x0b, + 0x71, 0x4f, 0xc5, 0x21, 0xce, 0x77, 0x1d, 0x06, 0x2b, 0xfb, 0x1d, 0xbf, 0xba, 0x5d, 0x76, 0xbc, + 0x8c, 0x72, 0x9d, 0xb9, 0xcb, 0x7f, 0x1d, 0x2a, 0x2e, 0xa1, 0xba, 0x69, 0x69, 0xb1, 0x03, 0x7c, + 0x59, 0x08, 0x65, 0x59, 0xe0, 0x10, 0x9e, 0x9a, 0xcb, 0x79, 0xd0, 0xff, 0x43, 0x31, 0xa4, 0x4b, + 0xe9, 0x84, 0xb3, 0x70, 0x70, 0xbe, 0x0b, 0x75, 0xd5, 0xdf, 0xa7, 0x43, 0x97, 0xf1, 0x13, 0x63, + 0x1b, 0x56, 0x5c, 0xe2, 0x4d, 0x46, 0xe2, 0x0c, 0x57, 0xdd, 0x7e, 0x6d, 0x39, 0xb6, 0xc4, 0xa4, + 0x93, 0x11, 0xc5, 0xd2, 0x58, 0x7d, 0x00, 0x2b, 0x42, 0x82, 0x4a, 0xb0, 0x7a, 0x6f, 0xff, 0xee, + 0xfe, 0xc1, 0x07, 0xfb, 0xf5, 0x14, 0x02, 0x58, 0xd9, 0x69, 0xb5, 0xda, 0x87, 0xdd, 0x7a, 0x1a, + 0x15, 0x21, 0xbf, 0xd3, 0x3c, 0xc0, 0xdd, 0x7a, 0x86, 0x89, 0x71, 0xfb, 0xfd, 0x76, 0xab, 0x5b, + 0xcf, 0xa2, 0x35, 0xa8, 0x88, 0xb6, 0x76, 0xe7, 0x00, 0xff, 0x68, 0xa7, 0x5b, 0xcf, 0x45, 0x44, + 0x47, 0xed, 0xfd, 0xdb, 0x6d, 0x5c, 0xcf, 0xab, 0xaf, 0xb3, 0x43, 0x62, 0x02, 0xbf, 0x0a, 0x8f, + 0x83, 0xe9, 0xc8, 0x71, 0x50, 0xfd, 0x75, 0x06, 0x94, 0x64, 0xd2, 0x84, 0xde, 0x9f, 0x9a, 0xf8, + 0xf6, 0x05, 0x18, 0xd7, 0xd4, 0xec, 0xd1, 0x0b, 0x50, 0x75, 0xc9, 0x31, 0xa1, 0xfd, 0xa1, 0x20, + 0x71, 0x22, 0x65, 0x56, 0x70, 0x45, 0x4a, 0xb9, 0x91, 0x27, 0xd4, 0x3e, 0x21, 0x7d, 0xaa, 0x09, + 0x2c, 0x12, 0x9b, 0xae, 0xc8, 0xd4, 0x98, 0xf4, 0x48, 0x08, 0xd5, 0x8f, 0x2f, 0x14, 0xcb, 0x22, + 0xe4, 0x71, 0xbb, 0x8b, 0x3f, 0xac, 0x67, 0x11, 0x82, 0x2a, 0x6f, 0x6a, 0x47, 0xfb, 0x3b, 0x87, + 0x47, 0x9d, 0x03, 0x16, 0xcb, 0x4b, 0x50, 0xf3, 0x63, 0xe9, 0x0b, 0xf3, 0xea, 0x21, 0x3c, 0x9d, + 0xc0, 0xf8, 0xbe, 0xe5, 0x91, 0x58, 0xfd, 0x4d, 0x3a, 0xea, 0x32, 0x7e, 0xd8, 0x7d, 0x6f, 0x2a, + 0xd2, 0x5b, 0xcb, 0xf2, 0xc4, 0xe9, 0x30, 0x2b, 0x50, 0x20, 0xb2, 0xd0, 0x23, 0x8f, 0xc0, 0x41, + 0x5f, 0x7d, 0x6d, 0x71, 0xd0, 0xc2, 0x5d, 0x97, 0x51, 0x3f, 0x82, 0x6a, 0xbc, 0x10, 0xc5, 0x36, + 0x91, 0x6b, 0x4f, 0x2c, 0x83, 0x0f, 0x32, 0x8f, 0x45, 0x07, 0xdd, 0x82, 0xfc, 0x89, 0x2d, 0x80, + 0x66, 0xfe, 0xd7, 0x76, 0xdf, 0xa6, 0x24, 0x52, 0xc8, 0x12, 0xda, 0xea, 0x63, 0xc8, 0x73, 0xdc, + 0x60, 0x18, 0xc0, 0x4b, 0x4a, 0x92, 0x56, 0xb2, 0x36, 0xfa, 0x08, 0x40, 0xa7, 0xd4, 0x35, 0x7b, + 0x93, 0xd0, 0xf1, 0xc6, 0x7c, 0xdc, 0xd9, 0xf1, 0xf5, 0x9a, 0x57, 0x25, 0x00, 0x5d, 0x0e, 0x4d, + 0x23, 0x20, 0x14, 0x71, 0xa8, 0xee, 0x43, 0x35, 0x6e, 0xeb, 0x13, 0x21, 0x31, 0x86, 0x38, 0x11, + 0x12, 0xbc, 0x56, 0x12, 0xa1, 0x80, 0x46, 0x65, 0x45, 0xf9, 0x90, 0x77, 0xd4, 0xdf, 0xa6, 0xa1, + 0xd0, 0x3d, 0x95, 0xc1, 0x4d, 0xa8, 0x5c, 0x85, 0xa6, 0x99, 0x68, 0x9d, 0x46, 0x94, 0xc2, 0xb2, + 0x41, 0x81, 0xed, 0xdd, 0x60, 0x27, 0xe4, 0x96, 0x3d, 0xb1, 0xfa, 0x05, 0x10, 0xb9, 0x05, 0xae, + 0x43, 0xc5, 0x76, 0xcd, 0x81, 0x69, 0xe9, 0xa3, 0x28, 0x4b, 0x2e, 0xfb, 0x42, 0x4e, 0x2d, 0xdf, + 0x81, 0x62, 0x90, 0x5a, 0x18, 0x89, 0xd7, 0x0d, 0xc3, 0x25, 0x9e, 0x27, 0xe1, 0xc1, 0xef, 0xf2, + 0x6a, 0xa9, 0xfd, 0x48, 0x96, 0x8b, 0xb2, 0x58, 0x74, 0x54, 0x03, 0x6a, 0x53, 0x79, 0x09, 0xbd, + 0x03, 0xab, 0xce, 0xa4, 0xa7, 0xf9, 0x31, 0x9c, 0xba, 0xc9, 0xf3, 0xe9, 0xe1, 0xa4, 0x37, 0x32, + 0xfb, 0x77, 0xc9, 0x99, 0x3f, 0x62, 0x67, 0xd2, 0xbb, 0x2b, 0x42, 0x2d, 0xde, 0x92, 0x89, 0xbe, + 0xe5, 0x04, 0x0a, 0xfe, 0xce, 0x41, 0x3f, 0x80, 0x62, 0x90, 0xf2, 0x82, 0x22, 0x7a, 0x62, 0xae, + 0x94, 0xee, 0x43, 0x13, 0x76, 0xd6, 0xf0, 0xcc, 0x81, 0x45, 0x0c, 0x2d, 0x3c, 0x46, 0xf0, 0xb7, + 0x15, 0x70, 0x4d, 0x3c, 0xd8, 0xf3, 0xcf, 0x10, 0xea, 0xbf, 0xd3, 0x50, 0xf0, 0x8b, 0xa5, 0xe8, + 0xf5, 0xc8, 0xe6, 0xac, 0xce, 0xa9, 0xbe, 0xf8, 0x8a, 0x61, 0xc1, 0x33, 0x3e, 0xd6, 0xcc, 0xc5, + 0xc7, 0x9a, 0x54, 0xb9, 0xf6, 0xef, 0x10, 0x72, 0x17, 0xbe, 0x43, 0x78, 0x15, 0x10, 0xb5, 0xa9, + 0x3e, 0xd2, 0x4e, 0x6c, 0x6a, 0x5a, 0x03, 0x4d, 0x04, 0x5b, 0x50, 0xa6, 0x3a, 0x7f, 0x72, 0x9f, + 0x3f, 0x38, 0xe4, 0x71, 0xff, 0x79, 0x1a, 0x0a, 0x41, 0xee, 0xbb, 0x68, 0xfd, 0xf2, 0x0a, 0xac, + 0x48, 0x78, 0x17, 0x05, 0x4c, 0xd9, 0x0b, 0x4a, 0xe9, 0xb9, 0x48, 0x29, 0x5d, 0x81, 0xc2, 0x98, + 0x50, 0x9d, 0xa3, 0xa8, 0xd8, 0xa3, 0x41, 0xff, 0xe6, 0xdb, 0x50, 0x8a, 0x94, 0x92, 0xd9, 0xe7, + 0xb9, 0xdf, 0xfe, 0xa0, 0x9e, 0x52, 0x56, 0x3f, 0xfb, 0xe2, 0x5a, 0x76, 0x9f, 0x3c, 0x62, 0x7b, + 0x16, 0xb7, 0x5b, 0x9d, 0x76, 0xeb, 0x6e, 0x3d, 0xad, 0x94, 0x3e, 0xfb, 0xe2, 0xda, 0x2a, 0x26, + 0xbc, 0xf2, 0x73, 0xb3, 0x03, 0xe5, 0xe8, 0xaa, 0xc4, 0xc1, 0x0e, 0x41, 0xf5, 0xf6, 0xbd, 0xc3, + 0xbd, 0xdd, 0xd6, 0x4e, 0xb7, 0xad, 0xdd, 0x3f, 0xe8, 0xb6, 0xeb, 0x69, 0xf4, 0x34, 0x5c, 0xda, + 0xdb, 0x7d, 0xaf, 0xd3, 0xd5, 0x5a, 0x7b, 0xbb, 0xed, 0xfd, 0xae, 0xb6, 0xd3, 0xed, 0xee, 0xb4, + 0xee, 0xd6, 0x33, 0xdb, 0xff, 0x02, 0xa8, 0xed, 0x34, 0x5b, 0xbb, 0x2c, 0xbb, 0x99, 0x7d, 0x9d, + 0x1f, 0xb3, 0x5b, 0x90, 0xe3, 0x07, 0xe9, 0x73, 0x2f, 0xc5, 0x95, 0xf3, 0x6b, 0x82, 0xe8, 0x0e, + 0xe4, 0xf9, 0x19, 0x1b, 0x9d, 0x7f, 0x4b, 0xae, 0x2c, 0x28, 0x12, 0xb2, 0xc1, 0xf0, 0xcf, 0xe3, + 0xdc, 0x6b, 0x73, 0xe5, 0xfc, 0x9a, 0x21, 0xc2, 0x50, 0x0c, 0x39, 0xfa, 0xe2, 0x6b, 0x64, 0x65, + 0x09, 0x44, 0x42, 0x7b, 0xb0, 0xea, 0x1f, 0xab, 0x16, 0x5d, 0x6c, 0x2b, 0x0b, 0x8b, 0x7a, 0x2c, + 0x5c, 0xe2, 0xf8, 0x7b, 0xfe, 0x2d, 0xbd, 0xb2, 0xa0, 0x42, 0x89, 0x76, 0x61, 0x45, 0xf2, 0xce, + 0x05, 0x97, 0xd5, 0xca, 0xa2, 0x22, 0x1d, 0x0b, 0x5a, 0x58, 0x58, 0x58, 0xfc, 0xef, 0x81, 0xb2, + 0x44, 0xf1, 0x15, 0xdd, 0x03, 0x88, 0x1c, 0x76, 0x97, 0xf8, 0xa9, 0x40, 0x59, 0xa6, 0xa8, 0x8a, + 0x0e, 0xa0, 0x10, 0x9c, 0x3d, 0x16, 0x5e, 0xf1, 0x2b, 0x8b, 0xab, 0x9b, 0xe8, 0x01, 0x54, 0xe2, + 0x9c, 0x7b, 0xb9, 0x8b, 0x7b, 0x65, 0xc9, 0xb2, 0x25, 0xf3, 0x1f, 0x27, 0xe0, 0xcb, 0x5d, 0xe4, + 0x2b, 0x4b, 0x56, 0x31, 0xd1, 0x27, 0xb0, 0x36, 0x4b, 0x90, 0x97, 0xbf, 0xd7, 0x57, 0x2e, 0x50, + 0xd7, 0x44, 0x63, 0x40, 0x73, 0x88, 0xf5, 0x05, 0xae, 0xf9, 0x95, 0x8b, 0x94, 0x39, 0x91, 0x01, + 0xb5, 0x69, 0xb6, 0xba, 0xec, 0xb5, 0xbf, 0xb2, 0x74, 0xc9, 0x53, 0xbc, 0x25, 0x4e, 0x60, 0x97, + 0xfd, 0x0d, 0x40, 0x59, 0xba, 0x02, 0xda, 0x6c, 0x7f, 0xf9, 0xcd, 0x7a, 0xfa, 0xab, 0x6f, 0xd6, + 0xd3, 0x7f, 0xfb, 0x66, 0x3d, 0xfd, 0xf9, 0x93, 0xf5, 0xd4, 0x57, 0x4f, 0xd6, 0x53, 0x7f, 0x7e, + 0xb2, 0x9e, 0xfa, 0xc9, 0x2b, 0x03, 0x93, 0x0e, 0x27, 0xbd, 0xcd, 0xbe, 0x3d, 0xde, 0x8a, 0xfe, + 0x0b, 0x35, 0xef, 0xff, 0xac, 0xde, 0x0a, 0x4f, 0x90, 0x6f, 0xfc, 0x27, 0x00, 0x00, 0xff, 0xff, + 0x23, 0x35, 0x8c, 0x56, 0xbf, 0x25, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3303,6 +3470,7 @@ type ABCIApplicationClient interface { LoadSnapshotChunk(ctx context.Context, in *RequestLoadSnapshotChunk, opts ...grpc.CallOption) (*ResponseLoadSnapshotChunk, error) ApplySnapshotChunk(ctx context.Context, in *RequestApplySnapshotChunk, opts ...grpc.CallOption) (*ResponseApplySnapshotChunk, error) PrepareProposal(ctx context.Context, in *RequestPrepareProposal, opts ...grpc.CallOption) (*ResponsePrepareProposal, error) + ProcessProposal(ctx context.Context, in *RequestProcessProposal, opts ...grpc.CallOption) (*ResponseProcessProposal, error) } type aBCIApplicationClient struct { @@ -3448,6 +3616,15 @@ func (c *aBCIApplicationClient) PrepareProposal(ctx context.Context, in *Request return out, nil } +func (c *aBCIApplicationClient) ProcessProposal(ctx context.Context, in *RequestProcessProposal, opts ...grpc.CallOption) (*ResponseProcessProposal, error) { + out := new(ResponseProcessProposal) + err := c.cc.Invoke(ctx, "/tendermint.abci.ABCIApplication/ProcessProposal", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ABCIApplicationServer is the server API for ABCIApplication service. type ABCIApplicationServer interface { Echo(context.Context, *RequestEcho) (*ResponseEcho, error) @@ -3465,6 +3642,7 @@ type ABCIApplicationServer interface { LoadSnapshotChunk(context.Context, *RequestLoadSnapshotChunk) (*ResponseLoadSnapshotChunk, error) ApplySnapshotChunk(context.Context, *RequestApplySnapshotChunk) (*ResponseApplySnapshotChunk, error) PrepareProposal(context.Context, *RequestPrepareProposal) (*ResponsePrepareProposal, error) + ProcessProposal(context.Context, *RequestProcessProposal) (*ResponseProcessProposal, error) } // UnimplementedABCIApplicationServer can be embedded to have forward compatible implementations. @@ -3516,6 +3694,9 @@ func (*UnimplementedABCIApplicationServer) ApplySnapshotChunk(ctx context.Contex func (*UnimplementedABCIApplicationServer) PrepareProposal(ctx context.Context, req *RequestPrepareProposal) (*ResponsePrepareProposal, error) { return nil, status.Errorf(codes.Unimplemented, "method PrepareProposal not implemented") } +func (*UnimplementedABCIApplicationServer) ProcessProposal(ctx context.Context, req *RequestProcessProposal) (*ResponseProcessProposal, error) { + return nil, status.Errorf(codes.Unimplemented, "method ProcessProposal not implemented") +} func RegisterABCIApplicationServer(s *grpc.Server, srv ABCIApplicationServer) { s.RegisterService(&_ABCIApplication_serviceDesc, srv) @@ -3791,6 +3972,24 @@ func _ABCIApplication_PrepareProposal_Handler(srv interface{}, ctx context.Conte return interceptor(ctx, in, info, handler) } +func _ABCIApplication_ProcessProposal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RequestProcessProposal) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ABCIApplicationServer).ProcessProposal(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tendermint.abci.ABCIApplication/ProcessProposal", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ABCIApplicationServer).ProcessProposal(ctx, req.(*RequestProcessProposal)) + } + return interceptor(ctx, in, info, handler) +} + var _ABCIApplication_serviceDesc = grpc.ServiceDesc{ ServiceName: "tendermint.abci.ABCIApplication", HandlerType: (*ABCIApplicationServer)(nil), @@ -3855,6 +4054,10 @@ var _ABCIApplication_serviceDesc = grpc.ServiceDesc{ MethodName: "PrepareProposal", Handler: _ABCIApplication_PrepareProposal_Handler, }, + { + MethodName: "ProcessProposal", + Handler: _ABCIApplication_ProcessProposal_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "tendermint/abci/types.proto", @@ -4207,6 +4410,29 @@ func (m *Request_PrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) } return len(dAtA) - i, nil } +func (m *Request_ProcessProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Request_ProcessProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.ProcessProposal != nil { + { + size, err := m.ProcessProposal.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } + return len(dAtA) - i, nil +} func (m *RequestEcho) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4372,12 +4598,12 @@ func (m *RequestInitChain) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - n17, err17 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) - if err17 != nil { - return 0, err17 + n18, err18 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) + if err18 != nil { + return 0, err18 } - i -= n17 - i = encodeVarintTypes(dAtA, i, uint64(n17)) + i -= n18 + i = encodeVarintTypes(dAtA, i, uint64(n18)) i-- dAtA[i] = 0xa return len(dAtA) - i, nil @@ -4800,6 +5026,48 @@ func (m *RequestPrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *RequestProcessProposal) 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 *RequestProcessProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RequestProcessProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Txs) > 0 { + for iNdEx := len(m.Txs) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Txs[iNdEx]) + copy(dAtA[i:], m.Txs[iNdEx]) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Txs[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Header.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *Response) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -5170,6 +5438,29 @@ func (m *Response_PrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error } return len(dAtA) - i, nil } +func (m *Response_ProcessProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Response_ProcessProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.ProcessProposal != nil { + { + size, err := m.ProcessProposal.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x8a + } + return len(dAtA) - i, nil +} func (m *ResponseException) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -5887,20 +6178,20 @@ func (m *ResponseApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, err } } if len(m.RefetchChunks) > 0 { - dAtA42 := make([]byte, len(m.RefetchChunks)*10) - var j41 int + dAtA45 := make([]byte, len(m.RefetchChunks)*10) + var j44 int for _, num := range m.RefetchChunks { for num >= 1<<7 { - dAtA42[j41] = uint8(uint64(num)&0x7f | 0x80) + dAtA45[j44] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j41++ + j44++ } - dAtA42[j41] = uint8(num) - j41++ + dAtA45[j44] = uint8(num) + j44++ } - i -= j41 - copy(dAtA[i:], dAtA42[:j41]) - i = encodeVarintTypes(dAtA, i, uint64(j41)) + i -= j44 + copy(dAtA[i:], dAtA45[:j44]) + i = encodeVarintTypes(dAtA, i, uint64(j44)) i-- dAtA[i] = 0x12 } @@ -5947,7 +6238,7 @@ func (m *ResponsePrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } -func (m *LastCommitInfo) Marshal() (dAtA []byte, err error) { +func (m *ResponseProcessProposal) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -5957,39 +6248,34 @@ func (m *LastCommitInfo) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *LastCommitInfo) MarshalTo(dAtA []byte) (int, error) { +func (m *ResponseProcessProposal) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *LastCommitInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *ResponseProcessProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Votes) > 0 { - for iNdEx := len(m.Votes) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Votes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } + if len(m.Evidence) > 0 { + for iNdEx := len(m.Evidence) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Evidence[iNdEx]) + copy(dAtA[i:], m.Evidence[iNdEx]) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Evidence[iNdEx]))) i-- dAtA[i] = 0x12 } } - if m.Round != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.Round)) + if m.Result != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Result)) i-- dAtA[i] = 0x8 } return len(dAtA) - i, nil } -func (m *Event) Marshal() (dAtA []byte, err error) { +func (m *LastCommitInfo) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -5999,17 +6285,59 @@ func (m *Event) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *Event) MarshalTo(dAtA []byte) (int, error) { +func (m *LastCommitInfo) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Event) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *LastCommitInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Attributes) > 0 { + if len(m.Votes) > 0 { + for iNdEx := len(m.Votes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Votes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Round != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Round)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Event) 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 *Event) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Event) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Attributes) > 0 { for iNdEx := len(m.Attributes) - 1; iNdEx >= 0; iNdEx-- { { size, err := m.Attributes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) @@ -6278,12 +6606,12 @@ func (m *Evidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x28 } - n47, err47 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) - if err47 != nil { - return 0, err47 + n50, err50 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) + if err50 != nil { + return 0, err50 } - i -= n47 - i = encodeVarintTypes(dAtA, i, uint64(n47)) + i -= n50 + i = encodeVarintTypes(dAtA, i, uint64(n50)) i-- dAtA[i] = 0x22 if m.Height != 0 { @@ -6564,6 +6892,18 @@ func (m *Request_PrepareProposal) Size() (n int) { } return n } +func (m *Request_ProcessProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ProcessProposal != nil { + l = m.ProcessProposal.Size() + n += 2 + l + sovTypes(uint64(l)) + } + return n +} func (m *RequestEcho) Size() (n int) { if m == nil { return 0 @@ -6817,6 +7157,23 @@ func (m *RequestPrepareProposal) Size() (n int) { return n } +func (m *RequestProcessProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Header.Size() + n += 1 + l + sovTypes(uint64(l)) + if len(m.Txs) > 0 { + for _, b := range m.Txs { + l = len(b) + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + func (m *Response) Size() (n int) { if m == nil { return 0 @@ -7021,6 +7378,18 @@ func (m *Response_PrepareProposal) Size() (n int) { } return n } +func (m *Response_ProcessProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ProcessProposal != nil { + l = m.ProcessProposal.Size() + n += 2 + l + sovTypes(uint64(l)) + } + return n +} func (m *ResponseException) Size() (n int) { if m == nil { return 0 @@ -7373,6 +7742,24 @@ func (m *ResponsePrepareProposal) Size() (n int) { return n } +func (m *ResponseProcessProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Result != 0 { + n += 1 + sovTypes(uint64(m.Result)) + } + if len(m.Evidence) > 0 { + for _, b := range m.Evidence { + l = len(b) + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + func (m *LastCommitInfo) Size() (n int) { if m == nil { return 0 @@ -8107,6 +8494,41 @@ func (m *Request) Unmarshal(dAtA []byte) error { } m.Value = &Request_PrepareProposal{v} iNdEx = postIndex + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProcessProposal", 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 + } + v := &RequestProcessProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Value = &Request_ProcessProposal{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -9812,6 +10234,121 @@ func (m *RequestPrepareProposal) Unmarshal(dAtA []byte) error { } return nil } +func (m *RequestProcessProposal) 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: RequestProcessProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RequestProcessProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Header", 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 err := m.Header.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Txs", 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.Txs = append(m.Txs, make([]byte, postIndex-iNdEx)) + copy(m.Txs[len(m.Txs)-1], dAtA[iNdEx:postIndex]) + 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 *Response) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -10401,6 +10938,41 @@ func (m *Response) Unmarshal(dAtA []byte) error { } m.Value = &Response_PrepareProposal{v} iNdEx = postIndex + case 17: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProcessProposal", 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 + } + v := &ResponseProcessProposal{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Value = &Response_ProcessProposal{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -12749,6 +13321,107 @@ func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { } return nil } +func (m *ResponseProcessProposal) 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: ResponseProcessProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResponseProcessProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + m.Result = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Result |= ResponseProcessProposal_Result(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Evidence", 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.Evidence = append(m.Evidence, make([]byte, postIndex-iNdEx)) + copy(m.Evidence[len(m.Evidence)-1], dAtA[iNdEx:postIndex]) + 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 *LastCommitInfo) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/internal/consensus/state.go b/internal/consensus/state.go index 64a201ef6d..1e2e721d2f 100644 --- a/internal/consensus/state.go +++ b/internal/consensus/state.go @@ -1346,6 +1346,19 @@ func (cs *State) defaultDoPrevote(height int64, round int32) { return } + stateMachineValidBlock, err := cs.blockExec.ProcessProposal(cs.ProposalBlock) + if err != nil { + cs.Logger.Error("state machine returned an error when trying to process proposal block", "err", err) + } + + // Vote nil if application invalidated the block + if !stateMachineValidBlock { + // Consensus says we must vote nil + logger.Error("prevote step: consensus deems this block to be mustVoteNil", "err", err) + cs.signAddVote(tmproto.PrevoteType, nil, types.PartSetHeader{}) + return + } + // Prevote cs.ProposalBlock // NOTE: the proposal signature is validated when it is received, // and the proposal block parts are validated as they are received (against the merkle hash in the proposal) diff --git a/internal/proxy/app_conn.go b/internal/proxy/app_conn.go index 775f946e4c..701f5eeb01 100644 --- a/internal/proxy/app_conn.go +++ b/internal/proxy/app_conn.go @@ -20,6 +20,7 @@ type AppConnConsensus interface { InitChainSync(context.Context, types.RequestInitChain) (*types.ResponseInitChain, error) PrepareProposalSync(context.Context, types.RequestPrepareProposal) (*types.ResponsePrepareProposal, error) + ProcessProposalSync(context.Context, types.RequestProcessProposal) (*types.ResponseProcessProposal, error) BeginBlockSync(context.Context, types.RequestBeginBlock) (*types.ResponseBeginBlock, error) DeliverTxAsync(context.Context, types.RequestDeliverTx) (*abciclient.ReqRes, error) @@ -93,6 +94,13 @@ func (app *appConnConsensus) PrepareProposalSync( return app.appConn.PrepareProposalSync(ctx, req) } +func (app *appConnConsensus) ProcessProposalSync( + ctx context.Context, + req types.RequestProcessProposal, +) (*types.ResponseProcessProposal, error) { + return app.appConn.ProcessProposalSync(ctx, req) +} + func (app *appConnConsensus) BeginBlockSync( ctx context.Context, req types.RequestBeginBlock, diff --git a/internal/proxy/mocks/app_conn_consensus.go b/internal/proxy/mocks/app_conn_consensus.go index d8a764542c..6e9e6e8676 100644 --- a/internal/proxy/mocks/app_conn_consensus.go +++ b/internal/proxy/mocks/app_conn_consensus.go @@ -171,6 +171,29 @@ func (_m *AppConnConsensus) PrepareProposalSync(_a0 context.Context, _a1 types.R return r0, r1 } +// ProcessProposalSync provides a mock function with given fields: _a0, _a1 +func (_m *AppConnConsensus) ProcessProposalSync(_a0 context.Context, _a1 types.RequestProcessProposal) (*types.ResponseProcessProposal, error) { + ret := _m.Called(_a0, _a1) + + var r0 *types.ResponseProcessProposal + if rf, ok := ret.Get(0).(func(context.Context, types.RequestProcessProposal) *types.ResponseProcessProposal); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.ResponseProcessProposal) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, types.RequestProcessProposal) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // SetResponseCallback provides a mock function with given fields: _a0 func (_m *AppConnConsensus) SetResponseCallback(_a0 abciclient.Callback) { _m.Called(_a0) diff --git a/internal/state/execution.go b/internal/state/execution.go index 25a65bc15f..fb7810d373 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -179,6 +179,23 @@ func (blockExec *BlockExecutor) CreateProposalBlock( ) } +func (blockExec *BlockExecutor) ProcessProposal( + block *types.Block, +) (bool, error) { + ctx := context.Background() + req := abci.RequestProcessProposal{ + Txs: block.Data.Txs.ToSliceOfBytes(), + Header: *block.Header.ToProto(), + } + + resp, err := blockExec.proxyApp.ProcessProposalSync(ctx, req) + if err != nil { + return false, ErrInvalidBlock(err) + } + + return resp.IsOK(), nil +} + // ValidateBlock validates the given block against the given state. // If the block is invalid, it returns an error. // Validation does not mutate state, but does require historical information from the stateDB, diff --git a/internal/state/execution_test.go b/internal/state/execution_test.go index a66b677f94..3761bd6e30 100644 --- a/internal/state/execution_test.go +++ b/internal/state/execution_test.go @@ -22,6 +22,7 @@ import ( "github.com/tendermint/tendermint/internal/state/mocks" sf "github.com/tendermint/tendermint/internal/state/test/factory" "github.com/tendermint/tendermint/internal/store" + "github.com/tendermint/tendermint/internal/test/factory" "github.com/tendermint/tendermint/libs/log" tmtime "github.com/tendermint/tendermint/libs/time" "github.com/tendermint/tendermint/types" @@ -215,6 +216,38 @@ func TestBeginBlockByzantineValidators(t *testing.T) { assert.Equal(t, abciEv, app.ByzantineValidators) } +func TestProcessProposal(t *testing.T) { + height := 1 + runTest := func(txs types.Txs, expectAccept bool) { + app := &testApp{} + cc := abciclient.NewLocalCreator(app) + proxyApp := proxy.NewAppConns(cc, proxy.NopMetrics()) + err := proxyApp.Start() + require.Nil(t, err) + defer proxyApp.Stop() //nolint:errcheck // ignore for tests + + state, stateDB, _ := makeState(1, height) + stateStore := sm.NewStore(stateDB) + + blockStore := store.NewBlockStore(dbm.NewMemDB()) + + blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), + mmock.Mempool{}, sm.EmptyEvidencePool{}, blockStore) + + block := sf.MakeBlock(state, int64(height), new(types.Commit)) + block.Txs = txs + acceptBlock, err := blockExec.ProcessProposal(block) + require.Nil(t, err) + require.Equal(t, expectAccept, acceptBlock) + } + goodTxs := factory.MakeTenTxs(int64(height)) + runTest(goodTxs, true) + // testApp has process proposal fail if any tx is 0-len + badTxs := factory.MakeTenTxs(int64(height)) + badTxs[0] = types.Tx{} + runTest(badTxs, false) +} + func TestValidateValidatorUpdates(t *testing.T) { pubkey1 := ed25519.GenPrivKey().PubKey() pubkey2 := ed25519.GenPrivKey().PubKey() diff --git a/internal/state/helpers_test.go b/internal/state/helpers_test.go index b4f4708593..2fecf13e07 100644 --- a/internal/state/helpers_test.go +++ b/internal/state/helpers_test.go @@ -304,3 +304,12 @@ func (app *testApp) Commit() abci.ResponseCommit { func (app *testApp) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQuery) { return } + +func (app *testApp) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal { + for _, tx := range req.Txs { + if len(tx) == 0 { + return abci.ResponseProcessProposal{Result: abci.ResponseProcessProposal_REJECT} + } + } + return abci.ResponseProcessProposal{Result: abci.ResponseProcessProposal_ACCEPT} +} diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 33b6a5fce8..bcb75a000f 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -36,6 +36,7 @@ message Request { RequestLoadSnapshotChunk load_snapshot_chunk = 13; RequestApplySnapshotChunk apply_snapshot_chunk = 14; RequestPrepareProposal prepare_proposal = 15; + RequestProcessProposal process_proposal = 16; } } @@ -127,6 +128,11 @@ message RequestPrepareProposal { int64 block_data_size = 2; } +message RequestProcessProposal { + tendermint.types.Header header = 1 [(gogoproto.nullable) = false]; + repeated bytes txs = 2; +} + //---------------------------------------- // Response types @@ -148,6 +154,7 @@ message Response { ResponseLoadSnapshotChunk load_snapshot_chunk = 14; ResponseApplySnapshotChunk apply_snapshot_chunk = 15; ResponsePrepareProposal prepare_proposal = 16; + ResponseProcessProposal process_proposal = 17; } } @@ -277,6 +284,17 @@ message ResponsePrepareProposal { tendermint.types.Data block_data = 1; } +message ResponseProcessProposal { + Result result = 1; + repeated bytes evidence = 2; + + enum Result { + UNKNOWN = 0; // Unknown result, invalidate + ACCEPT = 1; // proposal verified, vote on the proposal + REJECT = 2; // proposal invalidated + } +} + //---------------------------------------- // Misc. @@ -383,4 +401,5 @@ service ABCIApplication { rpc LoadSnapshotChunk(RequestLoadSnapshotChunk) returns (ResponseLoadSnapshotChunk); rpc ApplySnapshotChunk(RequestApplySnapshotChunk) returns (ResponseApplySnapshotChunk); rpc PrepareProposal(RequestPrepareProposal) returns (ResponsePrepareProposal); + rpc ProcessProposal(RequestProcessProposal) returns (ResponseProcessProposal); } From 14ad0247e124f7f336485c190a6291393f461931 Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Wed, 13 Apr 2022 02:26:47 -0500 Subject: [PATCH 18/31] Temporarily disable socket client app test (#714) * add missing ProcessProposal handlers for the socket client * disable test_apps --- .github/workflows/build.yml | 45 ++++++++++++++++++------------------ abci/client/socket_client.go | 2 ++ abci/server/socket_server.go | 3 +++ 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ce6958eabc..5a40447604 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -58,25 +58,26 @@ jobs: shell: bash if: "env.GIT_DIFF != ''" - test_apps: - runs-on: ubuntu-latest - needs: build - timeout-minutes: 5 - steps: - - uses: actions/setup-go@v3 - with: - go-version: "1.17" - - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6 - with: - PATTERNS: | - **/**.go - go.mod - go.sum - - name: install - run: make install install_abci - if: "env.GIT_DIFF != ''" - - name: test_apps - run: test/app/test.sh - shell: bash - if: "env.GIT_DIFF != ''" + # TODO: re-enable this test after upgrading to v0.36.x + # test_apps: + # runs-on: ubuntu-latest + # needs: build + # timeout-minutes: 5 + # steps: + # - uses: actions/setup-go@v3 + # with: + # go-version: "1.17" + # - uses: actions/checkout@v3 + # - uses: technote-space/get-diff-action@v6 + # with: + # PATTERNS: | + # **/**.go + # go.mod + # go.sum + # - name: install + # run: make install install_abci + # if: "env.GIT_DIFF != ''" + # - name: test_apps + # run: test/app/test.sh + # shell: bash + # if: "env.GIT_DIFF != ''" diff --git a/abci/client/socket_client.go b/abci/client/socket_client.go index 89c8e080fa..b19e150f3d 100644 --- a/abci/client/socket_client.go +++ b/abci/client/socket_client.go @@ -602,6 +602,8 @@ func resMatchesReq(req *types.Request, res *types.Response) (ok bool) { _, ok = res.Value.(*types.Response_OfferSnapshot) case *types.Request_PrepareProposal: _, ok = res.Value.(*types.Response_PrepareProposal) + case *types.Request_ProcessProposal: + _, ok = res.Value.(*types.Response_ProcessProposal) } return ok } diff --git a/abci/server/socket_server.go b/abci/server/socket_server.go index ead074f490..116d840218 100644 --- a/abci/server/socket_server.go +++ b/abci/server/socket_server.go @@ -230,6 +230,9 @@ func (s *SocketServer) handleRequest(req *types.Request, responses chan<- *types case *types.Request_PrepareProposal: res := s.app.PrepareProposal(*r.PrepareProposal) responses <- types.ToResponsePrepareProposal(res) + case *types.Request_ProcessProposal: + res := s.app.ProcessProposal(*r.ProcessProposal) + responses <- types.ToResponseProcessProposal(res) case *types.Request_LoadSnapshotChunk: res := s.app.LoadSnapshotChunk(*r.LoadSnapshotChunk) responses <- types.ToResponseLoadSnapshotChunk(res) From e094b58f956c43f57920a627bdb41a7631e56e99 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Mon, 2 May 2022 15:55:03 -0500 Subject: [PATCH 19/31] increase timeouts for CI e2e test try extending the deadline attempt to tune timer increase timeouts increase github CI timeout wait 5 seconds before checking on nodes patch test left over from rebase --- .github/workflows/e2e.yml | 2 +- internal/state/tx_filter_test.go | 2 +- test/e2e/app/app.go | 6 ++++++ test/e2e/runner/perturb.go | 2 +- test/e2e/runner/rpc.go | 6 +++--- test/e2e/runner/start.go | 2 +- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 491363d661..505e40779c 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -12,7 +12,7 @@ on: jobs: e2e-test: runs-on: ubuntu-latest - timeout-minutes: 15 + timeout-minutes: 25 steps: - uses: actions/setup-go@v3 with: diff --git a/internal/state/tx_filter_test.go b/internal/state/tx_filter_test.go index 04a1badd44..df13eda5e6 100644 --- a/internal/state/tx_filter_test.go +++ b/internal/state/tx_filter_test.go @@ -22,7 +22,7 @@ func TestTxFilter(t *testing.T) { tx types.Tx isErr bool }{ - {types.Tx(tmrand.Bytes(2149)), false}, + {types.Tx(tmrand.Bytes(2106)), false}, {types.Tx(tmrand.Bytes(2152)), true}, {types.Tx(tmrand.Bytes(3000)), true}, } diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index 1eaab99755..173ca33d2c 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -276,6 +276,12 @@ func (app *Application) PrepareProposal( return abci.ResponsePrepareProposal{BlockData: req.BlockData} } +func (app *Application) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal { + return abci.ResponseProcessProposal{ + Result: abci.ResponseProcessProposal_ACCEPT, + } +} + // validatorUpdates generates a validator set update. func (app *Application) validatorUpdates(height uint64) (abci.ValidatorUpdates, error) { updates := app.cfg.ValidatorUpdates[fmt.Sprintf("%v", height)] diff --git a/test/e2e/runner/perturb.go b/test/e2e/runner/perturb.go index ccb3f6c510..7d89f80c8f 100644 --- a/test/e2e/runner/perturb.go +++ b/test/e2e/runner/perturb.go @@ -88,7 +88,7 @@ func PerturbNode(ctx context.Context, node *e2e.Node, perturbation e2e.Perturbat return nil, nil } - ctx, cancel := context.WithTimeout(ctx, 5*time.Minute) + ctx, cancel := context.WithTimeout(ctx, 7*time.Minute) defer cancel() status, err := waitForNode(ctx, node, 0) if err != nil { diff --git a/test/e2e/runner/rpc.go b/test/e2e/runner/rpc.go index ad5fa7a64d..14c3f2e597 100644 --- a/test/e2e/runner/rpc.go +++ b/test/e2e/runner/rpc.go @@ -138,7 +138,7 @@ func waitForNode(ctx context.Context, node *e2e.Node, height int64) (*rpctypes.R return nil, err } - timer := time.NewTimer(0) + timer := time.NewTimer(5 * time.Second) defer timer.Stop() var ( @@ -171,7 +171,7 @@ func waitForNode(ctx context.Context, node *e2e.Node, height int64) (*rpctypes.R return nil, err case err == nil && status.SyncInfo.LatestBlockHeight >= height: return status, nil - case counter%500 == 0: + case counter%1000 == 0: switch { case err != nil: lastFailed = true @@ -190,7 +190,7 @@ func waitForNode(ctx context.Context, node *e2e.Node, height int64) (*rpctypes.R ) } } - timer.Reset(250 * time.Millisecond) + timer.Reset(350 * time.Millisecond) } } } diff --git a/test/e2e/runner/start.go b/test/e2e/runner/start.go index 967d2519cf..ee43d36fd7 100644 --- a/test/e2e/runner/start.go +++ b/test/e2e/runner/start.go @@ -109,7 +109,7 @@ func Start(ctx context.Context, testnet *e2e.Testnet) error { return err } - wctx, wcancel := context.WithTimeout(ctx, 8*time.Minute) + wctx, wcancel := context.WithTimeout(ctx, 12*time.Minute) status, err := waitForNode(wctx, node, node.StartAt) if err != nil { wcancel() From 158799468200015f7990e3d0c627b19f8dc62a97 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Wed, 9 Jun 2021 14:29:53 +0200 Subject: [PATCH 20/31] modify the github templates chore: update proposal chore: add write adr template chore: add implement feature template chore: add refs to spec chore: minor change to proposal Update .github/ISSUE_TEMPLATE/write-adr.md Co-authored-by: John Adler chore: remove a few lines from bug report --- .github/ISSUE_TEMPLATE/bug-report.md | 16 ++------ .github/ISSUE_TEMPLATE/feature-request.md | 36 ----------------- .github/ISSUE_TEMPLATE/implement-feature.md | 45 +++++++++++++++++++++ .github/ISSUE_TEMPLATE/proposal.md | 35 ++++++++++++++++ .github/ISSUE_TEMPLATE/write-adr.md | 43 ++++++++++++++++++++ 5 files changed, 126 insertions(+), 49 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/feature-request.md create mode 100644 .github/ISSUE_TEMPLATE/implement-feature.md create mode 100644 .github/ISSUE_TEMPLATE/proposal.md create mode 100644 .github/ISSUE_TEMPLATE/write-adr.md diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index e99d578800..46f6d3c5cf 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -10,15 +10,7 @@ Be ready for followup questions, and please respond in a timely manner. We might ask you to provide additional logs and data (tendermint & app). --> -**Tendermint version** (use `tendermint version` or `git rev-parse --verify HEAD` if installed from source): - - -**ABCI app** (name for built-in, URL for self-written if it's publicly available): - -**Environment**: -- **OS** (e.g. from /etc/os-release): -- **Install tools**: -- **Others**: +**Version** (use `git rev-parse --verify HEAD`): **What happened**: @@ -27,16 +19,14 @@ manner. We might ask you to provide additional logs and data (tendermint & app). **What you expected to happen**: -**Have you tried the latest version**: yes/no - **How to reproduce it** (as minimally and precisely as possible): **Logs (paste a small part showing an error (< 10 lines) or link a pastebin, gist, etc. containing more of the log file)**: -**Config (you can paste only the changes you've made)**: +**Config (you can paste only the changes you've made to the config)**: **node command runtime flags**: **Please provide the output from the `http://:/dump_consensus_state` RPC endpoint for consensus bugs** -**Anything else we need to know**: +**Anything else**: diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md deleted file mode 100644 index 62c3e4f3aa..0000000000 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -name: Feature Request -about: Create a proposal to request a feature - ---- - - - -## Summary - - - -## Problem Definition - - - -## Proposal - - - -____ - -#### For Admin Use - -- [ ] Not duplicate issue -- [ ] Appropriate labels applied -- [ ] Appropriate contributors tagged -- [ ] Contributor assigned/self-assigned diff --git a/.github/ISSUE_TEMPLATE/implement-feature.md b/.github/ISSUE_TEMPLATE/implement-feature.md new file mode 100644 index 0000000000..cac1cf69ed --- /dev/null +++ b/.github/ISSUE_TEMPLATE/implement-feature.md @@ -0,0 +1,45 @@ +--- +name: Actionable implementation task +about: A well-defined, already decided-on, actionable implementation task. + +--- + +## Summary + + + +## Details + + + +### Action Items + +- [ ] sub-task 1 + + +### References + + + diff --git a/.github/ISSUE_TEMPLATE/proposal.md b/.github/ISSUE_TEMPLATE/proposal.md new file mode 100644 index 0000000000..612dd9b4dd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/proposal.md @@ -0,0 +1,35 @@ +--- +name: proposal +about: Propose an improvement, feature, or change to core components + +--- + + + +## Summary + + + +## Problem Definition + + + +## Proposal + + + +### Implementation + + + + + + diff --git a/.github/ISSUE_TEMPLATE/write-adr.md b/.github/ISSUE_TEMPLATE/write-adr.md new file mode 100644 index 0000000000..fe3360eb65 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/write-adr.md @@ -0,0 +1,43 @@ +--- +name: ADR +about: Write an ADR for certain aspect of the system + +--- + +## Summary + + + +## Details + + + + + + + +## References and Context + + From 02a9dae63a6ccfd2ef077a08fcdbc9772664e4c3 Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Wed, 4 May 2022 10:19:59 -0500 Subject: [PATCH 21/31] use correct default branch Co-authored-by: John Adler --- .github/workflows/linter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index b7c2b5a009..356d4d550c 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -28,7 +28,7 @@ jobs: uses: docker://github/super-linter:v4 env: VALIDATE_ALL_CODEBASE: true - DEFAULT_BRANCH: v0.34.x-celestia + DEFAULT_BRANCH: v0.35.x-celestia GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VALIDATE_MD: true VALIDATE_OPENAPI: true From a5a3df7d16bb2b58a1f4561f073125017375e32c Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Wed, 4 May 2022 10:26:16 -0500 Subject: [PATCH 22/31] use the correct default branch in the readme Co-authored-by: John Adler --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e723e941a0..365067139f 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/celestiaorg/celestia-core) [![Community](https://img.shields.io/badge/chat%20on-discord-orange?&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/YsnTPcSfWQ) -[![license](https://img.shields.io/github/license/tendermint/tendermint.svg)](https://github.com/celestiaorg/celestia-core/blob/master/LICENSE) +[![license](https://img.shields.io/github/license/tendermint/tendermint.svg)](https://github.com/celestiaorg/celestia-core/blob/v0.35.x-celestia/LICENSE) Celestia Core will power the Celestia main chain by leveraging Tendermint. From 49965399174116fb4b516da9bd1d3065d90f411b Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 4 May 2022 12:54:21 -0500 Subject: [PATCH 23/31] replace the references of v0.34 with v0.35 in the e2e CI --- .github/workflows/e2e-nightly-34x.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e-nightly-34x.yml b/.github/workflows/e2e-nightly-34x.yml index 71b9c8182f..35cfda86ea 100644 --- a/.github/workflows/e2e-nightly-34x.yml +++ b/.github/workflows/e2e-nightly-34x.yml @@ -27,7 +27,7 @@ jobs: - uses: actions/checkout@v3 with: - ref: 'v0.34.x' + ref: 'v0.35.x' - name: Build working-directory: test/e2e @@ -56,7 +56,7 @@ jobs: SLACK_USERNAME: Nightly E2E Tests SLACK_ICON_EMOJI: ':skull:' SLACK_COLOR: danger - SLACK_MESSAGE: Nightly E2E tests failed on v0.34.x + SLACK_MESSAGE: Nightly E2E tests failed on v0.35.x SLACK_FOOTER: '' e2e-nightly-success: # may turn this off once they seem to pass consistently @@ -72,5 +72,5 @@ jobs: SLACK_USERNAME: Nightly E2E Tests SLACK_ICON_EMOJI: ':white_check_mark:' SLACK_COLOR: good - SLACK_MESSAGE: Nightly E2E tests passed on v0.34.x + SLACK_MESSAGE: Nightly E2E tests passed on v0.35.x SLACK_FOOTER: '' From 46b13bcaf9c4d6b1fc55a926dd0f349e8642bb09 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 4 May 2022 13:06:29 -0500 Subject: [PATCH 24/31] delete comment --- abci/example/kvstore/persistent_kvstore.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/abci/example/kvstore/persistent_kvstore.go b/abci/example/kvstore/persistent_kvstore.go index 5e5975ff4a..14f446693e 100644 --- a/abci/example/kvstore/persistent_kvstore.go +++ b/abci/example/kvstore/persistent_kvstore.go @@ -172,10 +172,6 @@ func (app *PersistentKVStoreApplication) ApplySnapshotChunk( func (app *PersistentKVStoreApplication) PrepareProposal( req types.RequestPrepareProposal) types.ResponsePrepareProposal { - // if len(req.BlockData.Txs) >= 1 { - // req.BlockData.Txs[0] = []byte("modified tx") - // } - return types.ResponsePrepareProposal{BlockData: req.BlockData} } From 79b95615e795864cf0fdfc67a3f3afba2088bab7 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 4 May 2022 13:15:12 -0500 Subject: [PATCH 25/31] add comment to ABCI interface for new methods --- abci/types/application.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/abci/types/application.go b/abci/types/application.go index 61b8f68c6c..b74b1cbfef 100644 --- a/abci/types/application.go +++ b/abci/types/application.go @@ -17,13 +17,13 @@ type Application interface { CheckTx(RequestCheckTx) ResponseCheckTx // Validate a tx for the mempool // Consensus Connection - InitChain(RequestInitChain) ResponseInitChain // Initialize blockchain w validators/other info from TendermintCore - PrepareProposal(RequestPrepareProposal) ResponsePrepareProposal - BeginBlock(RequestBeginBlock) ResponseBeginBlock // Signals the beginning of a block - DeliverTx(RequestDeliverTx) ResponseDeliverTx // Deliver a tx for full processing - EndBlock(RequestEndBlock) ResponseEndBlock // Signals the end of a block, returns changes to the validator set - Commit() ResponseCommit // Commit the state and return the application Merkle root hash - ProcessProposal(RequestProcessProposal) ResponseProcessProposal + InitChain(RequestInitChain) ResponseInitChain // Initialize blockchain w validators/other info from TendermintCore + PrepareProposal(RequestPrepareProposal) ResponsePrepareProposal // Passes the block data to the application for modification before proposing + BeginBlock(RequestBeginBlock) ResponseBeginBlock // Signals the beginning of a block + DeliverTx(RequestDeliverTx) ResponseDeliverTx // Deliver a tx for full processing + EndBlock(RequestEndBlock) ResponseEndBlock // Signals the end of a block, returns changes to the validator set + Commit() ResponseCommit // Commit the state and return the application Merkle root hash + ProcessProposal(RequestProcessProposal) ResponseProcessProposal // Inspects the proposed block before voting on it during consensus // State Sync Connection ListSnapshots(RequestListSnapshots) ResponseListSnapshots // List available snapshots From a544403ce4741d720792c09582d73b5b098edf2e Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 4 May 2022 13:26:17 -0500 Subject: [PATCH 26/31] add missing ADR documentation and consolidate readmes --- docs/celestia-architecture/README copy.md | 37 ------------- docs/celestia-architecture/README.md | 52 ++++++++++++++++--- ...oagation.md => adr-006-row-propagation.md} | 0 3 files changed, 46 insertions(+), 43 deletions(-) delete mode 100644 docs/celestia-architecture/README copy.md rename docs/celestia-architecture/{adr-006-row-propoagation.md => adr-006-row-propagation.md} (100%) diff --git a/docs/celestia-architecture/README copy.md b/docs/celestia-architecture/README copy.md deleted file mode 100644 index f00a22e54e..0000000000 --- a/docs/celestia-architecture/README copy.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -order: 1 -parent: - order: false ---- - -# Architecture Decision Records (ADR) - -This is a location to record all high-level architecture decisions in this repository. - -You can read more about the ADR concept in this [blog post](https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t). - -An ADR should provide: - -- Context on the relevant goals and the current state -- Proposed changes to achieve the goals -- Summary of pros and cons -- References -- Changelog - -Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and -justification for a change in architecture, or for the architecture of something -new. The spec is much more compressed and streamlined summary of everything as -it stands today. - -If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match. - -Note the context/background should be written in the present tense. - -To start a new ADR, you can use this template: [adr-template.md](./adr-template.md) - -### Table of Contents: - -- [ADR 001: Erasure Coding Block Propagation](./adr-001-block-propagation.md) -- [ADR 002: Sampling erasure coded Block chunks](./adr-002-ipld-da-sampling.md) -- [ADR 003: Retrieving Application messages](./adr-003-application-data-retrieval.md) -- [ADR 004: Data Availability Sampling Light Client](./adr-004-mvp-light-client.md) diff --git a/docs/celestia-architecture/README.md b/docs/celestia-architecture/README.md index ef7a3a24ae..2bae6abd8b 100644 --- a/docs/celestia-architecture/README.md +++ b/docs/celestia-architecture/README.md @@ -1,3 +1,9 @@ +--- +order: 1 +parent: + order: false +--- + # Tendermint and Celestia celestia-core is not meant to be used as a general purpose framework. @@ -6,17 +12,51 @@ Hence, we do not provide any extensive documentation here. Instead of keeping a copy of the Tendermint documentation, we refer to the existing extensive and maintained documentation and specification: - - https://docs.tendermint.com/ - - https://github.com/tendermint/tendermint/tree/master/docs/ - - https://github.com/tendermint/spec +- https://docs.tendermint.com/ +- https://github.com/tendermint/tendermint/tree/master/docs/ +- https://github.com/tendermint/spec Reading these will give you a lot of background and context on Tendermint which will also help you understand how celestia-core and [celestia-app](https://github.com/celestiaorg/celestia-app) interact with each other. -# Celestia +## Celestia As mentioned above, celestia-core aims to be more focused on the Celestia use-case than vanilla Tendermint. Moving forward we might provide a clear overview on the changes we incorporated. For now, we refer to the Celestia specific [ADRs](./adr) in this repository as well as to the Celestia specification: - - [celestia-adr](./adr) - - [celestia-specs](https://github.com/celestiaorg/celestia-specs) +- [celestia-specs](https://github.com/celestiaorg/celestia-specs)**** + +## Architecture Decision Records (ADR) + +This is a location to record all high-level architecture decisions in this repository. + +You can read more about the ADR concept in this [blog post](https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t). + +An ADR should provide: + +- Context on the relevant goals and the current state +- Proposed changes to achieve the goals +- Summary of pros and cons +- References +- Changelog + +Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something +new. The spec is much more compressed and streamlined summary of everything as +it stands today. + +If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match. + +Note the context/background should be written in the present tense. + +To start a new ADR, you can use this template: [adr-template.md](./adr-template.md) + +### Table of Contents + +- [ADR 001: Erasure Coding Block Propagation](./adr-001-block-propagation.md) +- [ADR 002: Sampling erasure coded Block chunks](./adr-002-ipld-da-sampling.md) +- [ADR 003: Retrieving Application messages](./adr-003-application-data-retrieval.md) +- [ADR 004: Data Availability Sampling Light Client](./adr-004-mvp-light-client.md) +- [ADR 005: Decouple BlockID and PartSetHeader](./adr-005-decouple-blockid-and-partsetheader) +- [ADR 006: Row Propagation](./adr-006-row-propagation) +- [ADR 007: Minimal Changes to Tendermint](./adr-007-minimal-changes-to-tendermint) \ No newline at end of file diff --git a/docs/celestia-architecture/adr-006-row-propoagation.md b/docs/celestia-architecture/adr-006-row-propagation.md similarity index 100% rename from docs/celestia-architecture/adr-006-row-propoagation.md rename to docs/celestia-architecture/adr-006-row-propagation.md From 67ed4acbd8bb466241543788937bebf68d854c50 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 4 May 2022 13:28:39 -0500 Subject: [PATCH 27/31] remove outdated comment --- types/block.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/types/block.go b/types/block.go index 2c48b4e462..caabd0b1ef 100644 --- a/types/block.go +++ b/types/block.go @@ -1011,11 +1011,6 @@ type Data struct { Evidence EvidenceData `json:"evidence"` // The messages included in this block. - // TODO: how do messages end up here? (abci) app <-> ll-core? - // A simple approach could be: include them in the Tx above and - // have a mechanism to split them out somehow? Probably better to include - // them only when necessary (before proposing the block) as messages do not - // really need to be processed by tendermint Messages Messages `json:"msgs"` // OriginalSquareSize is the size of the square after splitting all the block data From 15686cc3e269ff3e82d044d2e25c1d6cc3c6b00d Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 4 May 2022 13:29:15 -0500 Subject: [PATCH 28/31] remove unused var from the makefile --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 3eff0095e6..80876e9d9c 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,6 @@ BUILDDIR ?= $(CURDIR)/build BUILD_TAGS?=tendermint IMAGE := ghcr.io/tendermint/docker-build-proto:latest -DOCKER_PROTO_BUILDER := docker run -v $(shell pwd):/workspace --workdir /workspace $(IMAGE) # If building a release, please checkout the version tag to get the correct version setting ifneq ($(shell git symbolic-ref -q --short HEAD),) From 91ad715054a73b2b2ae2aa2a2d9633badecea729 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 4 May 2022 13:32:18 -0500 Subject: [PATCH 29/31] add back proto-gen to proto-all in makefile --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 80876e9d9c..29aeefa5f3 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ LD_FLAGS = -X github.com/tendermint/tendermint/version.TMVersion=$(VERSION) BUILD_FLAGS = -mod=readonly -ldflags "$(LD_FLAGS)" HTTPS_GIT := https://github.com/tendermint/tendermint.git BUILD_IMAGE := ghcr.io/tendermint/docker-build-proto -BASE_BRANCH := v0.35.x +BASE_BRANCH := v0.35.x-celestia DOCKER_PROTO := docker run -v $(shell pwd):/workspace --workdir /workspace $(BUILD_IMAGE) CGO_ENABLED ?= 0 @@ -82,7 +82,7 @@ $(BUILDDIR)/: ### Protobuf ### ############################################################################### -proto-all: proto-lint proto-check-breaking +proto-all: proto-gen proto-lint proto-check-breaking .PHONY: proto-all proto-gen: From e6cee7bd1e83dc87493d929a44ceb923fdd7b5d7 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 4 May 2022 13:56:10 -0500 Subject: [PATCH 30/31] rename file to reflect versioning change --- .github/workflows/{e2e-nightly-34x.yml => e2e-nightly-35x.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{e2e-nightly-34x.yml => e2e-nightly-35x.yml} (100%) diff --git a/.github/workflows/e2e-nightly-34x.yml b/.github/workflows/e2e-nightly-35x.yml similarity index 100% rename from .github/workflows/e2e-nightly-34x.yml rename to .github/workflows/e2e-nightly-35x.yml From d3aadefb1fc234c06f0872967307847dfdd3b93c Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 4 May 2022 14:25:13 -0500 Subject: [PATCH 31/31] use a second variable to clarify the number of bytes used by an empty block --- types/block.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/types/block.go b/types/block.go index caabd0b1ef..6143130f11 100644 --- a/types/block.go +++ b/types/block.go @@ -41,9 +41,13 @@ const ( // 2 fields (2 embedded): 2 bytes // Uvarint length of Data.Txs: 4 bytes // Data fields: 6 bytes + MaxOverheadForBlock int64 = 16 + + // MinimumDataBytes is the numbers of bytes that will be taken up by empty + // block data // Hash in Data 32 bytes // OriginalSquareSize in Data 8 bytes - MaxOverheadForBlock int64 = 56 + MinimumDataBytes int64 = 40 ) // Block defines the atomic unit of a Tendermint blockchain. @@ -265,6 +269,7 @@ func BlockFromProto(bp *tmproto.Block) (*Block, error) { func MaxDataBytes(maxBytes, evidenceBytes int64, valsCount int) int64 { maxDataBytes := maxBytes - MaxOverheadForBlock - + MinimumDataBytes - MaxHeaderBytes - MaxCommitBytes(valsCount) - evidenceBytes @@ -288,6 +293,7 @@ func MaxDataBytes(maxBytes, evidenceBytes int64, valsCount int) int64 { func MaxDataBytesNoEvidence(maxBytes int64, valsCount int) int64 { maxDataBytes := maxBytes - MaxOverheadForBlock - + MinimumDataBytes - MaxHeaderBytes - MaxCommitBytes(valsCount)