diff --git a/pkg/consts/consts.go b/pkg/consts/consts.go index 278f093697..835c668394 100644 --- a/pkg/consts/consts.go +++ b/pkg/consts/consts.go @@ -19,11 +19,14 @@ const ( // ShareReservedBytes is the reserved bytes for contiguous appends. ShareReservedBytes = 1 + // InfoReservedBytes is the number of reserved bytes for information. + // InfoReservedBytes is only applicable to message shares. + InfoReservedBytes = 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 + MsgShareSize = ShareSize - NamespaceSize - InfoReservedBytes // MaxSquareSize is the maximum number of // rows/columns of the original data shares in square layout. diff --git a/pkg/prove/proof.go b/pkg/prove/proof.go index 80f2e109e3..1b92fdf05d 100644 --- a/pkg/prove/proof.go +++ b/pkg/prove/proof.go @@ -13,12 +13,12 @@ import ( "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. +// TxInclusion uses the provided block data to progressively generate rows of a +// data square, and then uses 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, txIndex uint64) (types.TxProof, error) { - // calculate the index of the shares that contain the tx + // calculate the positions of the shares that contain this tx startPos, endPos, err := txSharePosition(data.Txs, txIndex) if err != nil { return types.TxProof{}, err @@ -90,8 +90,9 @@ func TxInclusion(codec rsmt2d.Codec, data types.Data, txIndex uint64) (types.TxP }, nil } -// txSharePosition returns the share that a given transaction is included in. -// returns an error if index is greater than that of the provided txs. +// txSharePosition returns the start and end positions for the shares that +// include the given transaction. Returns an error if txIndex is greater than +// the number of transactions. func txSharePosition(txs types.Txs, txIndex uint64) (startSharePos, endSharePos uint64, err error) { if txIndex >= uint64(len(txs)) { return startSharePos, endSharePos, errors.New("transaction index is greater than the number of txs") @@ -144,8 +145,8 @@ func genRowShares(codec rsmt2d.Codec, data types.Data, startRow, endRow uint64) } // 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 +// data square, meaning the rows only fill half the full square length, as there +// is no erasure data. func genOrigRowShares(data types.Data, startRow, endRow uint64) [][]byte { wantLen := (endRow + 1) * data.OriginalSquareSize startPos := startRow * data.OriginalSquareSize @@ -168,7 +169,7 @@ func genOrigRowShares(data types.Data, startRow, endRow uint64) [][]byte { if err != nil { panic(fmt.Sprintf("app accepted a Message that can not be encoded %#v", m)) } - shares = types.AppendToShares(shares, m.NamespaceID, rawData) + shares = types.AppendToShares(shares, m.NamespaceID, m.Version, rawData) // return if we have enough shares if uint64(len(shares)) >= wantLen { diff --git a/proto/tendermint/types/types.pb.go b/proto/tendermint/types/types.pb.go index d569e81f69..363b25b52f 100644 --- a/proto/tendermint/types/types.pb.go +++ b/proto/tendermint/types/types.pb.go @@ -827,6 +827,7 @@ func (m *Messages) GetMessagesList() []*Message { 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"` + Version uint32 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"` } func (m *Message) Reset() { *m = Message{} } @@ -876,6 +877,13 @@ func (m *Message) GetData() []byte { return nil } +func (m *Message) GetVersion() uint32 { + if m != nil { + return m.Version + } + return 0 +} + // 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 @@ -1681,124 +1689,124 @@ func init() { func init() { proto.RegisterFile("tendermint/types/types.proto", fileDescriptor_d3a6e55e2345de56) } var fileDescriptor_d3a6e55e2345de56 = []byte{ - // 1859 bytes of a gzipped FileDescriptorProto + // 1866 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, 0x76, 0x12, 0x59, 0x0c, 0x05, - 0xeb, 0xfd, 0x40, 0x0e, 0x5e, 0x8a, 0x8f, 0x2a, 0xa0, 0x56, 0xb2, 0xbd, 0xb1, 0x58, 0x4b, 0x16, - 0x23, 0x6d, 0xf8, 0xb8, 0x4c, 0xb5, 0x34, 0x6d, 0x69, 0x2a, 0xa3, 0x99, 0x61, 0xa6, 0xe5, 0xc8, - 0xf9, 0x0b, 0x28, 0x9f, 0x72, 0xe2, 0xe6, 0x13, 0x1c, 0xb8, 0xf3, 0x0f, 0x50, 0x9c, 0xf6, 0x42, - 0xd5, 0xde, 0xe0, 0x42, 0xa0, 0x12, 0x8a, 0xe2, 0xcf, 0xa0, 0xfa, 0x75, 0xcf, 0x68, 0x64, 0x49, - 0x81, 0x4a, 0xa5, 0xf6, 0xa2, 0x9a, 0x7e, 0xef, 0xf7, 0xba, 0x5f, 0xbf, 0xef, 0x16, 0x3c, 0x60, - 0xd4, 0x31, 0xa9, 0x3f, 0xb6, 0x1c, 0x76, 0xc0, 0xae, 0x3c, 0x1a, 0x88, 0xdf, 0x9a, 0xe7, 0xbb, - 0xcc, 0x55, 0x4b, 0x33, 0x6e, 0x0d, 0xe9, 0xbb, 0xdb, 0x43, 0x77, 0xe8, 0x22, 0xf3, 0x80, 0x7f, - 0x09, 0xdc, 0xee, 0xde, 0xd0, 0x75, 0x87, 0x36, 0x3d, 0xc0, 0x55, 0x7f, 0x72, 0x71, 0xc0, 0xac, - 0x31, 0x0d, 0x18, 0x19, 0x7b, 0x12, 0xf0, 0x30, 0x76, 0xcc, 0xc0, 0xbf, 0xf2, 0x98, 0xcb, 0xb1, - 0xee, 0x85, 0x64, 0x57, 0x62, 0xec, 0x4b, 0xea, 0x07, 0x96, 0xeb, 0xc4, 0xf5, 0xd8, 0xad, 0x2e, - 0x68, 0x79, 0x49, 0x6c, 0xcb, 0x24, 0xcc, 0xf5, 0x05, 0x42, 0xfb, 0x21, 0x14, 0x3b, 0xc4, 0x67, - 0x5d, 0xca, 0x4e, 0x29, 0x31, 0xa9, 0xaf, 0x6e, 0xc3, 0x3a, 0x73, 0x19, 0xb1, 0xcb, 0x4a, 0x55, - 0xd9, 0x2f, 0xea, 0x62, 0xa1, 0xaa, 0x90, 0x1a, 0x91, 0x60, 0x54, 0x4e, 0x54, 0x95, 0xfd, 0x82, - 0x8e, 0xdf, 0xda, 0x08, 0x52, 0x5c, 0x94, 0x4b, 0x58, 0x8e, 0x49, 0xa7, 0xa1, 0x04, 0x2e, 0x38, - 0xb5, 0x7f, 0xc5, 0x68, 0x20, 0x45, 0xc4, 0x42, 0xfd, 0x2e, 0xac, 0xa3, 0xfe, 0xe5, 0x64, 0x55, - 0xd9, 0xcf, 0x1f, 0x96, 0x6b, 0x31, 0x43, 0x89, 0xfb, 0xd5, 0x3a, 0x9c, 0xdf, 0x48, 0x7d, 0xf1, - 0x72, 0x6f, 0x4d, 0x17, 0x60, 0xcd, 0x86, 0x4c, 0xc3, 0x76, 0x07, 0x4f, 0x9b, 0xc7, 0x91, 0x22, - 0xca, 0x4c, 0x11, 0xb5, 0x05, 0x9b, 0x1e, 0xf1, 0x99, 0x11, 0x50, 0x66, 0x8c, 0xf0, 0x16, 0x78, - 0x68, 0xfe, 0x70, 0xaf, 0x76, 0xdb, 0x0f, 0xb5, 0xb9, 0xcb, 0xca, 0x53, 0x8a, 0x5e, 0x9c, 0xa8, - 0xfd, 0x3b, 0x05, 0x69, 0x69, 0x8c, 0x1f, 0x43, 0x46, 0x9a, 0x15, 0x0f, 0xcc, 0x1f, 0x3e, 0x8c, - 0xef, 0x28, 0x59, 0xb5, 0x23, 0xd7, 0x09, 0xa8, 0x13, 0x4c, 0x02, 0xb9, 0x5f, 0x28, 0xa3, 0x7e, - 0x0b, 0xb2, 0x83, 0x11, 0xb1, 0x1c, 0xc3, 0x32, 0x51, 0xa3, 0x5c, 0x23, 0xff, 0xea, 0xe5, 0x5e, - 0xe6, 0x88, 0xd3, 0x9a, 0xc7, 0x7a, 0x06, 0x99, 0x4d, 0x53, 0xbd, 0x0b, 0xe9, 0x11, 0xb5, 0x86, - 0x23, 0x86, 0x66, 0x49, 0xea, 0x72, 0xa5, 0xfe, 0x00, 0x52, 0x3c, 0x20, 0xca, 0x29, 0x3c, 0x7b, - 0xb7, 0x26, 0xa2, 0xa5, 0x16, 0x46, 0x4b, 0xad, 0x17, 0x46, 0x4b, 0x23, 0xcb, 0x0f, 0x7e, 0xf1, - 0x8f, 0x3d, 0x45, 0x47, 0x09, 0xf5, 0x08, 0x8a, 0x36, 0x09, 0x98, 0xd1, 0xe7, 0x66, 0xe3, 0xc7, - 0xaf, 0xe3, 0x16, 0x3b, 0x8b, 0x06, 0x91, 0x86, 0x95, 0xaa, 0xe7, 0xb9, 0x94, 0x20, 0x99, 0xea, - 0x3e, 0x94, 0x70, 0x93, 0x81, 0x3b, 0x1e, 0x5b, 0xcc, 0x40, 0xbb, 0xa7, 0xd1, 0xee, 0x1b, 0x9c, - 0x7e, 0x84, 0xe4, 0x53, 0xee, 0x81, 0xfb, 0x90, 0x33, 0x09, 0x23, 0x02, 0x92, 0x41, 0x48, 0x96, - 0x13, 0x90, 0xf9, 0x1e, 0x6c, 0x46, 0x51, 0x17, 0x08, 0x48, 0x56, 0xec, 0x32, 0x23, 0x23, 0xf0, - 0x11, 0x6c, 0x3b, 0x74, 0xca, 0x8c, 0xdb, 0xe8, 0x1c, 0xa2, 0x55, 0xce, 0x7b, 0x32, 0x2f, 0xf1, - 0x4d, 0xd8, 0x18, 0x84, 0xc6, 0x17, 0x58, 0x40, 0x6c, 0x31, 0xa2, 0x22, 0x6c, 0x07, 0xb2, 0xc4, - 0xf3, 0x04, 0x20, 0x8f, 0x80, 0x0c, 0xf1, 0x3c, 0x64, 0x7d, 0x00, 0x5b, 0x78, 0x47, 0x9f, 0x06, - 0x13, 0x9b, 0xc9, 0x4d, 0x0a, 0x88, 0xd9, 0xe4, 0x0c, 0x5d, 0xd0, 0x11, 0xfb, 0x0d, 0x28, 0xd2, - 0x4b, 0xcb, 0xa4, 0xce, 0x80, 0x0a, 0x5c, 0x11, 0x71, 0x85, 0x90, 0x88, 0xa0, 0xf7, 0xa1, 0xe4, - 0xf9, 0xae, 0xe7, 0x06, 0xd4, 0x37, 0x88, 0x69, 0xfa, 0x34, 0x08, 0xca, 0x1b, 0x62, 0xbf, 0x90, - 0x5e, 0x17, 0x64, 0xed, 0xa5, 0x02, 0xa9, 0x63, 0xc2, 0x88, 0x5a, 0x82, 0x24, 0x9b, 0x06, 0x65, - 0xa5, 0x9a, 0xdc, 0x2f, 0xe8, 0xfc, 0x53, 0xfd, 0x04, 0xb2, 0xe1, 0xae, 0x32, 0x55, 0x2a, 0x8b, - 0xae, 0x3b, 0x91, 0x88, 0x33, 0x2b, 0x60, 0xd2, 0x7f, 0x91, 0x94, 0xfa, 0x23, 0xc8, 0x8e, 0x69, - 0x10, 0x90, 0x21, 0x0d, 0xa2, 0xf8, 0x59, 0xd8, 0xa1, 0x25, 0x11, 0xa1, 0x74, 0x28, 0xc1, 0x5d, - 0xe1, 0xfa, 0xd6, 0xd0, 0x72, 0x88, 0x6d, 0x04, 0xbf, 0x9e, 0x10, 0x9f, 0x1a, 0x81, 0xf5, 0x9c, - 0x62, 0x18, 0xa5, 0x74, 0x35, 0xe4, 0x75, 0x91, 0xd5, 0xb5, 0x9e, 0xd3, 0x28, 0x31, 0xd3, 0xb1, - 0x0a, 0xf1, 0x22, 0x01, 0x77, 0x8e, 0x27, 0x9e, 0x6d, 0x0d, 0x08, 0xa3, 0x4f, 0x5c, 0x46, 0x43, - 0x8d, 0xd5, 0x6f, 0x43, 0xfa, 0xd2, 0x65, 0xd4, 0x20, 0x32, 0xaf, 0xee, 0x2e, 0xea, 0xc6, 0xf1, - 0xfa, 0x3a, 0x47, 0xd5, 0x23, 0x78, 0x5f, 0x26, 0xf6, 0x1b, 0xe1, 0x0d, 0xf5, 0x23, 0x50, 0xb1, - 0x6c, 0x19, 0x97, 0x2e, 0xb3, 0x9c, 0xa1, 0xe1, 0xb9, 0xcf, 0xa8, 0x2f, 0x73, 0xab, 0x84, 0x9c, - 0x27, 0xc8, 0xe8, 0x70, 0xfa, 0x5c, 0x7c, 0x4a, 0x68, 0x0a, 0xa1, 0xb3, 0xf8, 0x14, 0xc0, 0x06, - 0xe4, 0xa2, 0xfa, 0x2c, 0x13, 0xea, 0xff, 0xcb, 0xc9, 0x99, 0x98, 0xf6, 0x97, 0x04, 0xec, 0x9c, - 0xf1, 0xe4, 0x3e, 0xb2, 0x2d, 0xea, 0xb0, 0x3a, 0x63, 0x64, 0xf0, 0x34, 0x32, 0x4b, 0x13, 0xb6, - 0x06, 0xae, 0x73, 0x61, 0x5b, 0x03, 0xd4, 0x1b, 0xb3, 0x57, 0x5a, 0xe8, 0xc1, 0xe2, 0x95, 0x71, - 0x1f, 0x4c, 0x56, 0xbd, 0x14, 0x13, 0x43, 0x0a, 0x0f, 0x56, 0x9e, 0xb7, 0xae, 0x63, 0xc8, 0xd2, - 0x92, 0xc0, 0x3b, 0x15, 0x04, 0xf1, 0x54, 0x14, 0x98, 0x36, 0x6c, 0xf7, 0xaf, 0x9e, 0x13, 0x87, - 0x59, 0x0e, 0x8d, 0xa5, 0x5d, 0x39, 0x59, 0x4d, 0xee, 0xe7, 0x0f, 0xef, 0x2f, 0xb1, 0x72, 0x88, - 0xd1, 0xbf, 0x16, 0x09, 0xce, 0x72, 0x72, 0x85, 0xe1, 0x53, 0x2b, 0x0c, 0xff, 0x2e, 0xec, 0xf9, - 0x2f, 0x05, 0xb2, 0x91, 0xf9, 0x08, 0xdc, 0x33, 0xc3, 0x70, 0x33, 0x30, 0x60, 0xa2, 0x24, 0x12, - 0x46, 0x7c, 0x6f, 0xf1, 0x46, 0x4b, 0xe3, 0xf3, 0x74, 0x4d, 0xbf, 0x63, 0x2e, 0x0d, 0x5c, 0x07, - 0x1e, 0xd8, 0xdc, 0x74, 0xc6, 0x00, 0xfd, 0x67, 0x10, 0x74, 0xe0, 0xec, 0x1c, 0x11, 0x9f, 0x1f, - 0xae, 0x70, 0xd6, 0x32, 0xa7, 0x9f, 0xae, 0xe9, 0x3b, 0xf6, 0x2a, 0x66, 0x63, 0x1d, 0x92, 0xc1, - 0x64, 0xac, 0x9d, 0x41, 0x21, 0x9e, 0xed, 0x3c, 0xbb, 0x63, 0x57, 0x4b, 0x2e, 0xcf, 0xee, 0x68, - 0x93, 0x5b, 0xb5, 0x41, 0xfb, 0x29, 0x64, 0xc3, 0xcc, 0x57, 0x7f, 0x02, 0xc5, 0x30, 0xeb, 0x0d, - 0xdb, 0x0a, 0x98, 0xdc, 0x6e, 0x67, 0x65, 0xb1, 0xd0, 0x0b, 0x21, 0x9e, 0x6b, 0xa2, 0x7d, 0x02, - 0x19, 0xc9, 0x50, 0xbf, 0x0e, 0x05, 0x87, 0x8c, 0x69, 0xe0, 0x91, 0x01, 0xe5, 0x3d, 0x47, 0xf4, - 0xe8, 0x7c, 0x44, 0x6b, 0x9a, 0xbc, 0x4a, 0xf0, 0xbe, 0x10, 0xce, 0x11, 0xfc, 0x5b, 0xfb, 0x05, - 0xdc, 0xe5, 0x55, 0xb0, 0x7e, 0x49, 0x2c, 0x9b, 0xf4, 0x2d, 0xdb, 0x62, 0x57, 0xb2, 0xfd, 0xde, - 0x87, 0x9c, 0xef, 0x3e, 0x33, 0x7c, 0xd7, 0x65, 0x61, 0x75, 0xcc, 0xfa, 0xee, 0x33, 0x9d, 0xaf, - 0xf9, 0x69, 0x03, 0xd7, 0x9e, 0x8c, 0x1d, 0xc9, 0x4f, 0x20, 0x3f, 0x2f, 0x68, 0x08, 0xd1, 0xfe, - 0x93, 0x80, 0x14, 0xf7, 0x9e, 0xfa, 0x31, 0xa4, 0xf8, 0x1d, 0x50, 0xa3, 0x8d, 0x65, 0x63, 0x41, - 0xd7, 0x1a, 0x3a, 0xd4, 0x6c, 0x05, 0xc3, 0xde, 0x95, 0x47, 0x75, 0x04, 0xc7, 0xba, 0x72, 0x62, - 0xae, 0x2b, 0x6f, 0xc3, 0xba, 0xef, 0x4e, 0x1c, 0x13, 0x0b, 0xca, 0xba, 0x2e, 0x16, 0xea, 0x09, - 0x64, 0xa3, 0x66, 0x9b, 0xfa, 0x5f, 0xcd, 0x76, 0x93, 0x3b, 0x84, 0x8f, 0x02, 0x92, 0xa0, 0x67, - 0xfa, 0xb2, 0xe7, 0xbe, 0x83, 0x9c, 0x50, 0x3f, 0x84, 0xad, 0x59, 0x41, 0x0b, 0x7b, 0x90, 0xa8, - 0xcb, 0xa5, 0x88, 0x21, 0x9b, 0xd0, 0x7c, 0xf5, 0x13, 0x73, 0x5c, 0x06, 0xef, 0x35, 0xab, 0x7e, - 0x4d, 0x1c, 0xe8, 0x1e, 0x40, 0x2e, 0xb0, 0x86, 0x0e, 0x61, 0x13, 0x9f, 0xca, 0x06, 0x3e, 0x23, - 0x68, 0x7f, 0x52, 0x20, 0x2d, 0x06, 0x82, 0x98, 0xdd, 0x94, 0xe5, 0x76, 0x4b, 0xac, 0xb2, 0x5b, - 0xf2, 0xed, 0xed, 0x56, 0x07, 0x88, 0x94, 0xe1, 0x0d, 0x6f, 0x45, 0xfd, 0x12, 0x2a, 0x76, 0xad, - 0xa1, 0xcc, 0x89, 0x98, 0x90, 0xf6, 0x77, 0x05, 0x72, 0x11, 0x5f, 0xad, 0x43, 0x31, 0xd4, 0xcb, - 0xb8, 0xb0, 0xc9, 0x50, 0xc6, 0xce, 0xc3, 0x95, 0xca, 0x7d, 0x6a, 0x93, 0xa1, 0x9e, 0x97, 0xfa, - 0xf0, 0xc5, 0x72, 0x3f, 0x24, 0x56, 0xf8, 0x61, 0xce, 0xf1, 0xc9, 0xb7, 0x73, 0xfc, 0x9c, 0x8b, - 0x52, 0xb7, 0x5d, 0xf4, 0xc7, 0x04, 0x64, 0x3b, 0x38, 0x82, 0x10, 0xfb, 0xab, 0xc8, 0x88, 0xfb, - 0x90, 0xf3, 0x5c, 0xdb, 0x10, 0x9c, 0x14, 0x72, 0xb2, 0x9e, 0x6b, 0xeb, 0x0b, 0x6e, 0x5f, 0x7f, - 0x47, 0xe9, 0x92, 0x7e, 0x07, 0x56, 0xcb, 0xdc, 0xb6, 0x9a, 0x0f, 0x05, 0x61, 0x0a, 0x59, 0x93, - 0x1e, 0x71, 0x1b, 0xe0, 0x1b, 0x43, 0x59, 0x7c, 0xc2, 0x08, 0xb5, 0x05, 0x52, 0x97, 0x38, 0x2e, - 0x21, 0x26, 0x68, 0xd9, 0x1c, 0xca, 0xab, 0xc2, 0x52, 0x97, 0x38, 0xed, 0xb7, 0x0a, 0xc0, 0xac, - 0xb9, 0xf3, 0x61, 0x3e, 0x40, 0x15, 0x8c, 0xb9, 0x93, 0x2b, 0xab, 0x9c, 0x26, 0xcf, 0x2f, 0x04, - 0x71, 0xbd, 0x8f, 0xa0, 0x38, 0x0b, 0xc6, 0x80, 0x86, 0xca, 0x54, 0xde, 0xd0, 0xe3, 0xbb, 0x94, - 0xe9, 0x85, 0xcb, 0xd8, 0x4a, 0xfb, 0xb3, 0x02, 0x39, 0xd4, 0xa9, 0x45, 0x19, 0x99, 0xf3, 0xa1, - 0xf2, 0xf6, 0x3e, 0x7c, 0x08, 0x20, 0xb6, 0xc1, 0x09, 0x53, 0x44, 0x56, 0x0e, 0x29, 0x38, 0x58, - 0x7e, 0x2f, 0x32, 0x78, 0xf2, 0xcd, 0x06, 0x97, 0x29, 0x1d, 0x9a, 0xfd, 0x1e, 0x64, 0x9c, 0xc9, - 0xd8, 0xe0, 0x83, 0xb5, 0x18, 0x40, 0xd2, 0xce, 0x64, 0xdc, 0x9b, 0x06, 0x9a, 0x03, 0x99, 0xde, - 0x14, 0x5f, 0x99, 0x6f, 0x6e, 0x30, 0xb3, 0x5e, 0x95, 0x0c, 0x7b, 0x95, 0x7a, 0x08, 0x69, 0x7c, - 0x92, 0x86, 0x23, 0xd2, 0x92, 0xae, 0xdb, 0x6e, 0xf5, 0x70, 0x73, 0x5d, 0x22, 0xb5, 0x11, 0xe4, - 0x5b, 0xc4, 0xb6, 0x29, 0x61, 0xd4, 0xec, 0x4d, 0xf9, 0xab, 0x2a, 0x1a, 0xad, 0xd9, 0xd4, 0x88, - 0xbd, 0x66, 0x37, 0x42, 0x7a, 0x6f, 0x8a, 0x4f, 0x89, 0x0d, 0x48, 0xb0, 0xa9, 0x2c, 0x18, 0x09, - 0x36, 0x55, 0xf7, 0x20, 0x1f, 0x8c, 0xf8, 0x28, 0x2e, 0xca, 0x74, 0x12, 0x9f, 0xdb, 0x80, 0x24, - 0x2c, 0xd1, 0x1a, 0x85, 0x6c, 0x78, 0x3a, 0xcf, 0xc9, 0x80, 0x11, 0x5f, 0x14, 0xe1, 0x75, 0x5d, - 0x2c, 0xf8, 0x4b, 0x83, 0x46, 0x15, 0x98, 0x7f, 0x72, 0x9c, 0xe3, 0x9a, 0x54, 0x5c, 0xa8, 0xa0, - 0x8b, 0x05, 0x37, 0x8c, 0x4d, 0xc9, 0x85, 0xd0, 0x4e, 0x54, 0x92, 0x2c, 0x27, 0x70, 0xbd, 0x3e, - 0xf8, 0xab, 0x02, 0xf9, 0x58, 0xd1, 0x53, 0xbf, 0x03, 0x77, 0x1a, 0x67, 0xe7, 0x47, 0x9f, 0x19, - 0xcd, 0x63, 0xe3, 0xd3, 0xb3, 0xfa, 0x63, 0xe3, 0xf3, 0xf6, 0x67, 0xed, 0xf3, 0x9f, 0xb7, 0x4b, - 0x6b, 0xbb, 0x77, 0xaf, 0x6f, 0xaa, 0x6a, 0x0c, 0xfb, 0xb9, 0xf3, 0xd4, 0x71, 0x9f, 0x39, 0xea, - 0x01, 0x6c, 0xcf, 0x8b, 0xd4, 0x1b, 0xdd, 0x93, 0x76, 0xaf, 0xa4, 0xec, 0xde, 0xb9, 0xbe, 0xa9, - 0x6e, 0xc5, 0x24, 0xea, 0xfd, 0x80, 0x3a, 0x6c, 0x51, 0xe0, 0xe8, 0xbc, 0xd5, 0x6a, 0xf6, 0x4a, - 0x89, 0x05, 0x01, 0xd9, 0x85, 0xde, 0x87, 0xad, 0x79, 0x81, 0x76, 0xf3, 0xac, 0x94, 0xdc, 0x55, - 0xaf, 0x6f, 0xaa, 0x1b, 0x31, 0x74, 0xdb, 0xb2, 0x77, 0xb3, 0xbf, 0xf9, 0x5d, 0x65, 0xed, 0x0f, - 0xbf, 0xaf, 0x28, 0xfc, 0x66, 0xc5, 0xb9, 0xc2, 0xa7, 0x7e, 0x04, 0xf7, 0xba, 0xcd, 0xc7, 0xed, - 0x93, 0x63, 0xa3, 0xd5, 0x7d, 0x6c, 0xf4, 0x7e, 0xd9, 0x39, 0x89, 0xdd, 0x6e, 0xf3, 0xfa, 0xa6, - 0x9a, 0x97, 0x57, 0x5a, 0x85, 0xee, 0xe8, 0x27, 0x4f, 0xce, 0x7b, 0x27, 0x25, 0x45, 0xa0, 0x3b, - 0x3e, 0xe5, 0x83, 0x29, 0xa2, 0x1f, 0xc1, 0xce, 0x12, 0x74, 0x74, 0xb1, 0xad, 0xeb, 0x9b, 0x6a, - 0xb1, 0xe3, 0x53, 0x51, 0x14, 0x50, 0xa2, 0x06, 0xe5, 0x45, 0x89, 0xf3, 0xce, 0x79, 0xb7, 0x7e, - 0x56, 0xaa, 0xee, 0x96, 0xae, 0x6f, 0xaa, 0x85, 0xb0, 0xc2, 0x73, 0xfc, 0xec, 0x66, 0x8d, 0x9f, - 0x7d, 0xf1, 0xaa, 0xa2, 0x7c, 0xf9, 0xaa, 0xa2, 0xfc, 0xf3, 0x55, 0x45, 0x79, 0xf1, 0xba, 0xb2, - 0xf6, 0xe5, 0xeb, 0xca, 0xda, 0xdf, 0x5e, 0x57, 0xd6, 0x7e, 0xf5, 0xfd, 0xa1, 0xc5, 0x46, 0x93, - 0x7e, 0x6d, 0xe0, 0x8e, 0x0f, 0xe2, 0x7f, 0x17, 0xcd, 0x3e, 0xc5, 0xdf, 0x56, 0xb7, 0xff, 0x4a, - 0xea, 0xa7, 0x91, 0xfe, 0xf1, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xbf, 0xff, 0x3d, 0xd2, 0x0b, - 0x13, 0x00, 0x00, + 0xeb, 0xfd, 0x40, 0x0e, 0x5e, 0x8a, 0x8f, 0x2a, 0xa0, 0x90, 0x6c, 0x6f, 0x2c, 0xd6, 0x92, 0xc5, + 0x48, 0x1b, 0x60, 0x2f, 0x53, 0x2d, 0x4d, 0x5b, 0x9a, 0xca, 0x68, 0x66, 0x98, 0x69, 0x39, 0x72, + 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, + 0xa0, 0x52, 0xa9, 0xbd, 0xa8, 0xa6, 0xdf, 0xfb, 0xbd, 0xee, 0xd7, 0xef, 0xbb, 0x05, 0x0f, 0x18, + 0x75, 0x4c, 0xea, 0x8f, 0x2d, 0x87, 0x1d, 0xb0, 0x2b, 0x8f, 0x06, 0xe2, 0xb7, 0xe6, 0xf9, 0x2e, + 0x73, 0xd5, 0xd2, 0x8c, 0x5b, 0x43, 0xfa, 0xee, 0xf6, 0xd0, 0x1d, 0xba, 0xc8, 0x3c, 0xe0, 0x5f, + 0x02, 0xb7, 0xbb, 0x37, 0x74, 0xdd, 0xa1, 0x4d, 0x0f, 0x70, 0xd5, 0x9f, 0x5c, 0x1c, 0x30, 0x6b, + 0x4c, 0x03, 0x46, 0xc6, 0x9e, 0x04, 0x3c, 0x8c, 0x1d, 0x33, 0xf0, 0xaf, 0x3c, 0xe6, 0x72, 0xac, + 0x7b, 0x21, 0xd9, 0x95, 0x18, 0xfb, 0x92, 0xfa, 0x81, 0xe5, 0x3a, 0x71, 0x3d, 0x76, 0xab, 0x0b, + 0x5a, 0x5e, 0x12, 0xdb, 0x32, 0x09, 0x73, 0x7d, 0x81, 0xd0, 0x7e, 0x08, 0xc5, 0x0e, 0xf1, 0x59, + 0x97, 0xb2, 0x53, 0x4a, 0x4c, 0xea, 0xab, 0xdb, 0xb0, 0xce, 0x5c, 0x46, 0xec, 0xb2, 0x52, 0x55, + 0xf6, 0x8b, 0xba, 0x58, 0xa8, 0x2a, 0xa4, 0x46, 0x24, 0x18, 0x95, 0x13, 0x55, 0x65, 0xbf, 0xa0, + 0xe3, 0xb7, 0x36, 0x82, 0x14, 0x17, 0xe5, 0x12, 0x96, 0x63, 0xd2, 0x69, 0x28, 0x81, 0x0b, 0x4e, + 0xed, 0x5f, 0x31, 0x1a, 0x48, 0x11, 0xb1, 0x50, 0xbf, 0x0b, 0xeb, 0xa8, 0x7f, 0x39, 0x59, 0x55, + 0xf6, 0xf3, 0x87, 0xe5, 0x5a, 0xcc, 0x50, 0xe2, 0x7e, 0xb5, 0x0e, 0xe7, 0x37, 0x52, 0x5f, 0xbc, + 0xdc, 0x5b, 0xd3, 0x05, 0x58, 0xb3, 0x21, 0xd3, 0xb0, 0xdd, 0xc1, 0xd3, 0xe6, 0x71, 0xa4, 0x88, + 0x32, 0x53, 0x44, 0x6d, 0xc1, 0xa6, 0x47, 0x7c, 0x66, 0x04, 0x94, 0x19, 0x23, 0xbc, 0x05, 0x1e, + 0x9a, 0x3f, 0xdc, 0xab, 0xdd, 0xf6, 0x43, 0x6d, 0xee, 0xb2, 0xf2, 0x94, 0xa2, 0x17, 0x27, 0x6a, + 0xff, 0x4e, 0x41, 0x5a, 0x1a, 0xe3, 0xc7, 0x90, 0x91, 0x66, 0xc5, 0x03, 0xf3, 0x87, 0x0f, 0xe3, + 0x3b, 0x4a, 0x56, 0xed, 0xc8, 0x75, 0x02, 0xea, 0x04, 0x93, 0x40, 0xee, 0x17, 0xca, 0xa8, 0xdf, + 0x82, 0xec, 0x60, 0x44, 0x2c, 0xc7, 0xb0, 0x4c, 0xd4, 0x28, 0xd7, 0xc8, 0xbf, 0x7a, 0xb9, 0x97, + 0x39, 0xe2, 0xb4, 0xe6, 0xb1, 0x9e, 0x41, 0x66, 0xd3, 0x54, 0xef, 0x42, 0x7a, 0x44, 0xad, 0xe1, + 0x88, 0xa1, 0x59, 0x92, 0xba, 0x5c, 0xa9, 0x3f, 0x80, 0x14, 0x0f, 0x88, 0x72, 0x0a, 0xcf, 0xde, + 0xad, 0x89, 0x68, 0xa9, 0x85, 0xd1, 0x52, 0xeb, 0x85, 0xd1, 0xd2, 0xc8, 0xf2, 0x83, 0x5f, 0xfc, + 0x63, 0x4f, 0xd1, 0x51, 0x42, 0x3d, 0x82, 0xa2, 0x4d, 0x02, 0x66, 0xf4, 0xb9, 0xd9, 0xf8, 0xf1, + 0xeb, 0xb8, 0xc5, 0xce, 0xa2, 0x41, 0xa4, 0x61, 0xa5, 0xea, 0x79, 0x2e, 0x25, 0x48, 0xa6, 0xba, + 0x0f, 0x25, 0xdc, 0x64, 0xe0, 0x8e, 0xc7, 0x16, 0x33, 0xd0, 0xee, 0x69, 0xb4, 0xfb, 0x06, 0xa7, + 0x1f, 0x21, 0xf9, 0x94, 0x7b, 0xe0, 0x3e, 0xe4, 0x4c, 0xc2, 0x88, 0x80, 0x64, 0x10, 0x92, 0xe5, + 0x04, 0x64, 0xbe, 0x07, 0x9b, 0x51, 0xd4, 0x05, 0x02, 0x92, 0x15, 0xbb, 0xcc, 0xc8, 0x08, 0x7c, + 0x04, 0xdb, 0x0e, 0x9d, 0x32, 0xe3, 0x36, 0x3a, 0x87, 0x68, 0x95, 0xf3, 0x9e, 0xcc, 0x4b, 0x7c, + 0x13, 0x36, 0x06, 0xa1, 0xf1, 0x05, 0x16, 0x10, 0x5b, 0x8c, 0xa8, 0x08, 0xdb, 0x81, 0x2c, 0xf1, + 0x3c, 0x01, 0xc8, 0x23, 0x20, 0x43, 0x3c, 0x0f, 0x59, 0x1f, 0xc0, 0x16, 0xde, 0xd1, 0xa7, 0xc1, + 0xc4, 0x66, 0x72, 0x93, 0x02, 0x62, 0x36, 0x39, 0x43, 0x17, 0x74, 0xc4, 0x7e, 0x03, 0x8a, 0xf4, + 0xd2, 0x32, 0xa9, 0x33, 0xa0, 0x02, 0x57, 0x44, 0x5c, 0x21, 0x24, 0x22, 0xe8, 0x7d, 0x28, 0x79, + 0xbe, 0xeb, 0xb9, 0x01, 0xf5, 0x0d, 0x62, 0x9a, 0x3e, 0x0d, 0x82, 0xf2, 0x86, 0xd8, 0x2f, 0xa4, + 0xd7, 0x05, 0x59, 0x7b, 0xa9, 0x40, 0xea, 0x98, 0x30, 0xa2, 0x96, 0x20, 0xc9, 0xa6, 0x41, 0x59, + 0xa9, 0x26, 0xf7, 0x0b, 0x3a, 0xff, 0x54, 0x7f, 0x0a, 0xd9, 0x70, 0x57, 0x99, 0x2a, 0x95, 0x45, + 0xd7, 0x9d, 0x48, 0xc4, 0x99, 0x15, 0x30, 0xe9, 0xbf, 0x48, 0x4a, 0xfd, 0x11, 0x64, 0xc7, 0x34, + 0x08, 0xc8, 0x90, 0x06, 0x51, 0xfc, 0x2c, 0xec, 0xd0, 0x92, 0x88, 0x50, 0x3a, 0x94, 0xe0, 0xae, + 0x70, 0x7d, 0x6b, 0x68, 0x39, 0xc4, 0x36, 0x82, 0x5f, 0x4f, 0x88, 0x4f, 0x8d, 0xc0, 0x7a, 0x4e, + 0x31, 0x8c, 0x52, 0xba, 0x1a, 0xf2, 0xba, 0xc8, 0xea, 0x5a, 0xcf, 0x69, 0x94, 0x98, 0xe9, 0x58, + 0x85, 0x78, 0x91, 0x80, 0x3b, 0xc7, 0x13, 0xcf, 0xb6, 0x06, 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, 0xea, 0x11, 0xbc, 0x2f, 0x13, 0xfb, 0x8d, 0xf0, 0x86, 0xfa, 0x11, 0xa8, 0x58, + 0xb6, 0x8c, 0x4b, 0x97, 0x59, 0xce, 0xd0, 0xf0, 0xdc, 0x67, 0xd4, 0x97, 0xb9, 0x55, 0x42, 0xce, + 0x13, 0x64, 0x74, 0x38, 0x7d, 0x2e, 0x3e, 0x25, 0x34, 0x85, 0xd0, 0x59, 0x7c, 0x0a, 0x60, 0x03, + 0x72, 0x51, 0x7d, 0x96, 0x09, 0xf5, 0xff, 0xe5, 0xe4, 0x4c, 0x4c, 0xfb, 0x4b, 0x02, 0x76, 0xce, + 0x78, 0x72, 0x1f, 0xd9, 0x16, 0x75, 0x58, 0x9d, 0x31, 0x32, 0x78, 0x1a, 0x99, 0xa5, 0x09, 0x5b, + 0x03, 0xd7, 0xb9, 0xb0, 0xad, 0x01, 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, 0x2a, 0x0a, 0x4c, 0x1b, 0xb6, 0xfb, 0x57, 0xcf, 0x89, 0xc3, + 0x2c, 0x87, 0xc6, 0xd2, 0xae, 0x9c, 0xac, 0x26, 0xf7, 0xf3, 0x87, 0xf7, 0x97, 0x58, 0x39, 0xc4, + 0xe8, 0x5f, 0x8b, 0x04, 0x67, 0x39, 0xb9, 0xc2, 0xf0, 0xa9, 0x15, 0x86, 0x7f, 0x17, 0xf6, 0xfc, + 0x97, 0x02, 0xd9, 0xc8, 0x7c, 0x04, 0xee, 0x99, 0x61, 0xb8, 0x19, 0x18, 0x30, 0x51, 0x12, 0x09, + 0x23, 0xbe, 0xb7, 0x78, 0xa3, 0xa5, 0xf1, 0x79, 0xba, 0xa6, 0xdf, 0x31, 0x97, 0x06, 0xae, 0x03, + 0x0f, 0x6c, 0x6e, 0x3a, 0x63, 0x80, 0xfe, 0x33, 0x08, 0x3a, 0x70, 0x76, 0x8e, 0x88, 0xcf, 0x0f, + 0x57, 0x38, 0x6b, 0x99, 0xd3, 0x4f, 0xd7, 0xf4, 0x1d, 0x7b, 0x15, 0xb3, 0xb1, 0x0e, 0xc9, 0x60, + 0x32, 0xd6, 0xce, 0xa0, 0x10, 0xcf, 0x76, 0x9e, 0xdd, 0xb1, 0xab, 0x25, 0x97, 0x67, 0x77, 0xb4, + 0xc9, 0xad, 0xda, 0xa0, 0xfd, 0x0c, 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, 0x87, + 0x8c, 0x64, 0xa8, 0x5f, 0x87, 0x82, 0x43, 0xc6, 0x34, 0xf0, 0xc8, 0x80, 0xf2, 0x9e, 0x23, 0x7a, + 0x74, 0x3e, 0xa2, 0x35, 0x4d, 0x5e, 0x25, 0x78, 0x5f, 0x08, 0xe7, 0x08, 0xfe, 0xad, 0x96, 0x67, + 0x4d, 0x36, 0x89, 0x13, 0x44, 0xb8, 0xd4, 0x7e, 0x09, 0x77, 0x79, 0x7d, 0xac, 0x5f, 0x12, 0xcb, + 0x26, 0x7d, 0xcb, 0xb6, 0xd8, 0x95, 0x6c, 0xcc, 0xf7, 0x21, 0xe7, 0xbb, 0xcf, 0x0c, 0xdf, 0x75, + 0x59, 0x58, 0x37, 0xb3, 0xbe, 0xfb, 0x4c, 0xe7, 0x6b, 0xae, 0xc7, 0xc0, 0xb5, 0x27, 0x63, 0x47, + 0xf2, 0x13, 0xc8, 0xcf, 0x0b, 0x1a, 0x42, 0xb4, 0xff, 0x24, 0x20, 0xc5, 0xfd, 0xaa, 0x7e, 0x0c, + 0x29, 0x7e, 0x3b, 0xd4, 0x75, 0x63, 0xd9, 0xc0, 0xd0, 0xb5, 0x86, 0x0e, 0x35, 0x5b, 0xc1, 0xb0, + 0x77, 0xe5, 0x51, 0x1d, 0xc1, 0xb1, 0x7e, 0x9d, 0x98, 0xeb, 0xd7, 0xdb, 0xb0, 0xee, 0xbb, 0x13, + 0xc7, 0xc4, 0x7b, 0xac, 0xeb, 0x62, 0xa1, 0x9e, 0x40, 0x36, 0x6a, 0xc3, 0xa9, 0xff, 0xd5, 0x86, + 0x37, 0xb9, 0xab, 0xf8, 0x90, 0x20, 0x09, 0x7a, 0xa6, 0x2f, 0xbb, 0xf1, 0x3b, 0xc8, 0x16, 0xf5, + 0x43, 0xd8, 0x9a, 0x95, 0xba, 0xb0, 0x3b, 0x89, 0x8a, 0x5d, 0x8a, 0x18, 0xb2, 0x3d, 0xcd, 0xd7, + 0x45, 0x31, 0xe1, 0x65, 0xf0, 0x5e, 0xb3, 0xba, 0xd8, 0xc4, 0x51, 0xef, 0x01, 0xe4, 0x02, 0x6b, + 0xe8, 0x10, 0x36, 0xf1, 0xa9, 0x6c, 0xed, 0x33, 0x82, 0xf6, 0x27, 0x05, 0xd2, 0x62, 0x54, 0x88, + 0xd9, 0x4d, 0x59, 0x6e, 0xb7, 0xc4, 0x2a, 0xbb, 0x25, 0xdf, 0xde, 0x6e, 0x75, 0x80, 0x48, 0x19, + 0xde, 0x0a, 0x57, 0x54, 0x36, 0xa1, 0x62, 0xd7, 0x1a, 0xca, 0x6c, 0x89, 0x09, 0x69, 0x7f, 0x57, + 0x20, 0x17, 0xf1, 0xd5, 0x3a, 0x14, 0x43, 0xbd, 0x8c, 0x0b, 0x9b, 0x0c, 0x65, 0xec, 0x3c, 0x5c, + 0xa9, 0xdc, 0x27, 0x36, 0x19, 0xea, 0x79, 0xa9, 0x0f, 0x5f, 0x2c, 0xf7, 0x43, 0x62, 0x85, 0x1f, + 0xe6, 0x1c, 0x9f, 0x7c, 0x3b, 0xc7, 0xcf, 0xb9, 0x28, 0x75, 0xdb, 0x45, 0x7f, 0x4c, 0x40, 0xb6, + 0x83, 0xc3, 0x09, 0xb1, 0xbf, 0x8a, 0x8c, 0xb8, 0x0f, 0x39, 0xcf, 0xb5, 0x0d, 0xc1, 0x49, 0x21, + 0x27, 0xeb, 0xb9, 0xb6, 0xbe, 0xe0, 0xf6, 0xf5, 0x77, 0x94, 0x2e, 0xe9, 0x77, 0x60, 0xb5, 0xcc, + 0x6d, 0xab, 0xf9, 0x50, 0x10, 0xa6, 0x90, 0x35, 0xe9, 0x11, 0xb7, 0x01, 0xbe, 0x3e, 0x94, 0xc5, + 0xc7, 0x8d, 0x50, 0x5b, 0x20, 0x75, 0x89, 0xe3, 0x12, 0x62, 0xb6, 0x96, 0x6d, 0xa3, 0xbc, 0x2a, + 0x2c, 0x75, 0x89, 0xd3, 0x7e, 0xab, 0x00, 0xcc, 0xda, 0x3e, 0x1f, 0xf3, 0x03, 0x54, 0xc1, 0x98, + 0x3b, 0xb9, 0xb2, 0xca, 0x69, 0xf2, 0xfc, 0x42, 0x10, 0xd7, 0xfb, 0x08, 0x8a, 0xb3, 0x60, 0x0c, + 0x68, 0xa8, 0x4c, 0xe5, 0x0d, 0xdd, 0xbf, 0x4b, 0x99, 0x5e, 0xb8, 0x8c, 0xad, 0xb4, 0x3f, 0x2b, + 0x90, 0x43, 0x9d, 0x5a, 0x94, 0x91, 0x39, 0x1f, 0x2a, 0x6f, 0xef, 0xc3, 0x87, 0x00, 0x62, 0x1b, + 0x9c, 0x3d, 0x45, 0x64, 0xe5, 0x90, 0x82, 0x23, 0xe7, 0xf7, 0x22, 0x83, 0x27, 0xdf, 0x6c, 0x70, + 0x99, 0xd2, 0xa1, 0xd9, 0xef, 0x41, 0xc6, 0x99, 0x8c, 0x0d, 0x3e, 0x72, 0x8b, 0xd1, 0x24, 0xed, + 0x4c, 0xc6, 0xbd, 0x69, 0xa0, 0x39, 0x90, 0xe9, 0x4d, 0xf1, 0xfd, 0xf9, 0xe6, 0x06, 0x33, 0xeb, + 0x62, 0xc9, 0xa8, 0x8b, 0x1d, 0x42, 0x1a, 0x1f, 0xab, 0xe1, 0xf0, 0xb4, 0xa4, 0x1f, 0xb7, 0x5b, + 0x3d, 0xdc, 0x5c, 0x97, 0x48, 0x6d, 0x04, 0xf9, 0x16, 0xb1, 0x6d, 0x4a, 0x18, 0x35, 0x7b, 0x53, + 0xfe, 0xde, 0x8a, 0x86, 0x6e, 0x36, 0x35, 0x62, 0xef, 0xdc, 0x8d, 0x90, 0xde, 0x9b, 0xe2, 0x23, + 0x63, 0x03, 0x12, 0x6c, 0x2a, 0x0b, 0x46, 0x82, 0x4d, 0xd5, 0x3d, 0xc8, 0x07, 0x23, 0x3e, 0xa4, + 0x8b, 0x32, 0x2d, 0xda, 0x28, 0x20, 0x09, 0x4b, 0xb4, 0x46, 0x21, 0x1b, 0x9e, 0xce, 0x73, 0x32, + 0x60, 0xc4, 0x17, 0x45, 0x78, 0x5d, 0x17, 0x0b, 0xfe, 0x06, 0xa1, 0x51, 0x05, 0xe6, 0x9f, 0x1c, + 0xe7, 0xb8, 0x26, 0x15, 0x17, 0x2a, 0xe8, 0x62, 0xc1, 0x0d, 0x63, 0x53, 0x72, 0x21, 0xb4, 0x13, + 0x95, 0x24, 0xcb, 0x09, 0x5c, 0xaf, 0x0f, 0xfe, 0xaa, 0x40, 0x3e, 0x56, 0xf4, 0xd4, 0xef, 0xc0, + 0x9d, 0xc6, 0xd9, 0xf9, 0xd1, 0xa7, 0x46, 0xf3, 0xd8, 0xf8, 0xe4, 0xac, 0xfe, 0xd8, 0xf8, 0xac, + 0xfd, 0x69, 0xfb, 0xfc, 0x17, 0xed, 0xd2, 0xda, 0xee, 0xdd, 0xeb, 0x9b, 0xaa, 0x1a, 0xc3, 0x7e, + 0xe6, 0x3c, 0x75, 0xdc, 0x67, 0x8e, 0x7a, 0x00, 0xdb, 0xf3, 0x22, 0xf5, 0x46, 0xf7, 0xa4, 0xdd, + 0x2b, 0x29, 0xbb, 0x77, 0xae, 0x6f, 0xaa, 0x5b, 0x31, 0x89, 0x7a, 0x3f, 0xa0, 0x0e, 0x5b, 0x14, + 0x38, 0x3a, 0x6f, 0xb5, 0x9a, 0xbd, 0x52, 0x62, 0x41, 0x40, 0x76, 0xa1, 0xf7, 0x61, 0x6b, 0x5e, + 0xa0, 0xdd, 0x3c, 0x2b, 0x25, 0x77, 0xd5, 0xeb, 0x9b, 0xea, 0x46, 0x0c, 0xdd, 0xb6, 0xec, 0xdd, + 0xec, 0x6f, 0x7e, 0x57, 0x59, 0xfb, 0xc3, 0xef, 0x2b, 0x0a, 0xbf, 0x59, 0x71, 0xae, 0xf0, 0xa9, + 0x1f, 0xc1, 0xbd, 0x6e, 0xf3, 0x71, 0xfb, 0xe4, 0xd8, 0x68, 0x75, 0x1f, 0x1b, 0xbd, 0x5f, 0x75, + 0x4e, 0x62, 0xb7, 0xdb, 0xbc, 0xbe, 0xa9, 0xe6, 0xe5, 0x95, 0x56, 0xa1, 0x3b, 0xfa, 0xc9, 0x93, + 0xf3, 0xde, 0x49, 0x49, 0x11, 0xe8, 0x8e, 0x4f, 0xf9, 0xc8, 0x8a, 0xe8, 0x47, 0xb0, 0xb3, 0x04, + 0x1d, 0x5d, 0x6c, 0xeb, 0xfa, 0xa6, 0x5a, 0xec, 0xf8, 0x54, 0x14, 0x05, 0x94, 0xa8, 0x41, 0x79, + 0x51, 0xe2, 0xbc, 0x73, 0xde, 0xad, 0x9f, 0x95, 0xaa, 0xbb, 0xa5, 0xeb, 0x9b, 0x6a, 0x21, 0xac, + 0xf0, 0x1c, 0x3f, 0xbb, 0x59, 0xe3, 0xe7, 0x5f, 0xbc, 0xaa, 0x28, 0x5f, 0xbe, 0xaa, 0x28, 0xff, + 0x7c, 0x55, 0x51, 0x5e, 0xbc, 0xae, 0xac, 0x7d, 0xf9, 0xba, 0xb2, 0xf6, 0xb7, 0xd7, 0x95, 0xb5, + 0xcf, 0xbf, 0x3f, 0xb4, 0xd8, 0x68, 0xd2, 0xaf, 0x0d, 0xdc, 0xf1, 0x41, 0xfc, 0x8f, 0xa4, 0xd9, + 0xa7, 0xf8, 0x43, 0xeb, 0xf6, 0x9f, 0x4c, 0xfd, 0x34, 0xd2, 0x3f, 0xfe, 0x6f, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x23, 0x81, 0xd4, 0x66, 0x25, 0x13, 0x00, 0x00, } func (m *PartSetHeader) Marshal() (dAtA []byte, err error) { @@ -2411,6 +2419,11 @@ func (m *Message) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Version != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x18 + } if len(m.Data) > 0 { i -= len(m.Data) copy(dAtA[i:], m.Data) @@ -3288,6 +3301,9 @@ func (m *Message) Size() (n int) { if l > 0 { n += 1 + l + sovTypes(uint64(l)) } + if m.Version != 0 { + n += 1 + sovTypes(uint64(m.Version)) + } return n } @@ -5382,6 +5398,25 @@ func (m *Message) Unmarshal(dAtA []byte) error { m.Data = []byte{} } iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) diff --git a/proto/tendermint/types/types.proto b/proto/tendermint/types/types.proto index 60fde2774e..79f0801c7b 100644 --- a/proto/tendermint/types/types.proto +++ b/proto/tendermint/types/types.proto @@ -130,8 +130,9 @@ message Messages { } message Message { - bytes namespace_id = 1; - bytes data = 2; + bytes namespace_id = 1; + bytes data = 2; + uint32 version = 3; } // DataAvailabilityHeader contains the row and column roots of the erasure diff --git a/types/block.go b/types/block.go index fe915a32c8..79e8b68a0a 100644 --- a/types/block.go +++ b/types/block.go @@ -1189,7 +1189,7 @@ func (msgs Messages) SplitIntoShares() NamespacedShares { if err != nil { panic(fmt.Sprintf("app accepted a Message that can not be encoded %#v", m)) } - shares = AppendToShares(shares, m.NamespaceID, rawData) + shares = AppendToShares(shares, m.NamespaceID, m.Version, rawData) } return shares } @@ -1215,6 +1215,10 @@ type Message struct { // Data is the actual data contained in the message // (e.g. a block of a virtual sidechain). Data []byte + + // Version defines the the message format specification version of this + // message. Version is a number between 0 and 127 (inclusive). + Version uint8 } var ( @@ -1226,9 +1230,14 @@ func MessageFromProto(p *tmproto.Message) Message { if p == nil { return MessageEmpty } + if p.Version > 127 { + // TODO (throw an error here) + return MessageEmpty + } return Message{ NamespaceID: p.NamespaceId, Data: p.Data, + Version: uint8(p.Version), } } @@ -1288,6 +1297,7 @@ func (data *Data) ToProto() tmproto.Data { protoMsgs[i] = &tmproto.Message{ NamespaceId: msg.NamespaceID, Data: msg.Data, + Version: uint32(msg.Version), } } tp.Messages = tmproto.Messages{MessagesList: protoMsgs} @@ -1319,7 +1329,7 @@ func DataFromProto(dp *tmproto.Data) (Data, error) { 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} + msgs[i] = Message{NamespaceID: m.NamespaceId, Data: m.Data, Version: uint8(m.Version)} } data.Messages = Messages{MessagesList: msgs} } else { diff --git a/types/block_test.go b/types/block_test.go index ae3ad0311f..9ce5d2e446 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -682,10 +682,12 @@ func TestBlockDataProtobuf(t *testing.T) { { NamespaceID: []byte{8, 7, 6, 5, 4, 3, 2, 1}, Data: stdbytes.Repeat([]byte{3, 2, 1, 0}, 100), + Version: uint8(0), }, { NamespaceID: []byte{1, 2, 3, 4, 5, 6, 7, 8}, Data: stdbytes.Repeat([]byte{1, 2, 3}, 100), + Version: uint8(0), }, }, }, diff --git a/types/info_reserved_byte.go b/types/info_reserved_byte.go new file mode 100644 index 0000000000..adf6c8a935 --- /dev/null +++ b/types/info_reserved_byte.go @@ -0,0 +1,33 @@ +package types + +import "fmt" + +// InfoReservedByte is a byte with the following structure: the first 7 bits are +// reserved for version information in big endian form (initially `0000000`). +// The last bit is a "message start indicator", that is `1` if the share is at +// the start of a message and `0` otherwise. +type InfoReservedByte byte + +func NewInfoReservedByte(version uint8, isMessageStart bool) (InfoReservedByte, error) { + if version > 127 { + return 0, fmt.Errorf("version %d must be less than or equal to 127", version) + } + + prefix := version << 1 + if isMessageStart { + return InfoReservedByte(prefix + 1), nil + } + return InfoReservedByte(prefix), nil +} + +// Version returns the version encoded in this InfoReservedByte. +// Version is expected to be between 0 and 127 (inclusive). +func (i InfoReservedByte) Version() uint8 { + version := uint8(i) >> 1 + return version +} + +// IsMessageStart returns whether this share is the start of a message. +func (i InfoReservedByte) IsMessageStart() bool { + return uint(i)%2 == 1 +} diff --git a/types/info_reserved_byte_test.go b/types/info_reserved_byte_test.go new file mode 100644 index 0000000000..dce71abd84 --- /dev/null +++ b/types/info_reserved_byte_test.go @@ -0,0 +1,40 @@ +package types + +import "testing" + +func TestInfoReservedByte(t *testing.T) { + type testCase struct { + version uint8 + isMessageStart bool + } + tests := []testCase{ + {0, false}, + {1, false}, + {2, false}, + {127, false}, + {0, true}, + {1, true}, + {2, true}, + {127, true}, + } + + for _, test := range tests { + irb, err := NewInfoReservedByte(test.version, test.isMessageStart) + if err != nil { + t.Errorf("got %v want no error", err) + } + if got := irb.Version(); got != test.version { + t.Errorf("got version %v want %v", got, test.version) + } + if got := irb.IsMessageStart(); got != test.isMessageStart { + t.Errorf("got isMessageStart %v want %v", got, test.isMessageStart) + } + } +} + +func TestNewInfoReservedByte(t *testing.T) { + _, err := NewInfoReservedByte(128, false) + if err == nil { + t.Errorf("got nil but want error when version > 127") + } +} diff --git a/types/share_merging.go b/types/share_merging.go deleted file mode 100644 index 73ac48ba2f..0000000000 --- a/types/share_merging.go +++ /dev/null @@ -1,307 +0,0 @@ -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 index f6c690e4de..a7c97972b3 100644 --- a/types/share_splitting.go +++ b/types/share_splitting.go @@ -28,7 +28,7 @@ func (msw *MessageShareWriter) Write(msg Message) { panic(fmt.Sprintf("app accepted a Message that can not be encoded %#v", msg)) } newShares := make([]NamespacedShare, 0) - newShares = AppendToShares(newShares, msg.NamespaceID, rawMsg) + newShares = AppendToShares(newShares, msg.NamespaceID, msg.Version, rawMsg) msw.shares = append(msw.shares, newShares) msw.count += len(newShares) } @@ -58,27 +58,33 @@ 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 { +// AppendToShares appends raw data as shares. Used for messages. +func AppendToShares(shares []NamespacedShare, nid namespace.ID, version uint8, rawData []byte) []NamespacedShare { if len(rawData) <= consts.MsgShareSize { - rawShare := append(append( - make([]byte, 0, len(nid)+len(rawData)), + isMessageStart := true + infoReservedByte, err := NewInfoReservedByte(version, isMessageStart) + if err != nil { + // TODO (propogate this error?) + panic(err) + } + rawShare := append(append(append( + make([]byte, 0, len(nid)+consts.InfoReservedBytes+len(rawData)), nid...), + byte(infoReservedByte)), rawData..., ) paddedShare := zeroPadIfNecessary(rawShare, consts.ShareSize) share := NamespacedShare{paddedShare, nid} shares = append(shares, share) } else { // len(rawData) > MsgShareSize - shares = append(shares, splitMessage(rawData, nid)...) + shares = append(shares, splitMessage(rawData, nid, version)...) } return shares } // splitMessage breaks the data in a message into the minimum number of // namespaced shares -func splitMessage(rawData []byte, nid namespace.ID) NamespacedShares { +func splitMessage(rawData []byte, nid namespace.ID, version uint8) NamespacedShares { shares := make([]NamespacedShare, 0) firstRawShare := append(append( make([]byte, 0, consts.ShareSize), diff --git a/types/shares.go b/types/shares.go index ac0b517009..f4b7b08381 100644 --- a/types/shares.go +++ b/types/shares.go @@ -15,6 +15,11 @@ type NamespacedShare struct { ID namespace.ID } +type MessageShare struct { + NamespacedShare + Info byte +} + func (n NamespacedShare) NamespaceID() namespace.ID { return n.ID } @@ -24,7 +29,7 @@ func (n NamespacedShare) Data() []byte { } // NamespacedShares is just a list of NamespacedShare elements. -// It can be used to extract the raw raw shares. +// It can be used to extract the raw shares. type NamespacedShares []NamespacedShare // RawShares returns the raw shares that can be fed into the erasure coding diff --git a/types/shares_test.go b/types/shares_test.go deleted file mode 100644 index 7d8881413b..0000000000 --- a/types/shares_test.go +++ /dev/null @@ -1,574 +0,0 @@ -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/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 }) -}