From ffda05299a7bd3339b7852960a1b72d162c674bc Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:18:57 +0100 Subject: [PATCH 01/55] feat: allow passing sign id used to sign vote extensions --- abci/types/types.pb.go | 568 ++++++++++++++++++------------ proto/tendermint/abci/types.proto | 5 + spec/abci++/api.md | 1 + 3 files changed, 346 insertions(+), 228 deletions(-) diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index f0fc0d9704..15b9d4ed81 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -1739,6 +1739,10 @@ type RequestVerifyVoteExtension struct { Round int32 `protobuf:"varint,4,opt,name=round,proto3" json:"round,omitempty"` // Application-specific information signed by Tenderdash. Can have 0 length. VoteExtensions []*ExtendVoteExtension `protobuf:"bytes,5,rep,name=vote_extensions,json=voteExtensions,proto3" json:"vote_extensions,omitempty"` + // Types that are valid to be assigned to XSignId: + // + // *RequestVerifyVoteExtension_SignId + XSignId isRequestVerifyVoteExtension_XSignId `protobuf_oneof:"_sign_id"` } func (m *RequestVerifyVoteExtension) Reset() { *m = RequestVerifyVoteExtension{} } @@ -1774,6 +1778,25 @@ func (m *RequestVerifyVoteExtension) XXX_DiscardUnknown() { var xxx_messageInfo_RequestVerifyVoteExtension proto.InternalMessageInfo +type isRequestVerifyVoteExtension_XSignId interface { + isRequestVerifyVoteExtension_XSignId() + MarshalTo([]byte) (int, error) + Size() int +} + +type RequestVerifyVoteExtension_SignId struct { + SignId []byte `protobuf:"bytes,6,opt,name=sign_id,json=signId,proto3,oneof" json:"sign_id,omitempty"` +} + +func (*RequestVerifyVoteExtension_SignId) isRequestVerifyVoteExtension_XSignId() {} + +func (m *RequestVerifyVoteExtension) GetXSignId() isRequestVerifyVoteExtension_XSignId { + if m != nil { + return m.XSignId + } + return nil +} + func (m *RequestVerifyVoteExtension) GetHash() []byte { if m != nil { return m.Hash @@ -1809,6 +1832,20 @@ func (m *RequestVerifyVoteExtension) GetVoteExtensions() []*ExtendVoteExtension return nil } +func (m *RequestVerifyVoteExtension) GetSignId() []byte { + if x, ok := m.GetXSignId().(*RequestVerifyVoteExtension_SignId); ok { + return x.SignId + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*RequestVerifyVoteExtension) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*RequestVerifyVoteExtension_SignId)(nil), + } +} + // Finalize newly decided block. // // #### Usage @@ -4278,234 +4315,236 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 3631 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5b, 0xcd, 0x73, 0x1b, 0xd7, - 0x91, 0xc7, 0xe0, 0x1b, 0x8d, 0xaf, 0xe1, 0x23, 0x25, 0x41, 0x90, 0x44, 0xd2, 0xa3, 0xb5, 0x25, - 0x6b, 0x6d, 0xd2, 0x96, 0xd6, 0x96, 0xbd, 0xf6, 0x6e, 0x15, 0x08, 0x42, 0x0b, 0x4a, 0x14, 0x49, - 0x0f, 0x41, 0xba, 0xbc, 0x5e, 0x7b, 0x6a, 0x08, 0x3c, 0x12, 0x63, 0x01, 0x98, 0xf1, 0xcc, 0x80, - 0x02, 0x7d, 0xdd, 0xf5, 0x1e, 0x7c, 0xf2, 0x3f, 0xe0, 0xdb, 0xee, 0x71, 0x2f, 0x7b, 0x4a, 0xe5, - 0x90, 0x54, 0x6e, 0x4e, 0xe5, 0xe2, 0x63, 0x2e, 0x51, 0x5c, 0xf2, 0x25, 0x95, 0x5b, 0x4e, 0xb9, - 0xa5, 0x52, 0xef, 0x63, 0x3e, 0x81, 0xc1, 0x87, 0xe5, 0xaa, 0x54, 0x6e, 0x78, 0xfd, 0xba, 0x7b, - 0xde, 0x47, 0xbf, 0xee, 0x7e, 0xbf, 0x7e, 0x80, 0x6b, 0x36, 0x1e, 0x74, 0xb0, 0xd9, 0xd7, 0x06, - 0xf6, 0xa6, 0x7a, 0xd2, 0xd6, 0x36, 0xed, 0x0b, 0x03, 0x5b, 0x1b, 0x86, 0xa9, 0xdb, 0x3a, 0x2a, - 0x7b, 0x9d, 0x1b, 0xa4, 0xb3, 0x7a, 0xc3, 0xc7, 0xdd, 0x36, 0x2f, 0x0c, 0x5b, 0xdf, 0x34, 0x4c, - 0x5d, 0x3f, 0x65, 0xfc, 0x55, 0xbf, 0x32, 0xaa, 0x67, 0xb3, 0xa3, 0x5a, 0x5d, 0xde, 0x79, 0x7d, - 0xac, 0xf3, 0xa4, 0xa7, 0xb7, 0x9f, 0x44, 0xf6, 0xfa, 0x06, 0x12, 0xe8, 0xe5, 0xdf, 0x7d, 0x82, - 0x2f, 0x9c, 0xde, 0x1b, 0x63, 0xb2, 0x86, 0x6a, 0xaa, 0x7d, 0xa7, 0x7b, 0xd5, 0xd7, 0x7d, 0x8e, - 0x4d, 0x4b, 0xd3, 0x07, 0x01, 0xe5, 0x6b, 0x67, 0xba, 0x7e, 0xd6, 0xc3, 0x9b, 0xb4, 0x75, 0x32, - 0x3c, 0xdd, 0xb4, 0xb5, 0x3e, 0xb6, 0x6c, 0xb5, 0x6f, 0x70, 0x86, 0x95, 0x33, 0xfd, 0x4c, 0xa7, - 0x3f, 0x37, 0xc9, 0x2f, 0x46, 0x95, 0xbe, 0xcc, 0x41, 0x46, 0xc6, 0x9f, 0x0f, 0xb1, 0x65, 0xa3, - 0xbb, 0x90, 0xc4, 0xed, 0xae, 0x5e, 0x11, 0xd6, 0x85, 0xdb, 0xf9, 0xbb, 0xd7, 0x37, 0x42, 0xeb, - 0xb6, 0xc1, 0xf9, 0x1a, 0xed, 0xae, 0xde, 0x8c, 0xc9, 0x94, 0x17, 0xbd, 0x05, 0xa9, 0xd3, 0xde, - 0xd0, 0xea, 0x56, 0xe2, 0x54, 0xe8, 0x46, 0x94, 0xd0, 0x03, 0xc2, 0xd4, 0x8c, 0xc9, 0x8c, 0x9b, - 0x7c, 0x4a, 0x1b, 0x9c, 0xea, 0x95, 0xc4, 0xf4, 0x4f, 0xed, 0x0c, 0x4e, 0xe9, 0xa7, 0x08, 0x2f, - 0xda, 0x02, 0xd0, 0x06, 0x9a, 0xad, 0xb4, 0xbb, 0xaa, 0x36, 0xa8, 0x24, 0xa9, 0xe4, 0x4b, 0xd1, - 0x92, 0x9a, 0x5d, 0x27, 0x8c, 0xcd, 0x98, 0x9c, 0xd3, 0x9c, 0x06, 0x19, 0xee, 0xe7, 0x43, 0x6c, - 0x5e, 0x54, 0x52, 0xd3, 0x87, 0xfb, 0x01, 0x61, 0x22, 0xc3, 0xa5, 0xdc, 0xe8, 0x7d, 0xc8, 0xb6, - 0xbb, 0xb8, 0xfd, 0x44, 0xb1, 0x47, 0x95, 0x0c, 0x95, 0x5c, 0x8b, 0x92, 0xac, 0x13, 0xbe, 0xd6, - 0xa8, 0x19, 0x93, 0x33, 0x6d, 0xf6, 0x13, 0xed, 0x41, 0xa9, 0xa7, 0x59, 0xb6, 0x62, 0x0d, 0x54, - 0xc3, 0xea, 0xea, 0xb6, 0x55, 0xc9, 0x53, 0x1d, 0x2f, 0x47, 0xe9, 0xd8, 0xd5, 0x2c, 0xfb, 0xd0, - 0x61, 0x6e, 0xc6, 0xe4, 0x62, 0xcf, 0x4f, 0x20, 0xfa, 0xf4, 0xd3, 0x53, 0x6c, 0xba, 0x0a, 0x2b, - 0x85, 0xe9, 0xfa, 0xf6, 0x09, 0xb7, 0x23, 0x4f, 0xf4, 0xe9, 0x7e, 0x02, 0xfa, 0x18, 0x96, 0x7b, - 0xba, 0xda, 0x71, 0xd5, 0x29, 0xed, 0xee, 0x70, 0xf0, 0xa4, 0x52, 0xa4, 0x4a, 0x5f, 0x8d, 0x1c, - 0xa4, 0xae, 0x76, 0x1c, 0x15, 0x75, 0x22, 0xd0, 0x8c, 0xc9, 0x4b, 0xbd, 0x30, 0x11, 0x7d, 0x0a, - 0x2b, 0xaa, 0x61, 0xf4, 0x2e, 0xc2, 0xda, 0x4b, 0x54, 0xfb, 0x9d, 0x28, 0xed, 0x35, 0x22, 0x13, - 0x56, 0x8f, 0xd4, 0x31, 0x2a, 0x6a, 0x81, 0x68, 0x98, 0xd8, 0x50, 0x4d, 0xac, 0x18, 0xa6, 0x6e, - 0xe8, 0x96, 0xda, 0xab, 0x94, 0xa9, 0xee, 0x5b, 0x51, 0xba, 0x0f, 0x18, 0xff, 0x01, 0x67, 0x6f, - 0xc6, 0xe4, 0xb2, 0x11, 0x24, 0x31, 0xad, 0x7a, 0x1b, 0x5b, 0x96, 0xa7, 0x55, 0x9c, 0xa5, 0x95, - 0xf2, 0x07, 0xb5, 0x06, 0x48, 0xa8, 0x01, 0x79, 0x3c, 0x22, 0xe2, 0xca, 0xb9, 0x6e, 0xe3, 0xca, - 0x12, 0x55, 0x28, 0x45, 0x9e, 0x33, 0xca, 0x7a, 0xac, 0xdb, 0xb8, 0x19, 0x93, 0x01, 0xbb, 0x2d, - 0xa4, 0xc2, 0xa5, 0x73, 0x6c, 0x6a, 0xa7, 0x17, 0x54, 0x8d, 0x42, 0x7b, 0x88, 0x3f, 0xa8, 0x20, - 0xaa, 0xf0, 0x1f, 0xa3, 0x14, 0x1e, 0x53, 0x21, 0xa2, 0xa2, 0xe1, 0x88, 0x34, 0x63, 0xf2, 0xf2, - 0xf9, 0x38, 0x99, 0x98, 0xd8, 0xa9, 0x36, 0x50, 0x7b, 0xda, 0x17, 0x58, 0xa1, 0x0e, 0xae, 0xb2, - 0x3c, 0xdd, 0xc4, 0x1e, 0x70, 0xee, 0x2d, 0xc2, 0x4c, 0x4c, 0xec, 0xd4, 0x4f, 0xd8, 0xca, 0x40, - 0xea, 0x5c, 0xed, 0x0d, 0xf1, 0xc3, 0x64, 0x36, 0x2d, 0x66, 0x1e, 0x26, 0xb3, 0x59, 0x31, 0xf7, - 0x30, 0x99, 0xcd, 0x89, 0xf0, 0x30, 0x99, 0x05, 0x31, 0x2f, 0xdd, 0x82, 0xbc, 0xcf, 0xbd, 0xa0, - 0x0a, 0x64, 0xfa, 0xd8, 0xb2, 0xd4, 0x33, 0x4c, 0xbd, 0x51, 0x4e, 0x76, 0x9a, 0x52, 0x09, 0x0a, - 0x7e, 0x97, 0x22, 0x7d, 0x2d, 0xb8, 0x92, 0xc4, 0x5b, 0x10, 0x49, 0xee, 0x1e, 0x1d, 0x49, 0xde, - 0x44, 0x37, 0xa1, 0x48, 0xa7, 0xa2, 0x38, 0xfd, 0xc4, 0x65, 0x25, 0xe5, 0x02, 0x25, 0x1e, 0x73, - 0xa6, 0x35, 0xc8, 0x1b, 0x77, 0x0d, 0x97, 0x25, 0x41, 0x59, 0xc0, 0xb8, 0x6b, 0x38, 0x0c, 0x2f, - 0x41, 0x81, 0xcc, 0xdb, 0xe5, 0x48, 0xd2, 0x8f, 0xe4, 0x09, 0x8d, 0xb3, 0x48, 0xff, 0x95, 0x00, - 0x31, 0xec, 0x86, 0xd0, 0x3b, 0x90, 0x24, 0x1e, 0x99, 0x3b, 0xd7, 0xea, 0x06, 0x73, 0xd7, 0x1b, - 0x8e, 0xbb, 0xde, 0x68, 0x39, 0xee, 0x7a, 0x2b, 0xfb, 0xed, 0xb3, 0xb5, 0xd8, 0xd7, 0xbf, 0x5f, - 0x13, 0x64, 0x2a, 0x81, 0xae, 0x12, 0xe7, 0xa3, 0x6a, 0x03, 0x45, 0xeb, 0xd0, 0x21, 0xe7, 0x88, - 0x67, 0x51, 0xb5, 0xc1, 0x4e, 0x07, 0xed, 0x82, 0xd8, 0xd6, 0x07, 0x16, 0x1e, 0x58, 0x43, 0x4b, - 0x61, 0xe1, 0x82, 0xbb, 0xd4, 0x80, 0x63, 0x64, 0x71, 0xa2, 0xee, 0x70, 0x1e, 0x50, 0x46, 0xb9, - 0xdc, 0x0e, 0x12, 0xd0, 0x1e, 0x14, 0xcf, 0xd5, 0x9e, 0xd6, 0x51, 0x6d, 0xdd, 0x54, 0x2c, 0x6c, - 0x73, 0x1f, 0x7b, 0x73, 0x6c, 0xcf, 0x8f, 0x1d, 0xae, 0x43, 0x6c, 0x1f, 0x19, 0x1d, 0xd5, 0xc6, - 0x5b, 0xc9, 0x6f, 0x9f, 0xad, 0x09, 0x72, 0xe1, 0xdc, 0xd7, 0x83, 0x5e, 0x81, 0xb2, 0x6a, 0x18, - 0x8a, 0x65, 0xab, 0x36, 0x56, 0x4e, 0x2e, 0x6c, 0x6c, 0x51, 0xb7, 0x5b, 0x90, 0x8b, 0xaa, 0x61, - 0x1c, 0x12, 0xea, 0x16, 0x21, 0xa2, 0x97, 0xa1, 0x44, 0x3c, 0xb4, 0xa6, 0xf6, 0x94, 0x2e, 0xd6, - 0xce, 0xba, 0x76, 0x25, 0xbd, 0x2e, 0xdc, 0x4e, 0xc8, 0x45, 0x4e, 0x6d, 0x52, 0x22, 0xda, 0x80, - 0x65, 0x87, 0xad, 0xad, 0x9b, 0xd8, 0xe1, 0x25, 0xfe, 0xb8, 0x28, 0x2f, 0xf1, 0xae, 0xba, 0x6e, - 0x62, 0xc6, 0x2f, 0x75, 0x5c, 0x4b, 0xa1, 0xde, 0x1c, 0x21, 0x48, 0x76, 0x54, 0x5b, 0xa5, 0x3b, - 0x50, 0x90, 0xe9, 0x6f, 0x42, 0x33, 0x54, 0xbb, 0xcb, 0xd7, 0x95, 0xfe, 0x46, 0x97, 0x21, 0xcd, - 0x55, 0x27, 0xe8, 0x30, 0x78, 0x0b, 0xad, 0x40, 0xca, 0x30, 0xf5, 0x73, 0x4c, 0x97, 0x25, 0x2b, - 0xb3, 0x86, 0x24, 0x43, 0x29, 0xe8, 0xf9, 0x51, 0x09, 0xe2, 0xf6, 0x88, 0x7f, 0x25, 0x6e, 0x8f, - 0xd0, 0x1b, 0x90, 0x24, 0x1b, 0x40, 0xbf, 0x51, 0x9a, 0x10, 0xeb, 0xb8, 0x5c, 0xeb, 0xc2, 0xc0, - 0x32, 0xe5, 0x94, 0x2e, 0xc3, 0xca, 0xa4, 0x48, 0x20, 0x75, 0x5d, 0x7a, 0xc0, 0xa3, 0xa3, 0xb7, - 0x20, 0xeb, 0x86, 0x02, 0x66, 0x5f, 0x57, 0xc7, 0xbe, 0xe2, 0x30, 0xcb, 0x2e, 0x2b, 0x31, 0x2c, - 0xb2, 0x3f, 0x5d, 0x95, 0x87, 0xef, 0x82, 0x9c, 0x51, 0x0d, 0xa3, 0xa9, 0x5a, 0x5d, 0xe9, 0x0c, - 0x2a, 0x51, 0x6e, 0xde, 0xb7, 0x3e, 0x02, 0x3d, 0x1d, 0xce, 0xfa, 0xf8, 0x4e, 0x5e, 0x9c, 0xee, - 0x89, 0x7b, 0xf2, 0xa8, 0x05, 0x0f, 0x07, 0x4f, 0x88, 0x05, 0x27, 0xd8, 0x87, 0x68, 0x7b, 0xa7, - 0x23, 0x75, 0xe0, 0x6a, 0xa4, 0xc7, 0x0f, 0xc8, 0x09, 0x01, 0x39, 0xb2, 0x19, 0x2c, 0x8e, 0xb0, - 0x81, 0xb3, 0x06, 0x19, 0x9a, 0x45, 0xe7, 0x4d, 0x3f, 0x93, 0x93, 0x79, 0x4b, 0xfa, 0x53, 0x12, - 0x2e, 0x4f, 0x76, 0xfe, 0x68, 0x1d, 0x0a, 0x7d, 0x75, 0xa4, 0xd8, 0x23, 0x6e, 0xa1, 0x02, 0xdd, - 0x73, 0xe8, 0xab, 0xa3, 0xd6, 0x88, 0x99, 0xa7, 0x08, 0x09, 0x7b, 0x64, 0x55, 0xe2, 0xeb, 0x89, - 0xdb, 0x05, 0x99, 0xfc, 0x44, 0x8f, 0x61, 0xa9, 0xa7, 0xb7, 0xd5, 0x9e, 0xd2, 0x53, 0x2d, 0x5b, - 0x69, 0xeb, 0xfd, 0xbe, 0x66, 0xf3, 0x73, 0x77, 0x6d, 0x7c, 0x7b, 0x69, 0x37, 0xf1, 0x4d, 0xf4, - 0x90, 0xc4, 0xe4, 0x32, 0x95, 0xdd, 0x55, 0x2d, 0x9b, 0x75, 0xa1, 0x6d, 0xc8, 0xf7, 0x35, 0xeb, - 0x04, 0x77, 0xd5, 0x73, 0x4d, 0x37, 0x2b, 0xc9, 0xf5, 0xc4, 0xc4, 0x9c, 0xe8, 0xb1, 0xc7, 0xc3, - 0x35, 0xf9, 0xc5, 0x7c, 0xdb, 0x92, 0x0a, 0x98, 0xad, 0xe3, 0x78, 0xd2, 0x0b, 0x3b, 0x9e, 0x37, - 0x60, 0x65, 0x80, 0x47, 0xb6, 0xe2, 0x1e, 0x6a, 0x8b, 0xd9, 0x4a, 0x86, 0x2e, 0x39, 0x22, 0x7d, - 0xae, 0x27, 0xb0, 0x88, 0xd9, 0x90, 0x5d, 0x31, 0xf5, 0xe1, 0xa0, 0x53, 0xc9, 0xae, 0x0b, 0xb7, - 0x53, 0x32, 0x6b, 0xa0, 0xfb, 0x50, 0xa1, 0x07, 0x96, 0x79, 0x31, 0xe2, 0x6d, 0x71, 0xc7, 0x39, - 0xbd, 0x39, 0x6a, 0x29, 0x97, 0x48, 0x3f, 0xf5, 0x93, 0xbb, 0xb4, 0x97, 0x9f, 0xf8, 0x4d, 0x58, - 0x61, 0xd1, 0x17, 0x9b, 0x24, 0x0c, 0x93, 0x4d, 0xa2, 0x03, 0x00, 0x3a, 0x80, 0x25, 0xa7, 0xef, - 0xc0, 0xd4, 0x5b, 0x23, 0xfa, 0xfd, 0x37, 0x5c, 0x81, 0x8e, 0x42, 0x4c, 0xdb, 0xb1, 0xc7, 0x3c, - 0x35, 0x54, 0xe4, 0xf4, 0xd5, 0x0c, 0xd7, 0x9d, 0xdf, 0xf7, 0x8c, 0xb6, 0x30, 0x9e, 0x12, 0xf2, - 0x2e, 0xcf, 0x75, 0x7a, 0x36, 0xbd, 0x06, 0xf9, 0xcf, 0x87, 0xba, 0x39, 0xec, 0xb3, 0x21, 0x15, - 0xe9, 0x90, 0x80, 0x91, 0xe8, 0x11, 0xfa, 0x65, 0xca, 0x67, 0x73, 0xc1, 0x3c, 0x80, 0x5b, 0x94, - 0xe0, 0x59, 0xd4, 0xa1, 0x6f, 0xe0, 0x7e, 0xa3, 0x8a, 0xcf, 0x6b, 0x54, 0xee, 0xdc, 0xa2, 0xed, - 0x2a, 0xf1, 0xe3, 0xec, 0x0a, 0x41, 0x92, 0xce, 0x30, 0xc9, 0xdc, 0x26, 0xf9, 0x1d, 0x69, 0x6b, - 0xee, 0xfe, 0xa7, 0xfd, 0xfb, 0xef, 0x58, 0x60, 0xe6, 0x27, 0xb3, 0xc0, 0x6c, 0xa4, 0x05, 0xfe, - 0x68, 0x5b, 0x6b, 0xc1, 0xe5, 0x90, 0xa0, 0x32, 0xa4, 0xa1, 0x8d, 0x5a, 0x5b, 0x28, 0xe1, 0x77, - 0x02, 0xaa, 0x4f, 0x91, 0xbc, 0x1c, 0xd0, 0xcb, 0xc2, 0x62, 0xa4, 0x05, 0xe7, 0x17, 0xb5, 0xe0, - 0xc2, 0x3c, 0x16, 0x5c, 0x7c, 0x11, 0x0b, 0x2e, 0x8d, 0x59, 0xf0, 0x11, 0x2c, 0x8d, 0xa5, 0xa2, - 0xae, 0x39, 0x08, 0x13, 0xcd, 0x21, 0x3e, 0xd9, 0x1c, 0x12, 0x3e, 0x73, 0x90, 0xbe, 0x17, 0xa0, - 0x1a, 0x9d, 0x91, 0x4e, 0xfc, 0xc0, 0x9b, 0x70, 0xc9, 0xcb, 0x4c, 0xfc, 0xeb, 0xc8, 0xbc, 0x3f, - 0x72, 0x3b, 0xbd, 0x85, 0x9c, 0x12, 0xc5, 0xd9, 0x98, 0x92, 0x7e, 0x13, 0x7d, 0x0c, 0xe5, 0x60, - 0x2e, 0x4d, 0x52, 0x15, 0x72, 0x5c, 0xfe, 0x61, 0xec, 0xb8, 0x78, 0x6b, 0xe1, 0x8e, 0x59, 0x2e, - 0x9d, 0xfb, 0x9b, 0x96, 0xf4, 0x9b, 0xb8, 0x1b, 0xa9, 0x03, 0x89, 0x31, 0x7a, 0x17, 0xd2, 0xfc, - 0x64, 0x0b, 0xf3, 0x9e, 0x6c, 0x2e, 0x10, 0x3e, 0xcd, 0xf1, 0x17, 0x3b, 0xcd, 0x89, 0x89, 0xdb, - 0x97, 0x9c, 0xbc, 0x54, 0x29, 0xff, 0x52, 0xbd, 0x0e, 0x29, 0x76, 0x23, 0x60, 0x01, 0xe5, 0xca, - 0xf8, 0xb9, 0xa0, 0x53, 0x95, 0x19, 0x17, 0xaa, 0x41, 0x96, 0x65, 0xdd, 0x5a, 0x87, 0x3b, 0x80, - 0xab, 0x11, 0x12, 0x3b, 0xdb, 0x5b, 0xf9, 0xe7, 0xcf, 0xd6, 0x32, 0xbc, 0x21, 0x67, 0xa8, 0xdc, - 0x4e, 0x47, 0xfa, 0x55, 0x0e, 0xb2, 0x32, 0xb6, 0x0c, 0x62, 0xc2, 0x68, 0x0b, 0x72, 0x78, 0xd4, - 0xc6, 0x86, 0xed, 0x64, 0xf8, 0x93, 0x6f, 0x50, 0x8c, 0xbb, 0xe1, 0x70, 0x36, 0x63, 0xb2, 0x27, - 0x86, 0xee, 0x71, 0xa0, 0x23, 0x1a, 0xb3, 0xe0, 0xe2, 0x7e, 0xa4, 0xe3, 0x6d, 0x07, 0xe9, 0x60, - 0x81, 0x7e, 0x35, 0x52, 0x2a, 0x04, 0x75, 0xdc, 0xe3, 0x50, 0x47, 0x72, 0xc6, 0xc7, 0x02, 0x58, - 0x47, 0x3d, 0x80, 0x75, 0xa4, 0x66, 0x4c, 0x33, 0x02, 0xec, 0x78, 0xdb, 0x01, 0x3b, 0xd2, 0x33, - 0x46, 0x1c, 0x42, 0x3b, 0xfe, 0x65, 0x0c, 0xed, 0x58, 0x8f, 0x14, 0x9d, 0x00, 0x77, 0xec, 0x8f, - 0xc1, 0x1d, 0x59, 0xaa, 0xe4, 0x95, 0x48, 0x25, 0x33, 0xf0, 0x8e, 0xfd, 0x31, 0xbc, 0x23, 0x37, - 0x43, 0xe1, 0x0c, 0xc0, 0xe3, 0x3f, 0x26, 0x03, 0x1e, 0x10, 0x09, 0x49, 0xf0, 0x61, 0xce, 0x87, - 0x78, 0x28, 0x11, 0x88, 0x47, 0x3e, 0xf2, 0x76, 0xce, 0xd4, 0xcf, 0x0d, 0x79, 0x1c, 0x4d, 0x80, - 0x3c, 0x58, 0xf2, 0x72, 0x3b, 0x52, 0xf9, 0x1c, 0x98, 0xc7, 0xd1, 0x04, 0xcc, 0xa3, 0x38, 0x53, - 0xed, 0x4c, 0xd0, 0xe3, 0x41, 0x10, 0xf4, 0x28, 0x45, 0xdc, 0x29, 0xbd, 0x23, 0x1b, 0x81, 0x7a, - 0x9c, 0x44, 0xa1, 0x1e, 0x0c, 0xed, 0x79, 0x2d, 0x52, 0xe3, 0x02, 0xb0, 0xc7, 0xfe, 0x18, 0xec, - 0x21, 0xce, 0xb0, 0xb4, 0x39, 0x71, 0x0f, 0xe9, 0x55, 0x12, 0x4b, 0x43, 0x4e, 0x89, 0x38, 0x58, - 0x6c, 0x9a, 0xba, 0xc9, 0x91, 0x0a, 0xd6, 0x90, 0x6e, 0x93, 0x7b, 0xab, 0xe7, 0x80, 0xa6, 0x60, - 0x21, 0x65, 0x28, 0x06, 0x9c, 0x8e, 0xf4, 0x33, 0xc1, 0x93, 0xa5, 0x68, 0x88, 0xff, 0xce, 0x9b, - 0xe3, 0x77, 0xde, 0xd0, 0x3d, 0x2d, 0x17, 0xc8, 0x08, 0xfc, 0x39, 0x07, 0x07, 0x3f, 0x54, 0x2f, - 0xd7, 0xb8, 0x03, 0x4b, 0x34, 0x3b, 0x65, 0x1e, 0x3d, 0x10, 0x34, 0xca, 0xa4, 0x83, 0xad, 0x02, - 0x8b, 0x1e, 0xaf, 0xc3, 0xb2, 0x8f, 0xd7, 0xbd, 0x68, 0x32, 0x04, 0x40, 0x74, 0xb9, 0x6b, 0xfc, - 0xc6, 0xf9, 0x87, 0xb8, 0xb7, 0x42, 0x1e, 0x6a, 0x32, 0x09, 0xe0, 0x10, 0x7e, 0x34, 0xc0, 0x11, - 0x7d, 0xe1, 0x45, 0x1f, 0xc3, 0x4a, 0x00, 0xfb, 0x70, 0x92, 0xbf, 0xc4, 0x62, 0x10, 0x48, 0xcc, - 0x97, 0x8b, 0xb8, 0x3d, 0xe8, 0x13, 0xb8, 0x46, 0xd3, 0xd8, 0x88, 0x04, 0x33, 0x39, 0x5f, 0x82, - 0x79, 0x85, 0xe8, 0xa8, 0x4f, 0x48, 0x32, 0x23, 0x80, 0x91, 0x54, 0x14, 0x30, 0xf2, 0x67, 0xc1, - 0xb3, 0x1b, 0x17, 0x1a, 0x69, 0xeb, 0x1d, 0x66, 0x5f, 0x45, 0x99, 0xfe, 0x26, 0x97, 0x94, 0x9e, - 0x7e, 0xc6, 0x4d, 0x84, 0xfc, 0x24, 0x5c, 0x2e, 0x68, 0x9f, 0xe3, 0x81, 0x6a, 0x05, 0x52, 0xda, - 0xa0, 0x83, 0x47, 0xdc, 0x0a, 0x58, 0x83, 0xc8, 0x3e, 0xc1, 0x17, 0x7c, 0xaf, 0xc9, 0x4f, 0xc2, - 0x47, 0x0f, 0x02, 0x8d, 0x45, 0x05, 0x99, 0x35, 0xd0, 0x3b, 0x90, 0xa3, 0x95, 0x17, 0x45, 0x37, - 0x2c, 0x1e, 0x6a, 0x02, 0x19, 0x11, 0xab, 0x92, 0x6c, 0x1c, 0x10, 0x9e, 0x7d, 0xc3, 0x92, 0xb3, - 0x06, 0xff, 0xe5, 0xcb, 0x59, 0xb2, 0x81, 0x9c, 0xe5, 0x3a, 0xe4, 0xc8, 0xe8, 0x2d, 0x43, 0x6d, - 0x63, 0x1a, 0x26, 0x72, 0xb2, 0x47, 0x90, 0x7e, 0x21, 0x40, 0x39, 0x14, 0xb9, 0x26, 0xce, 0xdd, - 0x39, 0x36, 0xf1, 0x20, 0x54, 0x34, 0x36, 0xfb, 0x1b, 0x00, 0x67, 0xaa, 0xa5, 0x3c, 0x55, 0x07, - 0x36, 0xee, 0xf0, 0x25, 0xc8, 0x9d, 0xa9, 0xd6, 0x87, 0x94, 0x10, 0x1c, 0x4c, 0x2a, 0x34, 0x18, - 0x1f, 0x58, 0x91, 0xf6, 0x83, 0x15, 0xa8, 0x0a, 0x59, 0xc3, 0xd4, 0x74, 0x53, 0xb3, 0x2f, 0xe8, - 0x9a, 0x24, 0x64, 0xb7, 0x2d, 0x1d, 0xc0, 0xa5, 0x89, 0x41, 0x13, 0xdd, 0x87, 0x9c, 0x17, 0x6f, - 0x05, 0x9a, 0x1b, 0x4e, 0xc1, 0x80, 0x3c, 0x5e, 0xb2, 0x24, 0x97, 0x26, 0x86, 0x4d, 0xd4, 0x80, - 0xb4, 0x89, 0xad, 0x61, 0x8f, 0xe5, 0xaa, 0xa5, 0xbb, 0xaf, 0xcf, 0x17, 0x6e, 0x09, 0x75, 0xd8, - 0xb3, 0x65, 0x2e, 0x2c, 0x7d, 0x0a, 0x69, 0x46, 0x41, 0x79, 0xc8, 0x1c, 0xed, 0x3d, 0xda, 0xdb, - 0xff, 0x70, 0x4f, 0x8c, 0x21, 0x80, 0x74, 0xad, 0x5e, 0x6f, 0x1c, 0xb4, 0x44, 0x01, 0xe5, 0x20, - 0x55, 0xdb, 0xda, 0x97, 0x5b, 0x62, 0x9c, 0x90, 0xe5, 0xc6, 0xc3, 0x46, 0xbd, 0x25, 0x26, 0xd0, - 0x12, 0x14, 0xd9, 0x6f, 0xe5, 0xc1, 0xbe, 0xfc, 0xb8, 0xd6, 0x12, 0x93, 0x3e, 0xd2, 0x61, 0x63, - 0x6f, 0xbb, 0x21, 0x8b, 0x29, 0xe9, 0x4d, 0xb8, 0x1a, 0x19, 0xa0, 0x3d, 0x98, 0x48, 0xf0, 0xc1, - 0x44, 0xd2, 0x77, 0x71, 0x72, 0x03, 0x89, 0x8a, 0xba, 0xe8, 0x61, 0x68, 0xe2, 0x77, 0x17, 0x08, - 0xd9, 0xa1, 0xd9, 0xa3, 0x97, 0xa1, 0x64, 0xe2, 0x53, 0x6c, 0xb7, 0xbb, 0x2c, 0x0b, 0x70, 0x70, - 0xa4, 0x22, 0xa7, 0x52, 0x21, 0x8b, 0xb1, 0x7d, 0x86, 0xdb, 0xb6, 0xc2, 0x8c, 0xc0, 0xa2, 0xb7, - 0xf5, 0x1c, 0x61, 0x23, 0xd4, 0x43, 0x46, 0x24, 0x0e, 0x9a, 0x39, 0x12, 0xa6, 0x2a, 0x49, 0x55, - 0x01, 0xf5, 0x0b, 0x94, 0x22, 0x3d, 0x5d, 0x68, 0xb1, 0x73, 0x90, 0x92, 0x1b, 0x2d, 0xf9, 0x23, - 0x31, 0x81, 0x10, 0x94, 0xe8, 0x4f, 0xe5, 0x70, 0xaf, 0x76, 0x70, 0xd8, 0xdc, 0x27, 0x8b, 0xbd, - 0x0c, 0x65, 0x67, 0xb1, 0x1d, 0x62, 0x0a, 0x5d, 0x82, 0xa5, 0xfa, 0xfe, 0xe3, 0x83, 0xdd, 0x46, - 0xab, 0xe1, 0x91, 0xd3, 0xd2, 0xcf, 0x13, 0x70, 0x25, 0x22, 0xd7, 0x40, 0xef, 0x00, 0xd8, 0x23, - 0xc5, 0xc4, 0x6d, 0xdd, 0xec, 0x44, 0x1b, 0x67, 0x6b, 0x24, 0x53, 0x0e, 0x39, 0x67, 0xf3, 0x5f, - 0x53, 0x1d, 0xf6, 0xfb, 0x5c, 0x29, 0x99, 0xac, 0xc5, 0xb1, 0x8d, 0x1b, 0x13, 0x2e, 0x6b, 0xb8, - 0x4d, 0x14, 0xd3, 0x3d, 0xa1, 0x8a, 0x29, 0x3f, 0xfa, 0x08, 0xae, 0x84, 0xe2, 0x0a, 0x77, 0xc6, - 0xd6, 0xa4, 0xc2, 0xe2, 0xe4, 0xf0, 0x72, 0x29, 0x18, 0x5e, 0x98, 0x33, 0xb6, 0xa6, 0x00, 0x09, - 0xa9, 0x17, 0x00, 0x12, 0xa2, 0xe2, 0x53, 0x7a, 0x51, 0x88, 0x7e, 0x42, 0x7c, 0x92, 0xfe, 0x3f, - 0xb0, 0x79, 0xc1, 0xf4, 0x6d, 0x1f, 0xd2, 0x96, 0xad, 0xda, 0x43, 0x8b, 0x1f, 0x86, 0xfb, 0xf3, - 0xe6, 0x82, 0x1b, 0xce, 0x8f, 0x43, 0x2a, 0x2e, 0x73, 0x35, 0x7f, 0x97, 0x7b, 0x1a, 0xb5, 0xfa, - 0xa9, 0x9f, 0x62, 0xf5, 0xdf, 0x82, 0x52, 0x70, 0xa9, 0xa2, 0xcf, 0xae, 0xe7, 0x1d, 0xe3, 0x52, - 0x0f, 0x96, 0x27, 0x40, 0x11, 0xe8, 0x3e, 0xaf, 0x36, 0xb0, 0xdd, 0xba, 0x39, 0x3e, 0xe5, 0x00, - 0xbb, 0x57, 0x74, 0x20, 0xc1, 0xca, 0xcb, 0xa9, 0xd9, 0xc6, 0x78, 0x04, 0xa9, 0x0d, 0x68, 0x3c, - 0x43, 0x9f, 0x04, 0x9b, 0x08, 0x2f, 0x00, 0x9b, 0xfc, 0xaf, 0x00, 0xd7, 0xa6, 0x64, 0xed, 0xe8, - 0x83, 0x90, 0x2d, 0xbe, 0xbb, 0x48, 0xce, 0xbf, 0xc1, 0x68, 0x41, 0x6b, 0x94, 0xee, 0x41, 0xc1, - 0x4f, 0x9f, 0x6f, 0xe9, 0xff, 0xdb, 0x17, 0x33, 0x83, 0xf8, 0x4e, 0x13, 0xd2, 0xf8, 0x1c, 0x0f, - 0xdc, 0x18, 0x7c, 0x79, 0x7c, 0x1d, 0x48, 0xf7, 0x56, 0x85, 0xe4, 0x8a, 0x7f, 0x7c, 0xb6, 0x26, - 0x32, 0xee, 0xd7, 0xf4, 0xbe, 0x66, 0xe3, 0xbe, 0x61, 0x5f, 0xc8, 0x5c, 0x1e, 0xdd, 0x84, 0xa2, - 0x89, 0x6d, 0xe2, 0x42, 0x02, 0xd0, 0x5a, 0x81, 0x11, 0x79, 0x26, 0xf7, 0x6b, 0x01, 0xc0, 0x03, - 0x8c, 0x3c, 0xc0, 0x46, 0xf0, 0x03, 0x36, 0x21, 0x9c, 0x2f, 0x1e, 0xc6, 0xf9, 0xd0, 0x2d, 0x28, - 0xb3, 0x24, 0xdd, 0xd2, 0xce, 0x06, 0xaa, 0x3d, 0x34, 0x31, 0x87, 0x87, 0x4a, 0x94, 0x7c, 0xe8, - 0x50, 0xd1, 0xc7, 0x70, 0xd5, 0xee, 0x9a, 0xd8, 0xea, 0xea, 0xbd, 0x8e, 0x12, 0xde, 0x78, 0x56, - 0xb6, 0x58, 0x9b, 0x61, 0x70, 0xf2, 0x15, 0x57, 0xc3, 0x71, 0x70, 0xf3, 0xbf, 0x80, 0x14, 0x5d, - 0x1b, 0x92, 0x68, 0xb9, 0x16, 0x9c, 0xe3, 0xc6, 0xf9, 0x09, 0x80, 0x6a, 0xdb, 0xa6, 0x76, 0x32, - 0x24, 0xc7, 0x39, 0x3e, 0xfe, 0x29, 0x6f, 0x6d, 0x6b, 0x0e, 0xdf, 0xd6, 0x75, 0xbe, 0xc8, 0x2b, - 0x9e, 0xa8, 0x6f, 0xa1, 0x7d, 0x0a, 0xa5, 0x3d, 0x28, 0x05, 0x65, 0x9d, 0x0c, 0x96, 0x8d, 0x21, - 0x98, 0xc1, 0xb2, 0x8c, 0x98, 0x67, 0xb0, 0x6e, 0xfe, 0x9b, 0x60, 0x45, 0x41, 0xda, 0x90, 0xfe, - 0x22, 0x40, 0xc1, 0xef, 0xa6, 0xe6, 0x4e, 0x32, 0x79, 0xd2, 0x9d, 0x18, 0x4f, 0xba, 0x93, 0x91, - 0x69, 0x67, 0x2a, 0x9c, 0x76, 0x5e, 0x85, 0x2c, 0xe9, 0x1e, 0x5a, 0xb8, 0xc3, 0x2b, 0xa9, 0x99, - 0x33, 0xd5, 0x3a, 0xb2, 0x70, 0xc7, 0x67, 0x9f, 0x99, 0x17, 0xb4, 0xcf, 0x40, 0x6e, 0x9b, 0x0d, - 0x27, 0xda, 0x5f, 0x0a, 0x90, 0x75, 0x27, 0x1f, 0x2c, 0x18, 0x06, 0xf0, 0x45, 0xb6, 0x76, 0xac, - 0x5c, 0xc8, 0xef, 0x0e, 0xac, 0x7c, 0x9a, 0x70, 0xcb, 0xa7, 0xef, 0xb9, 0xd9, 0x58, 0x14, 0x82, - 0xe6, 0x5f, 0x69, 0x07, 0x34, 0xe5, 0xc9, 0xe7, 0xff, 0xf0, 0x71, 0x90, 0x74, 0x02, 0xfd, 0x33, - 0xa4, 0xd5, 0xb6, 0x8b, 0x1b, 0x96, 0x26, 0x00, 0x6a, 0x0e, 0xeb, 0x46, 0x6b, 0x54, 0xa3, 0x9c, - 0x32, 0x97, 0xe0, 0xa3, 0x8a, 0x3b, 0xa3, 0x92, 0x76, 0x89, 0x5e, 0xc6, 0x13, 0xf4, 0x19, 0x25, - 0x80, 0xa3, 0xbd, 0xc7, 0xfb, 0xdb, 0x3b, 0x0f, 0x76, 0x1a, 0xdb, 0x3c, 0xdd, 0xda, 0xde, 0x6e, - 0x6c, 0x8b, 0x71, 0xc2, 0x27, 0x37, 0x1e, 0xef, 0x1f, 0x37, 0xb6, 0xc5, 0x04, 0x69, 0x6c, 0x37, - 0x76, 0x6b, 0x1f, 0x35, 0xb6, 0xc5, 0xa4, 0x54, 0x83, 0x9c, 0x1b, 0x32, 0x68, 0x9d, 0x59, 0x7f, - 0x8a, 0x4d, 0xbe, 0x5a, 0xac, 0x81, 0x56, 0x21, 0x3f, 0x0e, 0x7c, 0x93, 0xdb, 0x13, 0xc3, 0xbb, - 0xa5, 0xff, 0x13, 0xa0, 0xec, 0xea, 0xe0, 0x49, 0xc3, 0x7b, 0x90, 0x31, 0x86, 0x27, 0x8a, 0x63, - 0xc8, 0x21, 0xb8, 0xd8, 0xb9, 0x5c, 0x0d, 0x4f, 0x7a, 0x5a, 0xfb, 0x11, 0xbe, 0xe0, 0x21, 0x2a, - 0x6d, 0x0c, 0x4f, 0x1e, 0x31, 0x7b, 0x67, 0xc3, 0x88, 0x4f, 0x19, 0x46, 0x22, 0x34, 0x0c, 0x74, - 0x0b, 0x0a, 0x03, 0xbd, 0x83, 0x15, 0xb5, 0xd3, 0x31, 0xb1, 0xc5, 0x22, 0x6f, 0x8e, 0x6b, 0xce, - 0x93, 0x9e, 0x1a, 0xeb, 0x90, 0xbe, 0x17, 0x00, 0x8d, 0x87, 0x49, 0x74, 0x08, 0x4b, 0x5e, 0xa4, - 0x75, 0xc2, 0x37, 0xf3, 0xa5, 0xeb, 0xd1, 0x61, 0x36, 0x70, 0x03, 0x17, 0xcf, 0x83, 0x64, 0x92, - 0x92, 0xad, 0x78, 0x7e, 0xcb, 0xa0, 0xf3, 0xa5, 0x8b, 0x12, 0x9f, 0x73, 0x51, 0x62, 0x32, 0x72, - 0xe5, 0xdd, 0x9e, 0xb0, 0x5f, 0x4d, 0x8c, 0xd5, 0x4f, 0x0c, 0xa8, 0xb4, 0xc6, 0xc4, 0xf8, 0x3c, - 0xa3, 0x86, 0x24, 0xbc, 0xc8, 0x90, 0xa4, 0x7b, 0x20, 0x7e, 0xe0, 0x7e, 0x9f, 0x7f, 0x29, 0x34, - 0x4c, 0x61, 0x6c, 0x98, 0xe7, 0x90, 0x25, 0xae, 0x98, 0x46, 0x90, 0x7f, 0x85, 0x9c, 0xbb, 0x7a, - 0xee, 0x53, 0x95, 0xc8, 0x65, 0xe7, 0x23, 0xf1, 0x44, 0xd0, 0x1d, 0x58, 0x22, 0x41, 0xc4, 0xa9, - 0x62, 0x32, 0x0c, 0x2d, 0x4e, 0x5d, 0x63, 0x99, 0x75, 0xec, 0x3a, 0xc0, 0x0f, 0x89, 0xf6, 0x22, - 0xcb, 0x0a, 0x70, 0xe7, 0x6f, 0x31, 0x00, 0x72, 0xe9, 0x0a, 0x41, 0x89, 0x6c, 0x0f, 0x8b, 0x81, - 0xb4, 0x44, 0xfa, 0xcf, 0x38, 0xe4, 0x7d, 0x55, 0x15, 0xf4, 0x4f, 0x81, 0x0c, 0x6b, 0x7d, 0x5a, - 0x05, 0xc6, 0x97, 0x5e, 0x05, 0x26, 0x16, 0x5f, 0x7c, 0x62, 0x51, 0xf5, 0x2c, 0xa7, 0xb8, 0x9a, - 0x5c, 0xb8, 0xb8, 0xfa, 0x1a, 0x20, 0x5b, 0xb7, 0xd5, 0x1e, 0x89, 0xe4, 0xda, 0xe0, 0x4c, 0x61, - 0xa7, 0x9d, 0x45, 0x13, 0x91, 0xf6, 0x1c, 0xd3, 0x8e, 0x03, 0x42, 0x97, 0x7a, 0x90, 0x75, 0x91, - 0x81, 0xc5, 0x5f, 0x80, 0x4c, 0x2a, 0x22, 0x57, 0x21, 0xdb, 0xc7, 0xb6, 0x4a, 0x63, 0x20, 0x43, - 0x8a, 0xdc, 0xf6, 0x9d, 0x77, 0x21, 0xef, 0x7b, 0x16, 0x43, 0xc2, 0xe2, 0x5e, 0xe3, 0x43, 0x31, - 0x56, 0xcd, 0x7c, 0xf5, 0xcd, 0x7a, 0x62, 0x0f, 0x3f, 0x25, 0x9f, 0x92, 0x1b, 0xf5, 0x66, 0xa3, - 0xfe, 0x48, 0x14, 0xaa, 0xf9, 0xaf, 0xbe, 0x59, 0xcf, 0xc8, 0x98, 0x16, 0x20, 0xee, 0x3c, 0x82, - 0x72, 0x68, 0x07, 0x82, 0x0e, 0x1a, 0x41, 0x69, 0xfb, 0xe8, 0x60, 0x77, 0xa7, 0x5e, 0x6b, 0x35, - 0x94, 0xe3, 0xfd, 0x56, 0x43, 0x14, 0xd0, 0x15, 0x58, 0xde, 0xdd, 0xf9, 0xb7, 0x66, 0x4b, 0xa9, - 0xef, 0xee, 0x34, 0xf6, 0x5a, 0x4a, 0xad, 0xd5, 0xaa, 0xd5, 0x1f, 0x89, 0xf1, 0xbb, 0xbf, 0x03, - 0x28, 0xd7, 0xb6, 0xea, 0x3b, 0xe4, 0xa2, 0xaf, 0xb5, 0x55, 0xea, 0xee, 0xeb, 0x90, 0xa4, 0xb8, - 0xec, 0xd4, 0x07, 0xb2, 0xd5, 0xe9, 0x55, 0x25, 0xf4, 0x00, 0x52, 0x14, 0xb2, 0x45, 0xd3, 0x5f, - 0xcc, 0x56, 0x67, 0x94, 0x99, 0xc8, 0x60, 0xe8, 0xb9, 0x99, 0xfa, 0x84, 0xb6, 0x3a, 0xbd, 0xea, - 0x84, 0x76, 0x21, 0xe3, 0xa0, 0x61, 0xb3, 0xde, 0xb5, 0x56, 0x67, 0x96, 0x82, 0xc8, 0xd4, 0x18, - 0xaa, 0x38, 0xfd, 0x75, 0x6d, 0x75, 0x46, 0x3d, 0x0a, 0xc9, 0x90, 0xf3, 0x80, 0xe0, 0xd9, 0x0f, - 0x7d, 0xab, 0x73, 0xd4, 0xc7, 0xd0, 0xa7, 0x50, 0x0c, 0xe2, 0x66, 0xf3, 0xbd, 0xc1, 0xad, 0xce, - 0x59, 0xbb, 0x22, 0xfa, 0x83, 0x20, 0xda, 0x7c, 0x6f, 0x72, 0xab, 0x73, 0x96, 0xb2, 0xd0, 0x67, - 0xb0, 0x34, 0x0e, 0x72, 0xcd, 0xff, 0x44, 0xb7, 0xba, 0x40, 0x71, 0x0b, 0xf5, 0x01, 0x4d, 0x00, - 0xc7, 0x16, 0x78, 0xb1, 0x5b, 0x5d, 0xa4, 0xd6, 0x85, 0x3a, 0x50, 0x0e, 0x03, 0x47, 0xf3, 0xbe, - 0xe0, 0xad, 0xce, 0x5d, 0xf7, 0x62, 0x5f, 0x09, 0x22, 0x1c, 0xf3, 0xbe, 0xe8, 0xad, 0xce, 0x5d, - 0x06, 0x43, 0x47, 0x00, 0xbe, 0x5b, 0xf2, 0x1c, 0x2f, 0x7c, 0xab, 0xf3, 0x14, 0xc4, 0x90, 0x01, - 0xcb, 0x93, 0xae, 0xc5, 0x8b, 0x3c, 0xf8, 0xad, 0x2e, 0x54, 0x27, 0x23, 0xf6, 0x1c, 0xbc, 0xe0, - 0xce, 0xf7, 0x00, 0xb8, 0x3a, 0x67, 0xc1, 0x6c, 0x6b, 0xeb, 0xdb, 0xe7, 0xab, 0xc2, 0x77, 0xcf, - 0x57, 0x85, 0xef, 0x9f, 0xaf, 0x0a, 0x5f, 0xff, 0xb0, 0x1a, 0xfb, 0xee, 0x87, 0xd5, 0xd8, 0x6f, - 0x7f, 0x58, 0x8d, 0xfd, 0xfb, 0xed, 0x33, 0xcd, 0xee, 0x0e, 0x4f, 0x36, 0xda, 0x7a, 0x9f, 0xfe, - 0xff, 0xc2, 0x50, 0x2f, 0x36, 0x99, 0x4e, 0xd2, 0xf2, 0xfd, 0xcb, 0xe3, 0x24, 0x4d, 0x63, 0xdd, - 0xbd, 0xbf, 0x06, 0x00, 0x00, 0xff, 0xff, 0x2b, 0x73, 0xfa, 0xad, 0x05, 0x32, 0x00, 0x00, + // 3655 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5b, 0xcb, 0x73, 0x1b, 0xc7, + 0xd1, 0xc7, 0xe2, 0x8d, 0xc6, 0x93, 0x43, 0x4a, 0x82, 0x20, 0x89, 0xa4, 0x57, 0x9f, 0x2d, 0x59, + 0x9f, 0x4d, 0xda, 0xd2, 0x67, 0xcb, 0xfe, 0xec, 0xef, 0xab, 0x02, 0x41, 0x28, 0xa0, 0x44, 0x91, + 0xf4, 0x12, 0xa4, 0xcb, 0x71, 0xec, 0xad, 0x25, 0x30, 0x04, 0xd6, 0x02, 0xb0, 0xeb, 0xdd, 0x05, + 0x05, 0xfa, 0x9a, 0x38, 0x95, 0xf2, 0xc9, 0xff, 0x80, 0x6f, 0xc9, 0x31, 0x97, 0x9c, 0x52, 0x39, + 0x24, 0x95, 0x9b, 0x53, 0xb9, 0xf8, 0x98, 0x4b, 0x14, 0x97, 0x7c, 0x49, 0xe5, 0x96, 0x53, 0x6e, + 0xa9, 0xd4, 0x3c, 0xf6, 0x09, 0x2c, 0x1e, 0x92, 0xab, 0x52, 0xb9, 0x61, 0x7a, 0xba, 0x7b, 0xe7, + 0xd1, 0xd3, 0xdd, 0xf3, 0xeb, 0x01, 0x5c, 0xb1, 0xf0, 0xa0, 0x8d, 0x8d, 0xbe, 0x3a, 0xb0, 0x36, + 0x95, 0x93, 0x96, 0xba, 0x69, 0x9d, 0xeb, 0xd8, 0xdc, 0xd0, 0x0d, 0xcd, 0xd2, 0x50, 0xd1, 0xed, + 0xdc, 0x20, 0x9d, 0x95, 0x6b, 0x1e, 0xee, 0x96, 0x71, 0xae, 0x5b, 0xda, 0xa6, 0x6e, 0x68, 0xda, + 0x29, 0xe3, 0xaf, 0x78, 0x95, 0x51, 0x3d, 0x9b, 0x6d, 0xc5, 0xec, 0xf2, 0xce, 0xab, 0x63, 0x9d, + 0x27, 0x3d, 0xad, 0xf5, 0x28, 0xb4, 0xd7, 0x33, 0x10, 0x5f, 0x2f, 0xff, 0xee, 0x23, 0x7c, 0x6e, + 0xf7, 0x5e, 0x1b, 0x93, 0xd5, 0x15, 0x43, 0xe9, 0xdb, 0xdd, 0xab, 0x9e, 0xee, 0x33, 0x6c, 0x98, + 0xaa, 0x36, 0xf0, 0x29, 0x5f, 0xeb, 0x68, 0x5a, 0xa7, 0x87, 0x37, 0x69, 0xeb, 0x64, 0x78, 0xba, + 0x69, 0xa9, 0x7d, 0x6c, 0x5a, 0x4a, 0x5f, 0xe7, 0x0c, 0x2b, 0x1d, 0xad, 0xa3, 0xd1, 0x9f, 0x9b, + 0xe4, 0x17, 0xa3, 0x8a, 0x9f, 0x67, 0x20, 0x25, 0xe1, 0x4f, 0x87, 0xd8, 0xb4, 0xd0, 0x6d, 0x88, + 0xe3, 0x56, 0x57, 0x2b, 0x0b, 0xeb, 0xc2, 0xcd, 0xec, 0xed, 0xab, 0x1b, 0x81, 0x75, 0xdb, 0xe0, + 0x7c, 0xf5, 0x56, 0x57, 0x6b, 0x44, 0x24, 0xca, 0x8b, 0xde, 0x80, 0xc4, 0x69, 0x6f, 0x68, 0x76, + 0xcb, 0x51, 0x2a, 0x74, 0x2d, 0x4c, 0xe8, 0x1e, 0x61, 0x6a, 0x44, 0x24, 0xc6, 0x4d, 0x3e, 0xa5, + 0x0e, 0x4e, 0xb5, 0x72, 0x6c, 0xfa, 0xa7, 0x76, 0x06, 0xa7, 0xf4, 0x53, 0x84, 0x17, 0x6d, 0x01, + 0xa8, 0x03, 0xd5, 0x92, 0x5b, 0x5d, 0x45, 0x1d, 0x94, 0xe3, 0x54, 0xf2, 0x85, 0x70, 0x49, 0xd5, + 0xaa, 0x11, 0xc6, 0x46, 0x44, 0xca, 0xa8, 0x76, 0x83, 0x0c, 0xf7, 0xd3, 0x21, 0x36, 0xce, 0xcb, + 0x89, 0xe9, 0xc3, 0x7d, 0x8f, 0x30, 0x91, 0xe1, 0x52, 0x6e, 0xf4, 0x2e, 0xa4, 0x5b, 0x5d, 0xdc, + 0x7a, 0x24, 0x5b, 0xa3, 0x72, 0x8a, 0x4a, 0xae, 0x85, 0x49, 0xd6, 0x08, 0x5f, 0x73, 0xd4, 0x88, + 0x48, 0xa9, 0x16, 0xfb, 0x89, 0xf6, 0xa0, 0xd0, 0x53, 0x4d, 0x4b, 0x36, 0x07, 0x8a, 0x6e, 0x76, + 0x35, 0xcb, 0x2c, 0x67, 0xa9, 0x8e, 0x17, 0xc3, 0x74, 0xec, 0xaa, 0xa6, 0x75, 0x68, 0x33, 0x37, + 0x22, 0x52, 0xbe, 0xe7, 0x25, 0x10, 0x7d, 0xda, 0xe9, 0x29, 0x36, 0x1c, 0x85, 0xe5, 0xdc, 0x74, + 0x7d, 0xfb, 0x84, 0xdb, 0x96, 0x27, 0xfa, 0x34, 0x2f, 0x01, 0x7d, 0x08, 0xcb, 0x3d, 0x4d, 0x69, + 0x3b, 0xea, 0xe4, 0x56, 0x77, 0x38, 0x78, 0x54, 0xce, 0x53, 0xa5, 0x2f, 0x87, 0x0e, 0x52, 0x53, + 0xda, 0xb6, 0x8a, 0x1a, 0x11, 0x68, 0x44, 0xa4, 0xa5, 0x5e, 0x90, 0x88, 0x3e, 0x86, 0x15, 0x45, + 0xd7, 0x7b, 0xe7, 0x41, 0xed, 0x05, 0xaa, 0xfd, 0x56, 0x98, 0xf6, 0x2a, 0x91, 0x09, 0xaa, 0x47, + 0xca, 0x18, 0x15, 0x35, 0xa1, 0xa4, 0x1b, 0x58, 0x57, 0x0c, 0x2c, 0xeb, 0x86, 0xa6, 0x6b, 0xa6, + 0xd2, 0x2b, 0x17, 0xa9, 0xee, 0x1b, 0x61, 0xba, 0x0f, 0x18, 0xff, 0x01, 0x67, 0x6f, 0x44, 0xa4, + 0xa2, 0xee, 0x27, 0x31, 0xad, 0x5a, 0x0b, 0x9b, 0xa6, 0xab, 0xb5, 0x34, 0x4b, 0x2b, 0xe5, 0xf7, + 0x6b, 0xf5, 0x91, 0x50, 0x1d, 0xb2, 0x78, 0x44, 0xc4, 0xe5, 0x33, 0xcd, 0xc2, 0xe5, 0x25, 0xaa, + 0x50, 0x0c, 0x3d, 0x67, 0x94, 0xf5, 0x58, 0xb3, 0x70, 0x23, 0x22, 0x01, 0x76, 0x5a, 0x48, 0x81, + 0x0b, 0x67, 0xd8, 0x50, 0x4f, 0xcf, 0xa9, 0x1a, 0x99, 0xf6, 0x10, 0x7f, 0x50, 0x46, 0x54, 0xe1, + 0x7f, 0x87, 0x29, 0x3c, 0xa6, 0x42, 0x44, 0x45, 0xdd, 0x16, 0x69, 0x44, 0xa4, 0xe5, 0xb3, 0x71, + 0x32, 0x31, 0xb1, 0x53, 0x75, 0xa0, 0xf4, 0xd4, 0xcf, 0xb0, 0x4c, 0x1d, 0x5c, 0x79, 0x79, 0xba, + 0x89, 0xdd, 0xe3, 0xdc, 0x5b, 0x84, 0x99, 0x98, 0xd8, 0xa9, 0x97, 0xb0, 0x95, 0x82, 0xc4, 0x99, + 0xd2, 0x1b, 0xe2, 0xfb, 0xf1, 0x74, 0xb2, 0x94, 0xba, 0x1f, 0x4f, 0xa7, 0x4b, 0x99, 0xfb, 0xf1, + 0x74, 0xa6, 0x04, 0xf7, 0xe3, 0x69, 0x28, 0x65, 0xc5, 0x1b, 0x90, 0xf5, 0xb8, 0x17, 0x54, 0x86, + 0x54, 0x1f, 0x9b, 0xa6, 0xd2, 0xc1, 0xd4, 0x1b, 0x65, 0x24, 0xbb, 0x29, 0x16, 0x20, 0xe7, 0x75, + 0x29, 0xe2, 0x97, 0x82, 0x23, 0x49, 0xbc, 0x05, 0x91, 0xe4, 0xee, 0xd1, 0x96, 0xe4, 0x4d, 0x74, + 0x1d, 0xf2, 0x74, 0x2a, 0xb2, 0xdd, 0x4f, 0x5c, 0x56, 0x5c, 0xca, 0x51, 0xe2, 0x31, 0x67, 0x5a, + 0x83, 0xac, 0x7e, 0x5b, 0x77, 0x58, 0x62, 0x94, 0x05, 0xf4, 0xdb, 0xba, 0xcd, 0xf0, 0x02, 0xe4, + 0xc8, 0xbc, 0x1d, 0x8e, 0x38, 0xfd, 0x48, 0x96, 0xd0, 0x38, 0x8b, 0xf8, 0x93, 0x18, 0x94, 0x82, + 0x6e, 0x08, 0xbd, 0x05, 0x71, 0xe2, 0x91, 0xb9, 0x73, 0xad, 0x6c, 0x30, 0x77, 0xbd, 0x61, 0xbb, + 0xeb, 0x8d, 0xa6, 0xed, 0xae, 0xb7, 0xd2, 0x5f, 0x3f, 0x59, 0x8b, 0x7c, 0xf9, 0x97, 0x35, 0x41, + 0xa2, 0x12, 0xe8, 0x32, 0x71, 0x3e, 0x8a, 0x3a, 0x90, 0xd5, 0x36, 0x1d, 0x72, 0x86, 0x78, 0x16, + 0x45, 0x1d, 0xec, 0xb4, 0xd1, 0x2e, 0x94, 0x5a, 0xda, 0xc0, 0xc4, 0x03, 0x73, 0x68, 0xca, 0x2c, + 0x5c, 0x70, 0x97, 0xea, 0x73, 0x8c, 0x2c, 0x4e, 0xd4, 0x6c, 0xce, 0x03, 0xca, 0x28, 0x15, 0x5b, + 0x7e, 0x02, 0xda, 0x83, 0xfc, 0x99, 0xd2, 0x53, 0xdb, 0x8a, 0xa5, 0x19, 0xb2, 0x89, 0x2d, 0xee, + 0x63, 0xaf, 0x8f, 0xed, 0xf9, 0xb1, 0xcd, 0x75, 0x88, 0xad, 0x23, 0xbd, 0xad, 0x58, 0x78, 0x2b, + 0xfe, 0xf5, 0x93, 0x35, 0x41, 0xca, 0x9d, 0x79, 0x7a, 0xd0, 0x4b, 0x50, 0x54, 0x74, 0x5d, 0x36, + 0x2d, 0xc5, 0xc2, 0xf2, 0xc9, 0xb9, 0x85, 0x4d, 0xea, 0x76, 0x73, 0x52, 0x5e, 0xd1, 0xf5, 0x43, + 0x42, 0xdd, 0x22, 0x44, 0xf4, 0x22, 0x14, 0x88, 0x87, 0x56, 0x95, 0x9e, 0xdc, 0xc5, 0x6a, 0xa7, + 0x6b, 0x95, 0x93, 0xeb, 0xc2, 0xcd, 0x98, 0x94, 0xe7, 0xd4, 0x06, 0x25, 0xa2, 0x0d, 0x58, 0xb6, + 0xd9, 0x5a, 0x9a, 0x81, 0x6d, 0x5e, 0xe2, 0x8f, 0xf3, 0xd2, 0x12, 0xef, 0xaa, 0x69, 0x06, 0x66, + 0xfc, 0x62, 0xdb, 0xb1, 0x14, 0xea, 0xcd, 0x11, 0x82, 0x78, 0x5b, 0xb1, 0x14, 0xba, 0x03, 0x39, + 0x89, 0xfe, 0x26, 0x34, 0x5d, 0xb1, 0xba, 0x7c, 0x5d, 0xe9, 0x6f, 0x74, 0x11, 0x92, 0x5c, 0x75, + 0x8c, 0x0e, 0x83, 0xb7, 0xd0, 0x0a, 0x24, 0x74, 0x43, 0x3b, 0xc3, 0x74, 0x59, 0xd2, 0x12, 0x6b, + 0x88, 0x12, 0x14, 0xfc, 0x9e, 0x1f, 0x15, 0x20, 0x6a, 0x8d, 0xf8, 0x57, 0xa2, 0xd6, 0x08, 0xbd, + 0x06, 0x71, 0xb2, 0x01, 0xf4, 0x1b, 0x85, 0x09, 0xb1, 0x8e, 0xcb, 0x35, 0xcf, 0x75, 0x2c, 0x51, + 0x4e, 0xf1, 0x22, 0xac, 0x4c, 0x8a, 0x04, 0x62, 0xd7, 0xa1, 0xfb, 0x3c, 0x3a, 0x7a, 0x03, 0xd2, + 0x4e, 0x28, 0x60, 0xf6, 0x75, 0x79, 0xec, 0x2b, 0x36, 0xb3, 0xe4, 0xb0, 0x12, 0xc3, 0x22, 0xfb, + 0xd3, 0x55, 0x78, 0xf8, 0xce, 0x49, 0x29, 0x45, 0xd7, 0x1b, 0x8a, 0xd9, 0x15, 0x3b, 0x50, 0x0e, + 0x73, 0xf3, 0x9e, 0xf5, 0x11, 0xe8, 0xe9, 0xb0, 0xd7, 0xc7, 0x73, 0xf2, 0xa2, 0x74, 0x4f, 0x9c, + 0x93, 0x47, 0x2d, 0x78, 0x38, 0x78, 0x44, 0x2c, 0x38, 0xc6, 0x3e, 0x44, 0xdb, 0x3b, 0x6d, 0xb1, + 0x0d, 0x97, 0x43, 0x3d, 0xbe, 0x4f, 0x4e, 0xf0, 0xc9, 0x91, 0xcd, 0x60, 0x71, 0x84, 0x0d, 0x9c, + 0x35, 0xc8, 0xd0, 0x4c, 0x3a, 0x6f, 0xfa, 0x99, 0x8c, 0xc4, 0x5b, 0xe2, 0xdf, 0xe3, 0x70, 0x71, + 0xb2, 0xf3, 0x47, 0xeb, 0x90, 0xeb, 0x2b, 0x23, 0xd9, 0x1a, 0x71, 0x0b, 0x15, 0xe8, 0x9e, 0x43, + 0x5f, 0x19, 0x35, 0x47, 0xcc, 0x3c, 0x4b, 0x10, 0xb3, 0x46, 0x66, 0x39, 0xba, 0x1e, 0xbb, 0x99, + 0x93, 0xc8, 0x4f, 0xf4, 0x10, 0x96, 0x7a, 0x5a, 0x4b, 0xe9, 0xc9, 0x3d, 0xc5, 0xb4, 0xe4, 0x96, + 0xd6, 0xef, 0xab, 0x16, 0x3f, 0x77, 0x57, 0xc6, 0xb7, 0x97, 0x76, 0x13, 0xdf, 0x44, 0x0f, 0x49, + 0x44, 0x2a, 0x52, 0xd9, 0x5d, 0xc5, 0xb4, 0x58, 0x17, 0xda, 0x86, 0x6c, 0x5f, 0x35, 0x4f, 0x70, + 0x57, 0x39, 0x53, 0x35, 0xa3, 0x1c, 0x5f, 0x8f, 0x4d, 0xcc, 0x89, 0x1e, 0xba, 0x3c, 0x5c, 0x93, + 0x57, 0xcc, 0xb3, 0x2d, 0x09, 0x9f, 0xd9, 0xda, 0x8e, 0x27, 0xb9, 0xb0, 0xe3, 0x79, 0x0d, 0x56, + 0x06, 0x78, 0x64, 0xc9, 0xce, 0xa1, 0x36, 0x99, 0xad, 0xa4, 0xe8, 0x92, 0x23, 0xd2, 0xe7, 0x78, + 0x02, 0x93, 0x98, 0x0d, 0xd9, 0x15, 0x43, 0x1b, 0x0e, 0xda, 0xe5, 0xf4, 0xba, 0x70, 0x33, 0x21, + 0xb1, 0x06, 0xba, 0x0b, 0x65, 0x7a, 0x60, 0x99, 0x17, 0x23, 0xde, 0x16, 0xb7, 0xed, 0xd3, 0x9b, + 0xa1, 0x96, 0x72, 0x81, 0xf4, 0x53, 0x3f, 0xb9, 0x4b, 0x7b, 0xf9, 0x89, 0xdf, 0x84, 0x15, 0x16, + 0x7d, 0xb1, 0x41, 0xc2, 0x30, 0xd9, 0x24, 0x3a, 0x00, 0xa0, 0x03, 0x58, 0xb2, 0xfb, 0x0e, 0x0c, + 0xad, 0x39, 0xa2, 0xdf, 0x7f, 0xcd, 0x11, 0x68, 0xcb, 0xc4, 0xb4, 0x6d, 0x7b, 0xcc, 0x52, 0x43, + 0x45, 0x76, 0x5f, 0x55, 0x77, 0xdc, 0xf9, 0x5d, 0xd7, 0x68, 0x73, 0xe3, 0x29, 0x21, 0xef, 0x72, + 0x5d, 0xa7, 0x6b, 0xd3, 0x6b, 0x90, 0xfd, 0x74, 0xa8, 0x19, 0xc3, 0x3e, 0x1b, 0x52, 0x9e, 0x0e, + 0x09, 0x18, 0x89, 0x1e, 0xa1, 0xdf, 0x25, 0x3c, 0x36, 0xe7, 0xcf, 0x03, 0xb8, 0x45, 0x09, 0xae, + 0x45, 0x1d, 0x7a, 0x06, 0xee, 0x35, 0xaa, 0xe8, 0xbc, 0x46, 0xe5, 0xcc, 0x2d, 0xdc, 0xae, 0x62, + 0xcf, 0x66, 0x57, 0x08, 0xe2, 0x74, 0x86, 0x71, 0xe6, 0x36, 0xc9, 0xef, 0x50, 0x5b, 0x73, 0xf6, + 0x3f, 0xe9, 0xdd, 0x7f, 0xdb, 0x02, 0x53, 0xdf, 0x9b, 0x05, 0xa6, 0x43, 0x2d, 0xf0, 0x99, 0x6d, + 0xad, 0x09, 0x17, 0x03, 0x82, 0xf2, 0x90, 0x86, 0x36, 0x6a, 0x6d, 0x81, 0x84, 0xdf, 0x0e, 0xa8, + 0x1e, 0x45, 0xd2, 0xb2, 0x4f, 0x2f, 0x0b, 0x8b, 0xa1, 0x16, 0x9c, 0x5d, 0xd4, 0x82, 0x73, 0xf3, + 0x58, 0x70, 0xfe, 0x79, 0x2c, 0xb8, 0x30, 0x66, 0xc1, 0x47, 0xb0, 0x34, 0x96, 0x8a, 0x3a, 0xe6, + 0x20, 0x4c, 0x34, 0x87, 0xe8, 0x64, 0x73, 0x88, 0x79, 0xcc, 0x41, 0xfc, 0x22, 0x0a, 0x95, 0xf0, + 0x8c, 0x74, 0xe2, 0x07, 0x5e, 0x87, 0x0b, 0x6e, 0x66, 0xe2, 0x5d, 0x47, 0xe6, 0xfd, 0x91, 0xd3, + 0xe9, 0x2e, 0xe4, 0x94, 0x28, 0xce, 0xc6, 0x14, 0xf7, 0x9a, 0xe8, 0x43, 0x28, 0xfa, 0x73, 0x69, + 0x92, 0xaa, 0x90, 0xe3, 0xf2, 0x5f, 0x63, 0xc7, 0xc5, 0x5d, 0x0b, 0x67, 0xcc, 0x52, 0xe1, 0xcc, + 0xdb, 0x34, 0xd1, 0x55, 0x48, 0x99, 0x6a, 0x87, 0x66, 0x6c, 0xe4, 0x24, 0xe4, 0x1a, 0x11, 0x29, + 0x49, 0x08, 0x3b, 0xed, 0x9f, 0x09, 0xc2, 0x16, 0x40, 0x5a, 0xe6, 0xdd, 0xe2, 0x1f, 0xa3, 0x4e, + 0x4c, 0xf7, 0xa5, 0xd0, 0xe8, 0x6d, 0x48, 0x72, 0x1f, 0x20, 0xcc, 0xeb, 0x03, 0xb8, 0x40, 0xf0, + 0xdc, 0x47, 0x9f, 0xef, 0xdc, 0xc7, 0x26, 0x6e, 0x74, 0x7c, 0xf2, 0xa2, 0x26, 0xbc, 0x8b, 0xfa, + 0x2a, 0x24, 0xd8, 0xdd, 0x81, 0x85, 0x9e, 0x4b, 0xe3, 0x27, 0x88, 0x4e, 0x55, 0x62, 0x5c, 0xa8, + 0x0a, 0x69, 0x96, 0x9f, 0xab, 0x6d, 0xee, 0x2a, 0x2e, 0x87, 0x48, 0xec, 0x6c, 0x6f, 0x65, 0x9f, + 0x3e, 0x59, 0x4b, 0xf1, 0x86, 0x94, 0xa2, 0x72, 0x3b, 0x6d, 0xf1, 0xf7, 0x19, 0x48, 0x4b, 0xd8, + 0xd4, 0x89, 0xb1, 0xa3, 0x2d, 0xc8, 0xe0, 0x51, 0x0b, 0xeb, 0x96, 0x7d, 0x17, 0x98, 0x7c, 0xd7, + 0x62, 0xdc, 0x75, 0x9b, 0xb3, 0x11, 0x91, 0x5c, 0x31, 0x74, 0x87, 0x43, 0x22, 0xe1, 0xe8, 0x06, + 0x17, 0xf7, 0x62, 0x22, 0x6f, 0xda, 0x98, 0x08, 0x4b, 0x09, 0x56, 0x43, 0xa5, 0x02, 0xa0, 0xc8, + 0x1d, 0x0e, 0x8a, 0xc4, 0x67, 0x7c, 0xcc, 0x87, 0x8a, 0xd4, 0x7c, 0xa8, 0x48, 0x62, 0xc6, 0x34, + 0x43, 0x60, 0x91, 0x37, 0x6d, 0x58, 0x24, 0x39, 0x63, 0xc4, 0x01, 0x5c, 0xe4, 0xff, 0xc6, 0x70, + 0x91, 0xf5, 0x50, 0xd1, 0x09, 0xc0, 0xc8, 0xfe, 0x18, 0x30, 0x92, 0xa6, 0x4a, 0x5e, 0x0a, 0x55, + 0x32, 0x03, 0x19, 0xd9, 0x1f, 0x43, 0x46, 0x32, 0x33, 0x14, 0xce, 0x80, 0x46, 0x7e, 0x34, 0x19, + 0x1a, 0x81, 0x50, 0xf0, 0x82, 0x0f, 0x73, 0x3e, 0x6c, 0x44, 0x0e, 0xc1, 0x46, 0xb2, 0xa1, 0xf7, + 0x78, 0xa6, 0x7e, 0x6e, 0x70, 0xe4, 0x68, 0x02, 0x38, 0xc2, 0xd2, 0x9c, 0x9b, 0xa1, 0xca, 0xe7, + 0x40, 0x47, 0x8e, 0x26, 0xa0, 0x23, 0xf9, 0x99, 0x6a, 0x67, 0xc2, 0x23, 0xf7, 0xfc, 0xf0, 0x48, + 0x21, 0xe4, 0xf6, 0xe9, 0x1e, 0xd9, 0x10, 0x7c, 0xe4, 0x24, 0x0c, 0x1f, 0x61, 0xb8, 0xd0, 0x2b, + 0xa1, 0x1a, 0x17, 0x00, 0x48, 0xf6, 0xc7, 0x00, 0x92, 0xd2, 0x0c, 0x4b, 0x9b, 0x13, 0x21, 0x11, + 0x5f, 0x26, 0x51, 0x37, 0xe0, 0x94, 0x88, 0x83, 0xc5, 0x86, 0xa1, 0x19, 0x1c, 0xd3, 0x60, 0x0d, + 0xf1, 0x26, 0xb9, 0xe1, 0xba, 0x0e, 0x68, 0x0a, 0x6a, 0x52, 0x84, 0xbc, 0xcf, 0xe9, 0x88, 0xbf, + 0x16, 0x5c, 0x59, 0x8a, 0x9b, 0x78, 0x6f, 0xc7, 0x19, 0x7e, 0x3b, 0x0e, 0xdc, 0xe8, 0x32, 0xbe, + 0xdc, 0xc1, 0x9b, 0x9d, 0x70, 0x98, 0x44, 0x71, 0xb3, 0x92, 0x5b, 0xb0, 0x44, 0xf3, 0x58, 0xe6, + 0xd1, 0x7d, 0x41, 0xa3, 0x48, 0x3a, 0xd8, 0x2a, 0xb0, 0xe8, 0xf1, 0x2a, 0x2c, 0x7b, 0x78, 0x9d, + 0x2b, 0x29, 0xc3, 0x0a, 0x4a, 0x0e, 0x77, 0x95, 0xdf, 0x4d, 0xff, 0x1a, 0x75, 0x57, 0xc8, 0xc5, + 0x57, 0x26, 0x41, 0x21, 0xc2, 0x33, 0x43, 0x21, 0xe1, 0x57, 0x63, 0xf4, 0x21, 0xac, 0xf8, 0x50, + 0x12, 0x3b, 0x4d, 0x8c, 0x2d, 0x06, 0x96, 0x44, 0x3c, 0x59, 0x8b, 0xd3, 0x83, 0x3e, 0x82, 0x2b, + 0x34, 0xe1, 0x0d, 0x49, 0x45, 0xe3, 0xf3, 0xa5, 0xa2, 0x97, 0x88, 0x8e, 0xda, 0x84, 0x74, 0x34, + 0x04, 0x42, 0x49, 0x84, 0x41, 0x28, 0xff, 0x10, 0x5c, 0xbb, 0x71, 0x40, 0x94, 0x96, 0xd6, 0x66, + 0xf6, 0x95, 0x97, 0xe8, 0x6f, 0x72, 0x9d, 0xe9, 0x69, 0x1d, 0x6e, 0x22, 0xe4, 0x27, 0xe1, 0x72, + 0xe0, 0xfd, 0x0c, 0x0f, 0x54, 0x2b, 0x90, 0x50, 0x07, 0x6d, 0x3c, 0xe2, 0x56, 0xc0, 0x1a, 0x44, + 0xf6, 0x11, 0x3e, 0xe7, 0x7b, 0x4d, 0x7e, 0x12, 0x3e, 0x7a, 0x10, 0x58, 0xe6, 0x24, 0xb1, 0x06, + 0x7a, 0x0b, 0x32, 0xb4, 0x46, 0x23, 0x6b, 0xba, 0xc9, 0x43, 0x8d, 0x2f, 0x23, 0x62, 0xf5, 0x94, + 0x8d, 0x03, 0xc2, 0xb3, 0xaf, 0x9b, 0x52, 0x5a, 0xe7, 0xbf, 0x3c, 0x39, 0x4b, 0xda, 0x97, 0xb3, + 0x5c, 0x85, 0x0c, 0x19, 0xbd, 0xa9, 0x2b, 0x2d, 0x4c, 0xc3, 0x44, 0x46, 0x72, 0x09, 0xe2, 0x6f, + 0x05, 0x28, 0x06, 0x22, 0xd7, 0xc4, 0xb9, 0xdb, 0xc7, 0x26, 0xea, 0x07, 0x95, 0xc6, 0x66, 0x7f, + 0x0d, 0xa0, 0xa3, 0x98, 0xf2, 0x63, 0x65, 0x60, 0xe1, 0x36, 0x5f, 0x82, 0x4c, 0x47, 0x31, 0xdf, + 0xa7, 0x04, 0xff, 0x60, 0x12, 0x81, 0xc1, 0x78, 0x60, 0x8d, 0xa4, 0x17, 0xd6, 0x40, 0x15, 0x48, + 0xeb, 0x86, 0xaa, 0x19, 0xaa, 0x75, 0x4e, 0xd7, 0x24, 0x26, 0x39, 0x6d, 0xf1, 0x00, 0x2e, 0x4c, + 0x0c, 0x9a, 0xe8, 0x2e, 0x64, 0xdc, 0x78, 0x2b, 0xd0, 0xdc, 0x70, 0x0a, 0x5a, 0xe4, 0xf2, 0x92, + 0x25, 0xb9, 0x30, 0x31, 0x6c, 0xa2, 0x3a, 0x24, 0x0d, 0x6c, 0x0e, 0x7b, 0x2c, 0x57, 0x2d, 0xdc, + 0x7e, 0x75, 0xbe, 0x70, 0x4b, 0xa8, 0xc3, 0x9e, 0x25, 0x71, 0x61, 0xf1, 0x63, 0x48, 0x32, 0x0a, + 0xca, 0x42, 0xea, 0x68, 0xef, 0xc1, 0xde, 0xfe, 0xfb, 0x7b, 0xa5, 0x08, 0x02, 0x48, 0x56, 0x6b, + 0xb5, 0xfa, 0x41, 0xb3, 0x24, 0xa0, 0x0c, 0x24, 0xaa, 0x5b, 0xfb, 0x52, 0xb3, 0x14, 0x25, 0x64, + 0xa9, 0x7e, 0xbf, 0x5e, 0x6b, 0x96, 0x62, 0x68, 0x09, 0xf2, 0xec, 0xb7, 0x7c, 0x6f, 0x5f, 0x7a, + 0x58, 0x6d, 0x96, 0xe2, 0x1e, 0xd2, 0x61, 0x7d, 0x6f, 0xbb, 0x2e, 0x95, 0x12, 0xe2, 0xeb, 0x70, + 0x39, 0x34, 0x40, 0xbb, 0x80, 0x92, 0xe0, 0x01, 0x94, 0xc4, 0x6f, 0xe8, 0x5d, 0x25, 0x2c, 0xea, + 0xa2, 0xfb, 0x81, 0x89, 0xdf, 0x5e, 0x20, 0x64, 0x07, 0x66, 0x8f, 0x5e, 0x84, 0x82, 0x81, 0x4f, + 0xb1, 0xd5, 0xea, 0xb2, 0x2c, 0xc0, 0x46, 0x9c, 0xf2, 0x9c, 0x4a, 0x85, 0x4c, 0xc6, 0xf6, 0x09, + 0x6e, 0x59, 0x32, 0x33, 0x02, 0x93, 0xde, 0xeb, 0x33, 0x84, 0x8d, 0x50, 0x0f, 0x19, 0x91, 0x38, + 0x68, 0xe6, 0x48, 0x98, 0xaa, 0x38, 0x55, 0x05, 0xd4, 0x2f, 0x50, 0x8a, 0xf8, 0x78, 0xa1, 0xc5, + 0xce, 0x40, 0x42, 0xaa, 0x37, 0xa5, 0x0f, 0x4a, 0x31, 0x84, 0xa0, 0x40, 0x7f, 0xca, 0x87, 0x7b, + 0xd5, 0x83, 0xc3, 0xc6, 0x3e, 0x59, 0xec, 0x65, 0x28, 0xda, 0x8b, 0x6d, 0x13, 0x13, 0xe8, 0x02, + 0x2c, 0xd5, 0xf6, 0x1f, 0x1e, 0xec, 0xd6, 0x9b, 0x75, 0x97, 0x9c, 0x14, 0x7f, 0x13, 0x83, 0x4b, + 0x21, 0xb9, 0x06, 0x7a, 0x0b, 0xc0, 0x1a, 0xc9, 0x06, 0x6e, 0x69, 0x46, 0x3b, 0xdc, 0x38, 0x9b, + 0x23, 0x89, 0x72, 0x48, 0x19, 0x8b, 0xff, 0x9a, 0xea, 0xb0, 0xdf, 0xe5, 0x4a, 0xc9, 0x64, 0x4d, + 0x8e, 0x82, 0x5c, 0x9b, 0x70, 0xad, 0xc3, 0x2d, 0xa2, 0x98, 0xee, 0x09, 0x55, 0x4c, 0xf9, 0xd1, + 0x07, 0x70, 0x29, 0x10, 0x57, 0xb8, 0x33, 0x36, 0x27, 0x95, 0x20, 0x27, 0x87, 0x97, 0x0b, 0xfe, + 0xf0, 0xc2, 0x9c, 0xb1, 0x39, 0x05, 0x72, 0x48, 0x3c, 0x07, 0xe4, 0x10, 0x16, 0x9f, 0x92, 0x8b, + 0x82, 0xf9, 0x13, 0xe2, 0x93, 0xf8, 0x2b, 0xdf, 0xe6, 0xf9, 0xd3, 0xb7, 0x7d, 0x48, 0x9a, 0x96, + 0x62, 0x0d, 0x4d, 0x7e, 0x18, 0xee, 0xce, 0x9b, 0x0b, 0x6e, 0xd8, 0x3f, 0x0e, 0xa9, 0xb8, 0xc4, + 0xd5, 0xfc, 0x47, 0xee, 0x69, 0xd8, 0xea, 0x27, 0xbe, 0x8f, 0xd5, 0x7f, 0x03, 0x0a, 0xfe, 0xa5, + 0x0a, 0x3f, 0xbb, 0xae, 0x77, 0x8c, 0x8a, 0x3d, 0x58, 0x9e, 0x00, 0x5a, 0xa0, 0xbb, 0xbc, 0x2e, + 0xc1, 0x76, 0xeb, 0xfa, 0xf8, 0x94, 0x7d, 0xec, 0x6e, 0x79, 0x82, 0x04, 0x2b, 0x37, 0xa7, 0x66, + 0x1b, 0xe3, 0x12, 0xc4, 0x16, 0xa0, 0xf1, 0x0c, 0x7d, 0x12, 0xc0, 0x22, 0x3c, 0x3b, 0xc0, 0x22, + 0xfe, 0x42, 0x80, 0x2b, 0x53, 0xb2, 0x76, 0xf4, 0x5e, 0xc0, 0x16, 0xdf, 0x5e, 0x24, 0xe7, 0xdf, + 0x60, 0x34, 0xbf, 0x35, 0x8a, 0x77, 0x20, 0xe7, 0xa5, 0xcf, 0xb7, 0xf4, 0x3f, 0xf5, 0xc4, 0x4c, + 0x3f, 0xbe, 0xd3, 0x80, 0x24, 0x3e, 0xc3, 0x03, 0x27, 0x06, 0x5f, 0x1c, 0x5f, 0x07, 0xd2, 0xbd, + 0x55, 0x26, 0xb9, 0xe2, 0xdf, 0x9e, 0xac, 0x95, 0x18, 0xf7, 0x2b, 0x5a, 0x5f, 0xb5, 0x70, 0x5f, + 0xb7, 0xce, 0x25, 0x2e, 0x8f, 0xae, 0x43, 0xde, 0xc0, 0x16, 0x71, 0x21, 0x3e, 0x10, 0x2e, 0xc7, + 0x88, 0x3c, 0x93, 0xfb, 0x83, 0x00, 0xe0, 0x02, 0x46, 0x2e, 0x60, 0x23, 0x78, 0x01, 0x9b, 0x00, + 0x22, 0x18, 0x0d, 0x22, 0x82, 0xe8, 0x06, 0x14, 0x59, 0x92, 0x6e, 0xaa, 0x9d, 0x81, 0x62, 0x0d, + 0x0d, 0xcc, 0xe1, 0xa1, 0x02, 0x25, 0x1f, 0xda, 0x54, 0xf4, 0x21, 0x5c, 0xb6, 0xba, 0x06, 0x36, + 0xbb, 0x5a, 0xaf, 0x2d, 0x07, 0x37, 0x9e, 0x15, 0x38, 0xd6, 0x66, 0x18, 0x9c, 0x74, 0xc9, 0xd1, + 0x70, 0xec, 0xdf, 0xfc, 0xcf, 0x20, 0x41, 0xd7, 0x86, 0x24, 0x5a, 0x8e, 0x05, 0x67, 0xb8, 0x71, + 0x7e, 0x04, 0xa0, 0x58, 0x96, 0xa1, 0x9e, 0x0c, 0xc9, 0x71, 0x8e, 0x8e, 0x7f, 0xca, 0x5d, 0xdb, + 0xaa, 0xcd, 0xb7, 0x75, 0x95, 0x2f, 0xf2, 0x8a, 0x2b, 0xea, 0x59, 0x68, 0x8f, 0x42, 0x71, 0x0f, + 0x0a, 0x7e, 0x59, 0x3b, 0x83, 0x65, 0x63, 0xf0, 0x67, 0xb0, 0x2c, 0x23, 0xe6, 0x19, 0xac, 0x93, + 0xff, 0xc6, 0x58, 0xf9, 0x90, 0x36, 0xc4, 0x7f, 0x0a, 0x90, 0xf3, 0xba, 0xa9, 0xb9, 0x93, 0x4c, + 0x9e, 0x74, 0xc7, 0xc6, 0x93, 0xee, 0x78, 0x68, 0xda, 0x99, 0x08, 0xa6, 0x9d, 0x97, 0x21, 0x4d, + 0xba, 0x87, 0x26, 0x6e, 0xf3, 0x9a, 0x6b, 0xaa, 0xa3, 0x98, 0x47, 0x26, 0x6e, 0x7b, 0xec, 0x33, + 0xf5, 0x9c, 0xf6, 0xe9, 0xcb, 0x6d, 0xd3, 0xc1, 0x44, 0xfb, 0x73, 0x01, 0xd2, 0xce, 0xe4, 0xfd, + 0xa5, 0x45, 0x1f, 0xbe, 0xc8, 0xd6, 0x8e, 0x15, 0x16, 0xf9, 0xdd, 0x81, 0x15, 0x5a, 0x63, 0x4e, + 0xa1, 0xf5, 0x1d, 0x27, 0x1b, 0x0b, 0x43, 0xd0, 0xbc, 0x2b, 0x6d, 0x83, 0xa6, 0x3c, 0xf9, 0xfc, + 0x39, 0x1f, 0x07, 0x49, 0x27, 0xd0, 0xff, 0x42, 0x52, 0x69, 0x39, 0xb8, 0x61, 0x61, 0x02, 0xa0, + 0x66, 0xb3, 0x6e, 0x34, 0x47, 0x55, 0xca, 0x29, 0x71, 0x09, 0x3e, 0xaa, 0xa8, 0x3d, 0x2a, 0x71, + 0x97, 0xe8, 0x65, 0x3c, 0x7e, 0x9f, 0x51, 0x00, 0x38, 0xda, 0x7b, 0xb8, 0xbf, 0xbd, 0x73, 0x6f, + 0xa7, 0xbe, 0xcd, 0xd3, 0xad, 0xed, 0xed, 0xfa, 0x76, 0x29, 0x4a, 0xf8, 0xa4, 0xfa, 0xc3, 0xfd, + 0xe3, 0xfa, 0x76, 0x29, 0x46, 0x1a, 0xdb, 0xf5, 0xdd, 0xea, 0x07, 0xf5, 0xed, 0x52, 0x5c, 0xac, + 0x42, 0xc6, 0x09, 0x19, 0xb4, 0x22, 0xad, 0x3d, 0xc6, 0x06, 0x5f, 0x2d, 0xd6, 0x40, 0xab, 0x90, + 0x1d, 0x87, 0xc8, 0xc9, 0xed, 0x89, 0x21, 0xe3, 0xe2, 0x2f, 0x05, 0x28, 0x3a, 0x3a, 0x78, 0xd2, + 0xf0, 0x0e, 0xa4, 0xf4, 0xe1, 0x89, 0x6c, 0x1b, 0x72, 0x00, 0x2e, 0xb6, 0x2f, 0x57, 0xc3, 0x93, + 0x9e, 0xda, 0x7a, 0x80, 0xcf, 0x79, 0x88, 0x4a, 0xea, 0xc3, 0x93, 0x07, 0xcc, 0xde, 0xd9, 0x30, + 0xa2, 0x53, 0x86, 0x11, 0x0b, 0x0c, 0x03, 0xdd, 0x80, 0xdc, 0x40, 0x6b, 0x63, 0x59, 0x69, 0xb7, + 0x0d, 0x6c, 0xb2, 0xc8, 0x9b, 0xe1, 0x9a, 0xb3, 0xa4, 0xa7, 0xca, 0x3a, 0xc4, 0x6f, 0x05, 0x40, + 0xe3, 0x61, 0x12, 0x1d, 0xc2, 0x92, 0x1b, 0x69, 0xed, 0xf0, 0xcd, 0x7c, 0xe9, 0x7a, 0x78, 0x98, + 0xf5, 0xdd, 0xc0, 0x4b, 0x67, 0x7e, 0x32, 0x49, 0xc9, 0x56, 0x5c, 0xbf, 0xa5, 0xd3, 0xf9, 0xd2, + 0x45, 0x89, 0xce, 0xb9, 0x28, 0x11, 0x09, 0x39, 0xf2, 0x4e, 0x4f, 0xd0, 0xaf, 0xc6, 0xc6, 0x2a, + 0x2d, 0x3a, 0x94, 0x9b, 0x63, 0x62, 0x7c, 0x9e, 0x61, 0x43, 0x12, 0x9e, 0x67, 0x48, 0xe2, 0x1d, + 0x28, 0xbd, 0xe7, 0x7c, 0x9f, 0x7f, 0x29, 0x30, 0x4c, 0x61, 0x6c, 0x98, 0x67, 0x90, 0x26, 0xae, + 0x98, 0x46, 0x90, 0xff, 0x87, 0x8c, 0xb3, 0x7a, 0xce, 0xa3, 0x96, 0xd0, 0x65, 0xe7, 0x23, 0x71, + 0x45, 0xd0, 0x2d, 0x58, 0x22, 0x41, 0xc4, 0xae, 0x77, 0x32, 0x0c, 0x2d, 0x4a, 0x5d, 0x63, 0x91, + 0x75, 0xec, 0xda, 0xc0, 0x0f, 0x89, 0xf6, 0x25, 0x96, 0x15, 0xe0, 0xf6, 0xbf, 0x63, 0x00, 0xe4, + 0xd2, 0x15, 0x80, 0x12, 0xd9, 0x1e, 0xe6, 0x7d, 0x69, 0x89, 0xf8, 0xe3, 0x28, 0x64, 0x3d, 0x55, + 0x15, 0xf4, 0x3f, 0xbe, 0x0c, 0x6b, 0x7d, 0x5a, 0x05, 0xc6, 0x93, 0x5e, 0xf9, 0x26, 0x16, 0x5d, + 0x7c, 0x62, 0x61, 0x95, 0x2f, 0xbb, 0x0c, 0x1b, 0x5f, 0xb8, 0x0c, 0xfb, 0x0a, 0x20, 0x4b, 0xb3, + 0x94, 0x1e, 0x89, 0xe4, 0xea, 0xa0, 0x23, 0xb3, 0xd3, 0xce, 0xa2, 0x49, 0x89, 0xf6, 0x1c, 0xd3, + 0x8e, 0x03, 0x42, 0x17, 0x7b, 0x90, 0x76, 0x90, 0x81, 0xc5, 0xdf, 0x8a, 0x4c, 0x2a, 0x37, 0x57, + 0x20, 0xdd, 0xc7, 0x96, 0x42, 0x63, 0x20, 0x43, 0x8a, 0x9c, 0xf6, 0xad, 0xb7, 0x21, 0xeb, 0x79, + 0x40, 0x43, 0xc2, 0xe2, 0x5e, 0xfd, 0xfd, 0x52, 0xa4, 0x92, 0xfa, 0xe2, 0xab, 0xf5, 0xd8, 0x1e, + 0x7e, 0x4c, 0x3e, 0x25, 0xd5, 0x6b, 0x8d, 0x7a, 0xed, 0x41, 0x49, 0xa8, 0x64, 0xbf, 0xf8, 0x6a, + 0x3d, 0x25, 0x61, 0x5a, 0x80, 0xb8, 0xf5, 0x00, 0x8a, 0x81, 0x1d, 0xf0, 0x3b, 0x68, 0x04, 0x85, + 0xed, 0xa3, 0x83, 0xdd, 0x9d, 0x5a, 0xb5, 0x59, 0x97, 0x8f, 0xf7, 0x9b, 0xf5, 0x92, 0x80, 0x2e, + 0xc1, 0xf2, 0xee, 0xce, 0x0f, 0x1a, 0x4d, 0xb9, 0xb6, 0xbb, 0x53, 0xdf, 0x6b, 0xca, 0xd5, 0x66, + 0xb3, 0x5a, 0x7b, 0x50, 0x8a, 0xde, 0xfe, 0x33, 0x40, 0xb1, 0xba, 0x55, 0xdb, 0x21, 0x17, 0x7d, + 0xb5, 0xa5, 0x50, 0x77, 0x5f, 0x83, 0x38, 0xc5, 0x65, 0xa7, 0x3e, 0xa5, 0xad, 0x4c, 0xaf, 0x2a, + 0xa1, 0x7b, 0x90, 0xa0, 0x90, 0x2d, 0x9a, 0xfe, 0xb6, 0xb6, 0x32, 0xa3, 0xcc, 0x44, 0x06, 0x43, + 0xcf, 0xcd, 0xd4, 0xc7, 0xb6, 0x95, 0xe9, 0x55, 0x27, 0xb4, 0x0b, 0x29, 0x1b, 0x0d, 0x9b, 0xf5, + 0x02, 0xb6, 0x32, 0xb3, 0x14, 0x44, 0xa6, 0xc6, 0x50, 0xc5, 0xe9, 0xef, 0x70, 0x2b, 0x33, 0xea, + 0x51, 0x48, 0x82, 0x8c, 0x0b, 0x04, 0xcf, 0x7e, 0x12, 0x5c, 0x99, 0xa3, 0x3e, 0x86, 0x3e, 0x86, + 0xbc, 0x1f, 0x37, 0x9b, 0xef, 0xb5, 0x6e, 0x65, 0xce, 0xda, 0x15, 0xd1, 0xef, 0x07, 0xd1, 0xe6, + 0x7b, 0xbd, 0x5b, 0x99, 0xb3, 0x94, 0x85, 0x3e, 0x81, 0xa5, 0x71, 0x90, 0x6b, 0xfe, 0xc7, 0xbc, + 0x95, 0x05, 0x8a, 0x5b, 0xa8, 0x0f, 0x68, 0x02, 0x38, 0xb6, 0xc0, 0xdb, 0xde, 0xca, 0x22, 0xb5, + 0x2e, 0xd4, 0x86, 0x62, 0x10, 0x38, 0x9a, 0xf7, 0xad, 0x6f, 0x65, 0xee, 0xba, 0x17, 0xfb, 0x8a, + 0x1f, 0xe1, 0x98, 0xf7, 0xed, 0x6f, 0x65, 0xee, 0x32, 0x18, 0x3a, 0x02, 0xf0, 0xdc, 0x92, 0xe7, + 0x78, 0x0b, 0x5c, 0x99, 0xa7, 0x20, 0x86, 0x74, 0x58, 0x9e, 0x74, 0x2d, 0x5e, 0xe4, 0x69, 0x70, + 0x65, 0xa1, 0x3a, 0x19, 0xb1, 0x67, 0xff, 0x05, 0x77, 0xbe, 0xa7, 0xc2, 0x95, 0x39, 0x0b, 0x66, + 0x5b, 0x5b, 0x5f, 0x3f, 0x5d, 0x15, 0xbe, 0x79, 0xba, 0x2a, 0x7c, 0xfb, 0x74, 0x55, 0xf8, 0xf2, + 0xbb, 0xd5, 0xc8, 0x37, 0xdf, 0xad, 0x46, 0xfe, 0xf4, 0xdd, 0x6a, 0xe4, 0x87, 0x37, 0x3b, 0xaa, + 0xd5, 0x1d, 0x9e, 0x6c, 0xb4, 0xb4, 0x3e, 0xfd, 0xa7, 0x86, 0xae, 0x9c, 0x6f, 0x32, 0x9d, 0xa4, + 0xe5, 0xf9, 0x3f, 0xc8, 0x49, 0x92, 0xc6, 0xba, 0x3b, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x0a, + 0x1d, 0x02, 0xcd, 0x2f, 0x32, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -6182,6 +6221,15 @@ func (m *RequestVerifyVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, err _ = i var l int _ = l + if m.XSignId != nil { + { + size := m.XSignId.Size() + i -= size + if _, err := m.XSignId.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } if len(m.VoteExtensions) > 0 { for iNdEx := len(m.VoteExtensions) - 1; iNdEx >= 0; iNdEx-- { { @@ -6223,6 +6271,22 @@ func (m *RequestVerifyVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, err return len(dAtA) - i, nil } +func (m *RequestVerifyVoteExtension_SignId) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RequestVerifyVoteExtension_SignId) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.SignId != nil { + i -= len(m.SignId) + copy(dAtA[i:], m.SignId) + i = encodeVarintTypes(dAtA, i, uint64(len(m.SignId))) + i-- + dAtA[i] = 0x32 + } + return len(dAtA) - i, nil +} func (m *RequestFinalizeBlock) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -8759,9 +8823,24 @@ func (m *RequestVerifyVoteExtension) Size() (n int) { n += 1 + l + sovTypes(uint64(l)) } } + if m.XSignId != nil { + n += m.XSignId.Size() + } return n } +func (m *RequestVerifyVoteExtension_SignId) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SignId != nil { + l = len(m.SignId) + n += 1 + l + sovTypes(uint64(l)) + } + return n +} func (m *RequestFinalizeBlock) Size() (n int) { if m == nil { return 0 @@ -12663,6 +12742,39 @@ func (m *RequestVerifyVoteExtension) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SignId", 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 + } + v := make([]byte, postIndex-iNdEx) + copy(v, dAtA[iNdEx:postIndex]) + m.XSignId = &RequestVerifyVoteExtension_SignId{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index db1b346831..29ce336fd2 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -450,6 +450,11 @@ message RequestVerifyVoteExtension { int32 round = 4; // // Round number for the block. // Application-specific information signed by Tenderdash. Can have 0 length. repeated ExtendVoteExtension vote_extensions = 5; + // Sign ID that will be used to sign the vote extensions. + // If not set, Tenderdash will generate it based on height and round. + // It should be unique per voting round. + // Use with caution - it can have severe security consequences. + optional bytes sign_id = 6; } // Finalize newly decided block. diff --git a/spec/abci++/api.md b/spec/abci++/api.md index c059cbfe85..3fe415ec5c 100644 --- a/spec/abci++/api.md +++ b/spec/abci++/api.md @@ -774,6 +774,7 @@ from this condition, but not sure), and _p_ receives a Precommit message for rou | height | [int64](#int64) | | Height of the block (for sanity check). | | round | [int32](#int32) | | Round number for the block. | | vote_extensions | [ExtendVoteExtension](#tendermint-abci-ExtendVoteExtension) | repeated | Application-specific information signed by Tenderdash. Can have 0 length. | +| sign_id | [bytes](#bytes) | optional | Sign ID that will be used to sign the vote extensions. If not set, Tenderdash will generate it based on height and round. It should be unique per voting round. Use with caution - it can have severe security consequences. | From 4e1028f887ec08592244a298bf08fa82ae9b70a7 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:23:27 +0100 Subject: [PATCH 02/55] chore: improve docs --- proto/tendermint/abci/types.proto | 4 +++- spec/abci++/api.md | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 29ce336fd2..167ae0c79c 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -452,7 +452,9 @@ message RequestVerifyVoteExtension { repeated ExtendVoteExtension vote_extensions = 5; // Sign ID that will be used to sign the vote extensions. // If not set, Tenderdash will generate it based on height and round. - // It should be unique per voting round. + + // If set, it SHOULD be unique per voting round, and it MUST start with `dpbvote` string. + // // Use with caution - it can have severe security consequences. optional bytes sign_id = 6; } diff --git a/spec/abci++/api.md b/spec/abci++/api.md index 3fe415ec5c..6af288bf5a 100644 --- a/spec/abci++/api.md +++ b/spec/abci++/api.md @@ -773,8 +773,12 @@ from this condition, but not sure), and _p_ receives a Precommit message for rou | validator_pro_tx_hash | [bytes](#bytes) | | ProTxHash of the validator that signed the extensions. | | height | [int64](#int64) | | Height of the block (for sanity check). | | round | [int32](#int32) | | Round number for the block. | -| vote_extensions | [ExtendVoteExtension](#tendermint-abci-ExtendVoteExtension) | repeated | Application-specific information signed by Tenderdash. Can have 0 length. | -| sign_id | [bytes](#bytes) | optional | Sign ID that will be used to sign the vote extensions. If not set, Tenderdash will generate it based on height and round. It should be unique per voting round. Use with caution - it can have severe security consequences. | +| vote_extensions | [ExtendVoteExtension](#tendermint-abci-ExtendVoteExtension) | repeated | Application-specific information signed by Tenderdash. Can have 0 length. + +Sign ID that will be used to sign the vote extensions. If not set, Tenderdash will generate it based on height and round. | +| sign_id | [bytes](#bytes) | optional | If set, it SHOULD be unique per voting round, and it MUST start with `dpbvote` string. + +Use with caution - it can have severe security consequences. | From 8040f9fb8024f841b310c8be734a03db3f3b7eee Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:26:42 +0100 Subject: [PATCH 03/55] chore: rename proto sign_id --- abci/types/types.pb.go | 520 +++++++++++++++--------------- proto/tendermint/abci/types.proto | 4 +- spec/abci++/api.md | 4 +- 3 files changed, 264 insertions(+), 264 deletions(-) diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 15b9d4ed81..97aba029b9 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -1739,10 +1739,10 @@ type RequestVerifyVoteExtension struct { Round int32 `protobuf:"varint,4,opt,name=round,proto3" json:"round,omitempty"` // Application-specific information signed by Tenderdash. Can have 0 length. VoteExtensions []*ExtendVoteExtension `protobuf:"bytes,5,rep,name=vote_extensions,json=voteExtensions,proto3" json:"vote_extensions,omitempty"` - // Types that are valid to be assigned to XSignId: + // Types that are valid to be assigned to XSignRequestId: // - // *RequestVerifyVoteExtension_SignId - XSignId isRequestVerifyVoteExtension_XSignId `protobuf_oneof:"_sign_id"` + // *RequestVerifyVoteExtension_SignRequestId + XSignRequestId isRequestVerifyVoteExtension_XSignRequestId `protobuf_oneof:"_sign_request_id"` } func (m *RequestVerifyVoteExtension) Reset() { *m = RequestVerifyVoteExtension{} } @@ -1778,21 +1778,21 @@ func (m *RequestVerifyVoteExtension) XXX_DiscardUnknown() { var xxx_messageInfo_RequestVerifyVoteExtension proto.InternalMessageInfo -type isRequestVerifyVoteExtension_XSignId interface { - isRequestVerifyVoteExtension_XSignId() +type isRequestVerifyVoteExtension_XSignRequestId interface { + isRequestVerifyVoteExtension_XSignRequestId() MarshalTo([]byte) (int, error) Size() int } -type RequestVerifyVoteExtension_SignId struct { - SignId []byte `protobuf:"bytes,6,opt,name=sign_id,json=signId,proto3,oneof" json:"sign_id,omitempty"` +type RequestVerifyVoteExtension_SignRequestId struct { + SignRequestId []byte `protobuf:"bytes,6,opt,name=sign_request_id,json=signRequestId,proto3,oneof" json:"sign_request_id,omitempty"` } -func (*RequestVerifyVoteExtension_SignId) isRequestVerifyVoteExtension_XSignId() {} +func (*RequestVerifyVoteExtension_SignRequestId) isRequestVerifyVoteExtension_XSignRequestId() {} -func (m *RequestVerifyVoteExtension) GetXSignId() isRequestVerifyVoteExtension_XSignId { +func (m *RequestVerifyVoteExtension) GetXSignRequestId() isRequestVerifyVoteExtension_XSignRequestId { if m != nil { - return m.XSignId + return m.XSignRequestId } return nil } @@ -1832,9 +1832,9 @@ func (m *RequestVerifyVoteExtension) GetVoteExtensions() []*ExtendVoteExtension return nil } -func (m *RequestVerifyVoteExtension) GetSignId() []byte { - if x, ok := m.GetXSignId().(*RequestVerifyVoteExtension_SignId); ok { - return x.SignId +func (m *RequestVerifyVoteExtension) GetSignRequestId() []byte { + if x, ok := m.GetXSignRequestId().(*RequestVerifyVoteExtension_SignRequestId); ok { + return x.SignRequestId } return nil } @@ -1842,7 +1842,7 @@ func (m *RequestVerifyVoteExtension) GetSignId() []byte { // XXX_OneofWrappers is for the internal use of the proto package. func (*RequestVerifyVoteExtension) XXX_OneofWrappers() []interface{} { return []interface{}{ - (*RequestVerifyVoteExtension_SignId)(nil), + (*RequestVerifyVoteExtension_SignRequestId)(nil), } } @@ -4315,236 +4315,236 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 3655 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5b, 0xcb, 0x73, 0x1b, 0xc7, - 0xd1, 0xc7, 0xe2, 0x8d, 0xc6, 0x93, 0x43, 0x4a, 0x82, 0x20, 0x89, 0xa4, 0x57, 0x9f, 0x2d, 0x59, - 0x9f, 0x4d, 0xda, 0xd2, 0x67, 0xcb, 0xfe, 0xec, 0xef, 0xab, 0x02, 0x41, 0x28, 0xa0, 0x44, 0x91, - 0xf4, 0x12, 0xa4, 0xcb, 0x71, 0xec, 0xad, 0x25, 0x30, 0x04, 0xd6, 0x02, 0xb0, 0xeb, 0xdd, 0x05, - 0x05, 0xfa, 0x9a, 0x38, 0x95, 0xf2, 0xc9, 0xff, 0x80, 0x6f, 0xc9, 0x31, 0x97, 0x9c, 0x52, 0x39, - 0x24, 0x95, 0x9b, 0x53, 0xb9, 0xf8, 0x98, 0x4b, 0x14, 0x97, 0x7c, 0x49, 0xe5, 0x96, 0x53, 0x6e, - 0xa9, 0xd4, 0x3c, 0xf6, 0x09, 0x2c, 0x1e, 0x92, 0xab, 0x52, 0xb9, 0x61, 0x7a, 0xba, 0x7b, 0xe7, - 0xd1, 0xd3, 0xdd, 0xf3, 0xeb, 0x01, 0x5c, 0xb1, 0xf0, 0xa0, 0x8d, 0x8d, 0xbe, 0x3a, 0xb0, 0x36, - 0x95, 0x93, 0x96, 0xba, 0x69, 0x9d, 0xeb, 0xd8, 0xdc, 0xd0, 0x0d, 0xcd, 0xd2, 0x50, 0xd1, 0xed, - 0xdc, 0x20, 0x9d, 0x95, 0x6b, 0x1e, 0xee, 0x96, 0x71, 0xae, 0x5b, 0xda, 0xa6, 0x6e, 0x68, 0xda, - 0x29, 0xe3, 0xaf, 0x78, 0x95, 0x51, 0x3d, 0x9b, 0x6d, 0xc5, 0xec, 0xf2, 0xce, 0xab, 0x63, 0x9d, - 0x27, 0x3d, 0xad, 0xf5, 0x28, 0xb4, 0xd7, 0x33, 0x10, 0x5f, 0x2f, 0xff, 0xee, 0x23, 0x7c, 0x6e, - 0xf7, 0x5e, 0x1b, 0x93, 0xd5, 0x15, 0x43, 0xe9, 0xdb, 0xdd, 0xab, 0x9e, 0xee, 0x33, 0x6c, 0x98, - 0xaa, 0x36, 0xf0, 0x29, 0x5f, 0xeb, 0x68, 0x5a, 0xa7, 0x87, 0x37, 0x69, 0xeb, 0x64, 0x78, 0xba, - 0x69, 0xa9, 0x7d, 0x6c, 0x5a, 0x4a, 0x5f, 0xe7, 0x0c, 0x2b, 0x1d, 0xad, 0xa3, 0xd1, 0x9f, 0x9b, - 0xe4, 0x17, 0xa3, 0x8a, 0x9f, 0x67, 0x20, 0x25, 0xe1, 0x4f, 0x87, 0xd8, 0xb4, 0xd0, 0x6d, 0x88, - 0xe3, 0x56, 0x57, 0x2b, 0x0b, 0xeb, 0xc2, 0xcd, 0xec, 0xed, 0xab, 0x1b, 0x81, 0x75, 0xdb, 0xe0, - 0x7c, 0xf5, 0x56, 0x57, 0x6b, 0x44, 0x24, 0xca, 0x8b, 0xde, 0x80, 0xc4, 0x69, 0x6f, 0x68, 0x76, - 0xcb, 0x51, 0x2a, 0x74, 0x2d, 0x4c, 0xe8, 0x1e, 0x61, 0x6a, 0x44, 0x24, 0xc6, 0x4d, 0x3e, 0xa5, - 0x0e, 0x4e, 0xb5, 0x72, 0x6c, 0xfa, 0xa7, 0x76, 0x06, 0xa7, 0xf4, 0x53, 0x84, 0x17, 0x6d, 0x01, - 0xa8, 0x03, 0xd5, 0x92, 0x5b, 0x5d, 0x45, 0x1d, 0x94, 0xe3, 0x54, 0xf2, 0x85, 0x70, 0x49, 0xd5, - 0xaa, 0x11, 0xc6, 0x46, 0x44, 0xca, 0xa8, 0x76, 0x83, 0x0c, 0xf7, 0xd3, 0x21, 0x36, 0xce, 0xcb, - 0x89, 0xe9, 0xc3, 0x7d, 0x8f, 0x30, 0x91, 0xe1, 0x52, 0x6e, 0xf4, 0x2e, 0xa4, 0x5b, 0x5d, 0xdc, - 0x7a, 0x24, 0x5b, 0xa3, 0x72, 0x8a, 0x4a, 0xae, 0x85, 0x49, 0xd6, 0x08, 0x5f, 0x73, 0xd4, 0x88, - 0x48, 0xa9, 0x16, 0xfb, 0x89, 0xf6, 0xa0, 0xd0, 0x53, 0x4d, 0x4b, 0x36, 0x07, 0x8a, 0x6e, 0x76, - 0x35, 0xcb, 0x2c, 0x67, 0xa9, 0x8e, 0x17, 0xc3, 0x74, 0xec, 0xaa, 0xa6, 0x75, 0x68, 0x33, 0x37, - 0x22, 0x52, 0xbe, 0xe7, 0x25, 0x10, 0x7d, 0xda, 0xe9, 0x29, 0x36, 0x1c, 0x85, 0xe5, 0xdc, 0x74, - 0x7d, 0xfb, 0x84, 0xdb, 0x96, 0x27, 0xfa, 0x34, 0x2f, 0x01, 0x7d, 0x08, 0xcb, 0x3d, 0x4d, 0x69, - 0x3b, 0xea, 0xe4, 0x56, 0x77, 0x38, 0x78, 0x54, 0xce, 0x53, 0xa5, 0x2f, 0x87, 0x0e, 0x52, 0x53, - 0xda, 0xb6, 0x8a, 0x1a, 0x11, 0x68, 0x44, 0xa4, 0xa5, 0x5e, 0x90, 0x88, 0x3e, 0x86, 0x15, 0x45, - 0xd7, 0x7b, 0xe7, 0x41, 0xed, 0x05, 0xaa, 0xfd, 0x56, 0x98, 0xf6, 0x2a, 0x91, 0x09, 0xaa, 0x47, - 0xca, 0x18, 0x15, 0x35, 0xa1, 0xa4, 0x1b, 0x58, 0x57, 0x0c, 0x2c, 0xeb, 0x86, 0xa6, 0x6b, 0xa6, - 0xd2, 0x2b, 0x17, 0xa9, 0xee, 0x1b, 0x61, 0xba, 0x0f, 0x18, 0xff, 0x01, 0x67, 0x6f, 0x44, 0xa4, - 0xa2, 0xee, 0x27, 0x31, 0xad, 0x5a, 0x0b, 0x9b, 0xa6, 0xab, 0xb5, 0x34, 0x4b, 0x2b, 0xe5, 0xf7, - 0x6b, 0xf5, 0x91, 0x50, 0x1d, 0xb2, 0x78, 0x44, 0xc4, 0xe5, 0x33, 0xcd, 0xc2, 0xe5, 0x25, 0xaa, - 0x50, 0x0c, 0x3d, 0x67, 0x94, 0xf5, 0x58, 0xb3, 0x70, 0x23, 0x22, 0x01, 0x76, 0x5a, 0x48, 0x81, - 0x0b, 0x67, 0xd8, 0x50, 0x4f, 0xcf, 0xa9, 0x1a, 0x99, 0xf6, 0x10, 0x7f, 0x50, 0x46, 0x54, 0xe1, - 0x7f, 0x87, 0x29, 0x3c, 0xa6, 0x42, 0x44, 0x45, 0xdd, 0x16, 0x69, 0x44, 0xa4, 0xe5, 0xb3, 0x71, - 0x32, 0x31, 0xb1, 0x53, 0x75, 0xa0, 0xf4, 0xd4, 0xcf, 0xb0, 0x4c, 0x1d, 0x5c, 0x79, 0x79, 0xba, - 0x89, 0xdd, 0xe3, 0xdc, 0x5b, 0x84, 0x99, 0x98, 0xd8, 0xa9, 0x97, 0xb0, 0x95, 0x82, 0xc4, 0x99, - 0xd2, 0x1b, 0xe2, 0xfb, 0xf1, 0x74, 0xb2, 0x94, 0xba, 0x1f, 0x4f, 0xa7, 0x4b, 0x99, 0xfb, 0xf1, - 0x74, 0xa6, 0x04, 0xf7, 0xe3, 0x69, 0x28, 0x65, 0xc5, 0x1b, 0x90, 0xf5, 0xb8, 0x17, 0x54, 0x86, - 0x54, 0x1f, 0x9b, 0xa6, 0xd2, 0xc1, 0xd4, 0x1b, 0x65, 0x24, 0xbb, 0x29, 0x16, 0x20, 0xe7, 0x75, - 0x29, 0xe2, 0x97, 0x82, 0x23, 0x49, 0xbc, 0x05, 0x91, 0xe4, 0xee, 0xd1, 0x96, 0xe4, 0x4d, 0x74, - 0x1d, 0xf2, 0x74, 0x2a, 0xb2, 0xdd, 0x4f, 0x5c, 0x56, 0x5c, 0xca, 0x51, 0xe2, 0x31, 0x67, 0x5a, - 0x83, 0xac, 0x7e, 0x5b, 0x77, 0x58, 0x62, 0x94, 0x05, 0xf4, 0xdb, 0xba, 0xcd, 0xf0, 0x02, 0xe4, - 0xc8, 0xbc, 0x1d, 0x8e, 0x38, 0xfd, 0x48, 0x96, 0xd0, 0x38, 0x8b, 0xf8, 0x93, 0x18, 0x94, 0x82, - 0x6e, 0x08, 0xbd, 0x05, 0x71, 0xe2, 0x91, 0xb9, 0x73, 0xad, 0x6c, 0x30, 0x77, 0xbd, 0x61, 0xbb, - 0xeb, 0x8d, 0xa6, 0xed, 0xae, 0xb7, 0xd2, 0x5f, 0x3f, 0x59, 0x8b, 0x7c, 0xf9, 0x97, 0x35, 0x41, - 0xa2, 0x12, 0xe8, 0x32, 0x71, 0x3e, 0x8a, 0x3a, 0x90, 0xd5, 0x36, 0x1d, 0x72, 0x86, 0x78, 0x16, - 0x45, 0x1d, 0xec, 0xb4, 0xd1, 0x2e, 0x94, 0x5a, 0xda, 0xc0, 0xc4, 0x03, 0x73, 0x68, 0xca, 0x2c, - 0x5c, 0x70, 0x97, 0xea, 0x73, 0x8c, 0x2c, 0x4e, 0xd4, 0x6c, 0xce, 0x03, 0xca, 0x28, 0x15, 0x5b, - 0x7e, 0x02, 0xda, 0x83, 0xfc, 0x99, 0xd2, 0x53, 0xdb, 0x8a, 0xa5, 0x19, 0xb2, 0x89, 0x2d, 0xee, - 0x63, 0xaf, 0x8f, 0xed, 0xf9, 0xb1, 0xcd, 0x75, 0x88, 0xad, 0x23, 0xbd, 0xad, 0x58, 0x78, 0x2b, - 0xfe, 0xf5, 0x93, 0x35, 0x41, 0xca, 0x9d, 0x79, 0x7a, 0xd0, 0x4b, 0x50, 0x54, 0x74, 0x5d, 0x36, - 0x2d, 0xc5, 0xc2, 0xf2, 0xc9, 0xb9, 0x85, 0x4d, 0xea, 0x76, 0x73, 0x52, 0x5e, 0xd1, 0xf5, 0x43, - 0x42, 0xdd, 0x22, 0x44, 0xf4, 0x22, 0x14, 0x88, 0x87, 0x56, 0x95, 0x9e, 0xdc, 0xc5, 0x6a, 0xa7, - 0x6b, 0x95, 0x93, 0xeb, 0xc2, 0xcd, 0x98, 0x94, 0xe7, 0xd4, 0x06, 0x25, 0xa2, 0x0d, 0x58, 0xb6, - 0xd9, 0x5a, 0x9a, 0x81, 0x6d, 0x5e, 0xe2, 0x8f, 0xf3, 0xd2, 0x12, 0xef, 0xaa, 0x69, 0x06, 0x66, - 0xfc, 0x62, 0xdb, 0xb1, 0x14, 0xea, 0xcd, 0x11, 0x82, 0x78, 0x5b, 0xb1, 0x14, 0xba, 0x03, 0x39, - 0x89, 0xfe, 0x26, 0x34, 0x5d, 0xb1, 0xba, 0x7c, 0x5d, 0xe9, 0x6f, 0x74, 0x11, 0x92, 0x5c, 0x75, - 0x8c, 0x0e, 0x83, 0xb7, 0xd0, 0x0a, 0x24, 0x74, 0x43, 0x3b, 0xc3, 0x74, 0x59, 0xd2, 0x12, 0x6b, - 0x88, 0x12, 0x14, 0xfc, 0x9e, 0x1f, 0x15, 0x20, 0x6a, 0x8d, 0xf8, 0x57, 0xa2, 0xd6, 0x08, 0xbd, - 0x06, 0x71, 0xb2, 0x01, 0xf4, 0x1b, 0x85, 0x09, 0xb1, 0x8e, 0xcb, 0x35, 0xcf, 0x75, 0x2c, 0x51, - 0x4e, 0xf1, 0x22, 0xac, 0x4c, 0x8a, 0x04, 0x62, 0xd7, 0xa1, 0xfb, 0x3c, 0x3a, 0x7a, 0x03, 0xd2, - 0x4e, 0x28, 0x60, 0xf6, 0x75, 0x79, 0xec, 0x2b, 0x36, 0xb3, 0xe4, 0xb0, 0x12, 0xc3, 0x22, 0xfb, - 0xd3, 0x55, 0x78, 0xf8, 0xce, 0x49, 0x29, 0x45, 0xd7, 0x1b, 0x8a, 0xd9, 0x15, 0x3b, 0x50, 0x0e, - 0x73, 0xf3, 0x9e, 0xf5, 0x11, 0xe8, 0xe9, 0xb0, 0xd7, 0xc7, 0x73, 0xf2, 0xa2, 0x74, 0x4f, 0x9c, - 0x93, 0x47, 0x2d, 0x78, 0x38, 0x78, 0x44, 0x2c, 0x38, 0xc6, 0x3e, 0x44, 0xdb, 0x3b, 0x6d, 0xb1, - 0x0d, 0x97, 0x43, 0x3d, 0xbe, 0x4f, 0x4e, 0xf0, 0xc9, 0x91, 0xcd, 0x60, 0x71, 0x84, 0x0d, 0x9c, - 0x35, 0xc8, 0xd0, 0x4c, 0x3a, 0x6f, 0xfa, 0x99, 0x8c, 0xc4, 0x5b, 0xe2, 0xdf, 0xe3, 0x70, 0x71, - 0xb2, 0xf3, 0x47, 0xeb, 0x90, 0xeb, 0x2b, 0x23, 0xd9, 0x1a, 0x71, 0x0b, 0x15, 0xe8, 0x9e, 0x43, - 0x5f, 0x19, 0x35, 0x47, 0xcc, 0x3c, 0x4b, 0x10, 0xb3, 0x46, 0x66, 0x39, 0xba, 0x1e, 0xbb, 0x99, - 0x93, 0xc8, 0x4f, 0xf4, 0x10, 0x96, 0x7a, 0x5a, 0x4b, 0xe9, 0xc9, 0x3d, 0xc5, 0xb4, 0xe4, 0x96, - 0xd6, 0xef, 0xab, 0x16, 0x3f, 0x77, 0x57, 0xc6, 0xb7, 0x97, 0x76, 0x13, 0xdf, 0x44, 0x0f, 0x49, - 0x44, 0x2a, 0x52, 0xd9, 0x5d, 0xc5, 0xb4, 0x58, 0x17, 0xda, 0x86, 0x6c, 0x5f, 0x35, 0x4f, 0x70, - 0x57, 0x39, 0x53, 0x35, 0xa3, 0x1c, 0x5f, 0x8f, 0x4d, 0xcc, 0x89, 0x1e, 0xba, 0x3c, 0x5c, 0x93, - 0x57, 0xcc, 0xb3, 0x2d, 0x09, 0x9f, 0xd9, 0xda, 0x8e, 0x27, 0xb9, 0xb0, 0xe3, 0x79, 0x0d, 0x56, - 0x06, 0x78, 0x64, 0xc9, 0xce, 0xa1, 0x36, 0x99, 0xad, 0xa4, 0xe8, 0x92, 0x23, 0xd2, 0xe7, 0x78, - 0x02, 0x93, 0x98, 0x0d, 0xd9, 0x15, 0x43, 0x1b, 0x0e, 0xda, 0xe5, 0xf4, 0xba, 0x70, 0x33, 0x21, - 0xb1, 0x06, 0xba, 0x0b, 0x65, 0x7a, 0x60, 0x99, 0x17, 0x23, 0xde, 0x16, 0xb7, 0xed, 0xd3, 0x9b, - 0xa1, 0x96, 0x72, 0x81, 0xf4, 0x53, 0x3f, 0xb9, 0x4b, 0x7b, 0xf9, 0x89, 0xdf, 0x84, 0x15, 0x16, - 0x7d, 0xb1, 0x41, 0xc2, 0x30, 0xd9, 0x24, 0x3a, 0x00, 0xa0, 0x03, 0x58, 0xb2, 0xfb, 0x0e, 0x0c, - 0xad, 0x39, 0xa2, 0xdf, 0x7f, 0xcd, 0x11, 0x68, 0xcb, 0xc4, 0xb4, 0x6d, 0x7b, 0xcc, 0x52, 0x43, - 0x45, 0x76, 0x5f, 0x55, 0x77, 0xdc, 0xf9, 0x5d, 0xd7, 0x68, 0x73, 0xe3, 0x29, 0x21, 0xef, 0x72, - 0x5d, 0xa7, 0x6b, 0xd3, 0x6b, 0x90, 0xfd, 0x74, 0xa8, 0x19, 0xc3, 0x3e, 0x1b, 0x52, 0x9e, 0x0e, - 0x09, 0x18, 0x89, 0x1e, 0xa1, 0xdf, 0x25, 0x3c, 0x36, 0xe7, 0xcf, 0x03, 0xb8, 0x45, 0x09, 0xae, - 0x45, 0x1d, 0x7a, 0x06, 0xee, 0x35, 0xaa, 0xe8, 0xbc, 0x46, 0xe5, 0xcc, 0x2d, 0xdc, 0xae, 0x62, - 0xcf, 0x66, 0x57, 0x08, 0xe2, 0x74, 0x86, 0x71, 0xe6, 0x36, 0xc9, 0xef, 0x50, 0x5b, 0x73, 0xf6, - 0x3f, 0xe9, 0xdd, 0x7f, 0xdb, 0x02, 0x53, 0xdf, 0x9b, 0x05, 0xa6, 0x43, 0x2d, 0xf0, 0x99, 0x6d, - 0xad, 0x09, 0x17, 0x03, 0x82, 0xf2, 0x90, 0x86, 0x36, 0x6a, 0x6d, 0x81, 0x84, 0xdf, 0x0e, 0xa8, - 0x1e, 0x45, 0xd2, 0xb2, 0x4f, 0x2f, 0x0b, 0x8b, 0xa1, 0x16, 0x9c, 0x5d, 0xd4, 0x82, 0x73, 0xf3, - 0x58, 0x70, 0xfe, 0x79, 0x2c, 0xb8, 0x30, 0x66, 0xc1, 0x47, 0xb0, 0x34, 0x96, 0x8a, 0x3a, 0xe6, - 0x20, 0x4c, 0x34, 0x87, 0xe8, 0x64, 0x73, 0x88, 0x79, 0xcc, 0x41, 0xfc, 0x22, 0x0a, 0x95, 0xf0, - 0x8c, 0x74, 0xe2, 0x07, 0x5e, 0x87, 0x0b, 0x6e, 0x66, 0xe2, 0x5d, 0x47, 0xe6, 0xfd, 0x91, 0xd3, - 0xe9, 0x2e, 0xe4, 0x94, 0x28, 0xce, 0xc6, 0x14, 0xf7, 0x9a, 0xe8, 0x43, 0x28, 0xfa, 0x73, 0x69, - 0x92, 0xaa, 0x90, 0xe3, 0xf2, 0x5f, 0x63, 0xc7, 0xc5, 0x5d, 0x0b, 0x67, 0xcc, 0x52, 0xe1, 0xcc, - 0xdb, 0x34, 0xd1, 0x55, 0x48, 0x99, 0x6a, 0x87, 0x66, 0x6c, 0xe4, 0x24, 0xe4, 0x1a, 0x11, 0x29, - 0x49, 0x08, 0x3b, 0xed, 0x9f, 0x09, 0xc2, 0x16, 0x40, 0x5a, 0xe6, 0xdd, 0xe2, 0x1f, 0xa3, 0x4e, - 0x4c, 0xf7, 0xa5, 0xd0, 0xe8, 0x6d, 0x48, 0x72, 0x1f, 0x20, 0xcc, 0xeb, 0x03, 0xb8, 0x40, 0xf0, - 0xdc, 0x47, 0x9f, 0xef, 0xdc, 0xc7, 0x26, 0x6e, 0x74, 0x7c, 0xf2, 0xa2, 0x26, 0xbc, 0x8b, 0xfa, - 0x2a, 0x24, 0xd8, 0xdd, 0x81, 0x85, 0x9e, 0x4b, 0xe3, 0x27, 0x88, 0x4e, 0x55, 0x62, 0x5c, 0xa8, - 0x0a, 0x69, 0x96, 0x9f, 0xab, 0x6d, 0xee, 0x2a, 0x2e, 0x87, 0x48, 0xec, 0x6c, 0x6f, 0x65, 0x9f, - 0x3e, 0x59, 0x4b, 0xf1, 0x86, 0x94, 0xa2, 0x72, 0x3b, 0x6d, 0xf1, 0xf7, 0x19, 0x48, 0x4b, 0xd8, - 0xd4, 0x89, 0xb1, 0xa3, 0x2d, 0xc8, 0xe0, 0x51, 0x0b, 0xeb, 0x96, 0x7d, 0x17, 0x98, 0x7c, 0xd7, - 0x62, 0xdc, 0x75, 0x9b, 0xb3, 0x11, 0x91, 0x5c, 0x31, 0x74, 0x87, 0x43, 0x22, 0xe1, 0xe8, 0x06, - 0x17, 0xf7, 0x62, 0x22, 0x6f, 0xda, 0x98, 0x08, 0x4b, 0x09, 0x56, 0x43, 0xa5, 0x02, 0xa0, 0xc8, - 0x1d, 0x0e, 0x8a, 0xc4, 0x67, 0x7c, 0xcc, 0x87, 0x8a, 0xd4, 0x7c, 0xa8, 0x48, 0x62, 0xc6, 0x34, - 0x43, 0x60, 0x91, 0x37, 0x6d, 0x58, 0x24, 0x39, 0x63, 0xc4, 0x01, 0x5c, 0xe4, 0xff, 0xc6, 0x70, - 0x91, 0xf5, 0x50, 0xd1, 0x09, 0xc0, 0xc8, 0xfe, 0x18, 0x30, 0x92, 0xa6, 0x4a, 0x5e, 0x0a, 0x55, - 0x32, 0x03, 0x19, 0xd9, 0x1f, 0x43, 0x46, 0x32, 0x33, 0x14, 0xce, 0x80, 0x46, 0x7e, 0x34, 0x19, - 0x1a, 0x81, 0x50, 0xf0, 0x82, 0x0f, 0x73, 0x3e, 0x6c, 0x44, 0x0e, 0xc1, 0x46, 0xb2, 0xa1, 0xf7, - 0x78, 0xa6, 0x7e, 0x6e, 0x70, 0xe4, 0x68, 0x02, 0x38, 0xc2, 0xd2, 0x9c, 0x9b, 0xa1, 0xca, 0xe7, - 0x40, 0x47, 0x8e, 0x26, 0xa0, 0x23, 0xf9, 0x99, 0x6a, 0x67, 0xc2, 0x23, 0xf7, 0xfc, 0xf0, 0x48, - 0x21, 0xe4, 0xf6, 0xe9, 0x1e, 0xd9, 0x10, 0x7c, 0xe4, 0x24, 0x0c, 0x1f, 0x61, 0xb8, 0xd0, 0x2b, - 0xa1, 0x1a, 0x17, 0x00, 0x48, 0xf6, 0xc7, 0x00, 0x92, 0xd2, 0x0c, 0x4b, 0x9b, 0x13, 0x21, 0x11, - 0x5f, 0x26, 0x51, 0x37, 0xe0, 0x94, 0x88, 0x83, 0xc5, 0x86, 0xa1, 0x19, 0x1c, 0xd3, 0x60, 0x0d, - 0xf1, 0x26, 0xb9, 0xe1, 0xba, 0x0e, 0x68, 0x0a, 0x6a, 0x52, 0x84, 0xbc, 0xcf, 0xe9, 0x88, 0xbf, - 0x16, 0x5c, 0x59, 0x8a, 0x9b, 0x78, 0x6f, 0xc7, 0x19, 0x7e, 0x3b, 0x0e, 0xdc, 0xe8, 0x32, 0xbe, - 0xdc, 0xc1, 0x9b, 0x9d, 0x70, 0x98, 0x44, 0x71, 0xb3, 0x92, 0x5b, 0xb0, 0x44, 0xf3, 0x58, 0xe6, - 0xd1, 0x7d, 0x41, 0xa3, 0x48, 0x3a, 0xd8, 0x2a, 0xb0, 0xe8, 0xf1, 0x2a, 0x2c, 0x7b, 0x78, 0x9d, - 0x2b, 0x29, 0xc3, 0x0a, 0x4a, 0x0e, 0x77, 0x95, 0xdf, 0x4d, 0xff, 0x1a, 0x75, 0x57, 0xc8, 0xc5, - 0x57, 0x26, 0x41, 0x21, 0xc2, 0x33, 0x43, 0x21, 0xe1, 0x57, 0x63, 0xf4, 0x21, 0xac, 0xf8, 0x50, - 0x12, 0x3b, 0x4d, 0x8c, 0x2d, 0x06, 0x96, 0x44, 0x3c, 0x59, 0x8b, 0xd3, 0x83, 0x3e, 0x82, 0x2b, - 0x34, 0xe1, 0x0d, 0x49, 0x45, 0xe3, 0xf3, 0xa5, 0xa2, 0x97, 0x88, 0x8e, 0xda, 0x84, 0x74, 0x34, - 0x04, 0x42, 0x49, 0x84, 0x41, 0x28, 0xff, 0x10, 0x5c, 0xbb, 0x71, 0x40, 0x94, 0x96, 0xd6, 0x66, - 0xf6, 0x95, 0x97, 0xe8, 0x6f, 0x72, 0x9d, 0xe9, 0x69, 0x1d, 0x6e, 0x22, 0xe4, 0x27, 0xe1, 0x72, - 0xe0, 0xfd, 0x0c, 0x0f, 0x54, 0x2b, 0x90, 0x50, 0x07, 0x6d, 0x3c, 0xe2, 0x56, 0xc0, 0x1a, 0x44, - 0xf6, 0x11, 0x3e, 0xe7, 0x7b, 0x4d, 0x7e, 0x12, 0x3e, 0x7a, 0x10, 0x58, 0xe6, 0x24, 0xb1, 0x06, - 0x7a, 0x0b, 0x32, 0xb4, 0x46, 0x23, 0x6b, 0xba, 0xc9, 0x43, 0x8d, 0x2f, 0x23, 0x62, 0xf5, 0x94, - 0x8d, 0x03, 0xc2, 0xb3, 0xaf, 0x9b, 0x52, 0x5a, 0xe7, 0xbf, 0x3c, 0x39, 0x4b, 0xda, 0x97, 0xb3, - 0x5c, 0x85, 0x0c, 0x19, 0xbd, 0xa9, 0x2b, 0x2d, 0x4c, 0xc3, 0x44, 0x46, 0x72, 0x09, 0xe2, 0x6f, - 0x05, 0x28, 0x06, 0x22, 0xd7, 0xc4, 0xb9, 0xdb, 0xc7, 0x26, 0xea, 0x07, 0x95, 0xc6, 0x66, 0x7f, - 0x0d, 0xa0, 0xa3, 0x98, 0xf2, 0x63, 0x65, 0x60, 0xe1, 0x36, 0x5f, 0x82, 0x4c, 0x47, 0x31, 0xdf, - 0xa7, 0x04, 0xff, 0x60, 0x12, 0x81, 0xc1, 0x78, 0x60, 0x8d, 0xa4, 0x17, 0xd6, 0x40, 0x15, 0x48, - 0xeb, 0x86, 0xaa, 0x19, 0xaa, 0x75, 0x4e, 0xd7, 0x24, 0x26, 0x39, 0x6d, 0xf1, 0x00, 0x2e, 0x4c, - 0x0c, 0x9a, 0xe8, 0x2e, 0x64, 0xdc, 0x78, 0x2b, 0xd0, 0xdc, 0x70, 0x0a, 0x5a, 0xe4, 0xf2, 0x92, - 0x25, 0xb9, 0x30, 0x31, 0x6c, 0xa2, 0x3a, 0x24, 0x0d, 0x6c, 0x0e, 0x7b, 0x2c, 0x57, 0x2d, 0xdc, - 0x7e, 0x75, 0xbe, 0x70, 0x4b, 0xa8, 0xc3, 0x9e, 0x25, 0x71, 0x61, 0xf1, 0x63, 0x48, 0x32, 0x0a, - 0xca, 0x42, 0xea, 0x68, 0xef, 0xc1, 0xde, 0xfe, 0xfb, 0x7b, 0xa5, 0x08, 0x02, 0x48, 0x56, 0x6b, - 0xb5, 0xfa, 0x41, 0xb3, 0x24, 0xa0, 0x0c, 0x24, 0xaa, 0x5b, 0xfb, 0x52, 0xb3, 0x14, 0x25, 0x64, - 0xa9, 0x7e, 0xbf, 0x5e, 0x6b, 0x96, 0x62, 0x68, 0x09, 0xf2, 0xec, 0xb7, 0x7c, 0x6f, 0x5f, 0x7a, - 0x58, 0x6d, 0x96, 0xe2, 0x1e, 0xd2, 0x61, 0x7d, 0x6f, 0xbb, 0x2e, 0x95, 0x12, 0xe2, 0xeb, 0x70, - 0x39, 0x34, 0x40, 0xbb, 0x80, 0x92, 0xe0, 0x01, 0x94, 0xc4, 0x6f, 0xe8, 0x5d, 0x25, 0x2c, 0xea, - 0xa2, 0xfb, 0x81, 0x89, 0xdf, 0x5e, 0x20, 0x64, 0x07, 0x66, 0x8f, 0x5e, 0x84, 0x82, 0x81, 0x4f, - 0xb1, 0xd5, 0xea, 0xb2, 0x2c, 0xc0, 0x46, 0x9c, 0xf2, 0x9c, 0x4a, 0x85, 0x4c, 0xc6, 0xf6, 0x09, - 0x6e, 0x59, 0x32, 0x33, 0x02, 0x93, 0xde, 0xeb, 0x33, 0x84, 0x8d, 0x50, 0x0f, 0x19, 0x91, 0x38, - 0x68, 0xe6, 0x48, 0x98, 0xaa, 0x38, 0x55, 0x05, 0xd4, 0x2f, 0x50, 0x8a, 0xf8, 0x78, 0xa1, 0xc5, - 0xce, 0x40, 0x42, 0xaa, 0x37, 0xa5, 0x0f, 0x4a, 0x31, 0x84, 0xa0, 0x40, 0x7f, 0xca, 0x87, 0x7b, - 0xd5, 0x83, 0xc3, 0xc6, 0x3e, 0x59, 0xec, 0x65, 0x28, 0xda, 0x8b, 0x6d, 0x13, 0x13, 0xe8, 0x02, - 0x2c, 0xd5, 0xf6, 0x1f, 0x1e, 0xec, 0xd6, 0x9b, 0x75, 0x97, 0x9c, 0x14, 0x7f, 0x13, 0x83, 0x4b, - 0x21, 0xb9, 0x06, 0x7a, 0x0b, 0xc0, 0x1a, 0xc9, 0x06, 0x6e, 0x69, 0x46, 0x3b, 0xdc, 0x38, 0x9b, - 0x23, 0x89, 0x72, 0x48, 0x19, 0x8b, 0xff, 0x9a, 0xea, 0xb0, 0xdf, 0xe5, 0x4a, 0xc9, 0x64, 0x4d, - 0x8e, 0x82, 0x5c, 0x9b, 0x70, 0xad, 0xc3, 0x2d, 0xa2, 0x98, 0xee, 0x09, 0x55, 0x4c, 0xf9, 0xd1, - 0x07, 0x70, 0x29, 0x10, 0x57, 0xb8, 0x33, 0x36, 0x27, 0x95, 0x20, 0x27, 0x87, 0x97, 0x0b, 0xfe, - 0xf0, 0xc2, 0x9c, 0xb1, 0x39, 0x05, 0x72, 0x48, 0x3c, 0x07, 0xe4, 0x10, 0x16, 0x9f, 0x92, 0x8b, - 0x82, 0xf9, 0x13, 0xe2, 0x93, 0xf8, 0x2b, 0xdf, 0xe6, 0xf9, 0xd3, 0xb7, 0x7d, 0x48, 0x9a, 0x96, - 0x62, 0x0d, 0x4d, 0x7e, 0x18, 0xee, 0xce, 0x9b, 0x0b, 0x6e, 0xd8, 0x3f, 0x0e, 0xa9, 0xb8, 0xc4, - 0xd5, 0xfc, 0x47, 0xee, 0x69, 0xd8, 0xea, 0x27, 0xbe, 0x8f, 0xd5, 0x7f, 0x03, 0x0a, 0xfe, 0xa5, - 0x0a, 0x3f, 0xbb, 0xae, 0x77, 0x8c, 0x8a, 0x3d, 0x58, 0x9e, 0x00, 0x5a, 0xa0, 0xbb, 0xbc, 0x2e, - 0xc1, 0x76, 0xeb, 0xfa, 0xf8, 0x94, 0x7d, 0xec, 0x6e, 0x79, 0x82, 0x04, 0x2b, 0x37, 0xa7, 0x66, - 0x1b, 0xe3, 0x12, 0xc4, 0x16, 0xa0, 0xf1, 0x0c, 0x7d, 0x12, 0xc0, 0x22, 0x3c, 0x3b, 0xc0, 0x22, - 0xfe, 0x42, 0x80, 0x2b, 0x53, 0xb2, 0x76, 0xf4, 0x5e, 0xc0, 0x16, 0xdf, 0x5e, 0x24, 0xe7, 0xdf, - 0x60, 0x34, 0xbf, 0x35, 0x8a, 0x77, 0x20, 0xe7, 0xa5, 0xcf, 0xb7, 0xf4, 0x3f, 0xf5, 0xc4, 0x4c, - 0x3f, 0xbe, 0xd3, 0x80, 0x24, 0x3e, 0xc3, 0x03, 0x27, 0x06, 0x5f, 0x1c, 0x5f, 0x07, 0xd2, 0xbd, - 0x55, 0x26, 0xb9, 0xe2, 0xdf, 0x9e, 0xac, 0x95, 0x18, 0xf7, 0x2b, 0x5a, 0x5f, 0xb5, 0x70, 0x5f, - 0xb7, 0xce, 0x25, 0x2e, 0x8f, 0xae, 0x43, 0xde, 0xc0, 0x16, 0x71, 0x21, 0x3e, 0x10, 0x2e, 0xc7, - 0x88, 0x3c, 0x93, 0xfb, 0x83, 0x00, 0xe0, 0x02, 0x46, 0x2e, 0x60, 0x23, 0x78, 0x01, 0x9b, 0x00, - 0x22, 0x18, 0x0d, 0x22, 0x82, 0xe8, 0x06, 0x14, 0x59, 0x92, 0x6e, 0xaa, 0x9d, 0x81, 0x62, 0x0d, - 0x0d, 0xcc, 0xe1, 0xa1, 0x02, 0x25, 0x1f, 0xda, 0x54, 0xf4, 0x21, 0x5c, 0xb6, 0xba, 0x06, 0x36, - 0xbb, 0x5a, 0xaf, 0x2d, 0x07, 0x37, 0x9e, 0x15, 0x38, 0xd6, 0x66, 0x18, 0x9c, 0x74, 0xc9, 0xd1, - 0x70, 0xec, 0xdf, 0xfc, 0xcf, 0x20, 0x41, 0xd7, 0x86, 0x24, 0x5a, 0x8e, 0x05, 0x67, 0xb8, 0x71, - 0x7e, 0x04, 0xa0, 0x58, 0x96, 0xa1, 0x9e, 0x0c, 0xc9, 0x71, 0x8e, 0x8e, 0x7f, 0xca, 0x5d, 0xdb, - 0xaa, 0xcd, 0xb7, 0x75, 0x95, 0x2f, 0xf2, 0x8a, 0x2b, 0xea, 0x59, 0x68, 0x8f, 0x42, 0x71, 0x0f, - 0x0a, 0x7e, 0x59, 0x3b, 0x83, 0x65, 0x63, 0xf0, 0x67, 0xb0, 0x2c, 0x23, 0xe6, 0x19, 0xac, 0x93, - 0xff, 0xc6, 0x58, 0xf9, 0x90, 0x36, 0xc4, 0x7f, 0x0a, 0x90, 0xf3, 0xba, 0xa9, 0xb9, 0x93, 0x4c, - 0x9e, 0x74, 0xc7, 0xc6, 0x93, 0xee, 0x78, 0x68, 0xda, 0x99, 0x08, 0xa6, 0x9d, 0x97, 0x21, 0x4d, - 0xba, 0x87, 0x26, 0x6e, 0xf3, 0x9a, 0x6b, 0xaa, 0xa3, 0x98, 0x47, 0x26, 0x6e, 0x7b, 0xec, 0x33, - 0xf5, 0x9c, 0xf6, 0xe9, 0xcb, 0x6d, 0xd3, 0xc1, 0x44, 0xfb, 0x73, 0x01, 0xd2, 0xce, 0xe4, 0xfd, - 0xa5, 0x45, 0x1f, 0xbe, 0xc8, 0xd6, 0x8e, 0x15, 0x16, 0xf9, 0xdd, 0x81, 0x15, 0x5a, 0x63, 0x4e, - 0xa1, 0xf5, 0x1d, 0x27, 0x1b, 0x0b, 0x43, 0xd0, 0xbc, 0x2b, 0x6d, 0x83, 0xa6, 0x3c, 0xf9, 0xfc, - 0x39, 0x1f, 0x07, 0x49, 0x27, 0xd0, 0xff, 0x42, 0x52, 0x69, 0x39, 0xb8, 0x61, 0x61, 0x02, 0xa0, - 0x66, 0xb3, 0x6e, 0x34, 0x47, 0x55, 0xca, 0x29, 0x71, 0x09, 0x3e, 0xaa, 0xa8, 0x3d, 0x2a, 0x71, - 0x97, 0xe8, 0x65, 0x3c, 0x7e, 0x9f, 0x51, 0x00, 0x38, 0xda, 0x7b, 0xb8, 0xbf, 0xbd, 0x73, 0x6f, - 0xa7, 0xbe, 0xcd, 0xd3, 0xad, 0xed, 0xed, 0xfa, 0x76, 0x29, 0x4a, 0xf8, 0xa4, 0xfa, 0xc3, 0xfd, - 0xe3, 0xfa, 0x76, 0x29, 0x46, 0x1a, 0xdb, 0xf5, 0xdd, 0xea, 0x07, 0xf5, 0xed, 0x52, 0x5c, 0xac, - 0x42, 0xc6, 0x09, 0x19, 0xb4, 0x22, 0xad, 0x3d, 0xc6, 0x06, 0x5f, 0x2d, 0xd6, 0x40, 0xab, 0x90, - 0x1d, 0x87, 0xc8, 0xc9, 0xed, 0x89, 0x21, 0xe3, 0xe2, 0x2f, 0x05, 0x28, 0x3a, 0x3a, 0x78, 0xd2, - 0xf0, 0x0e, 0xa4, 0xf4, 0xe1, 0x89, 0x6c, 0x1b, 0x72, 0x00, 0x2e, 0xb6, 0x2f, 0x57, 0xc3, 0x93, - 0x9e, 0xda, 0x7a, 0x80, 0xcf, 0x79, 0x88, 0x4a, 0xea, 0xc3, 0x93, 0x07, 0xcc, 0xde, 0xd9, 0x30, - 0xa2, 0x53, 0x86, 0x11, 0x0b, 0x0c, 0x03, 0xdd, 0x80, 0xdc, 0x40, 0x6b, 0x63, 0x59, 0x69, 0xb7, - 0x0d, 0x6c, 0xb2, 0xc8, 0x9b, 0xe1, 0x9a, 0xb3, 0xa4, 0xa7, 0xca, 0x3a, 0xc4, 0x6f, 0x05, 0x40, - 0xe3, 0x61, 0x12, 0x1d, 0xc2, 0x92, 0x1b, 0x69, 0xed, 0xf0, 0xcd, 0x7c, 0xe9, 0x7a, 0x78, 0x98, - 0xf5, 0xdd, 0xc0, 0x4b, 0x67, 0x7e, 0x32, 0x49, 0xc9, 0x56, 0x5c, 0xbf, 0xa5, 0xd3, 0xf9, 0xd2, - 0x45, 0x89, 0xce, 0xb9, 0x28, 0x11, 0x09, 0x39, 0xf2, 0x4e, 0x4f, 0xd0, 0xaf, 0xc6, 0xc6, 0x2a, - 0x2d, 0x3a, 0x94, 0x9b, 0x63, 0x62, 0x7c, 0x9e, 0x61, 0x43, 0x12, 0x9e, 0x67, 0x48, 0xe2, 0x1d, - 0x28, 0xbd, 0xe7, 0x7c, 0x9f, 0x7f, 0x29, 0x30, 0x4c, 0x61, 0x6c, 0x98, 0x67, 0x90, 0x26, 0xae, - 0x98, 0x46, 0x90, 0xff, 0x87, 0x8c, 0xb3, 0x7a, 0xce, 0xa3, 0x96, 0xd0, 0x65, 0xe7, 0x23, 0x71, - 0x45, 0xd0, 0x2d, 0x58, 0x22, 0x41, 0xc4, 0xae, 0x77, 0x32, 0x0c, 0x2d, 0x4a, 0x5d, 0x63, 0x91, - 0x75, 0xec, 0xda, 0xc0, 0x0f, 0x89, 0xf6, 0x25, 0x96, 0x15, 0xe0, 0xf6, 0xbf, 0x63, 0x00, 0xe4, - 0xd2, 0x15, 0x80, 0x12, 0xd9, 0x1e, 0xe6, 0x7d, 0x69, 0x89, 0xf8, 0xe3, 0x28, 0x64, 0x3d, 0x55, - 0x15, 0xf4, 0x3f, 0xbe, 0x0c, 0x6b, 0x7d, 0x5a, 0x05, 0xc6, 0x93, 0x5e, 0xf9, 0x26, 0x16, 0x5d, - 0x7c, 0x62, 0x61, 0x95, 0x2f, 0xbb, 0x0c, 0x1b, 0x5f, 0xb8, 0x0c, 0xfb, 0x0a, 0x20, 0x4b, 0xb3, - 0x94, 0x1e, 0x89, 0xe4, 0xea, 0xa0, 0x23, 0xb3, 0xd3, 0xce, 0xa2, 0x49, 0x89, 0xf6, 0x1c, 0xd3, - 0x8e, 0x03, 0x42, 0x17, 0x7b, 0x90, 0x76, 0x90, 0x81, 0xc5, 0xdf, 0x8a, 0x4c, 0x2a, 0x37, 0x57, - 0x20, 0xdd, 0xc7, 0x96, 0x42, 0x63, 0x20, 0x43, 0x8a, 0x9c, 0xf6, 0xad, 0xb7, 0x21, 0xeb, 0x79, - 0x40, 0x43, 0xc2, 0xe2, 0x5e, 0xfd, 0xfd, 0x52, 0xa4, 0x92, 0xfa, 0xe2, 0xab, 0xf5, 0xd8, 0x1e, - 0x7e, 0x4c, 0x3e, 0x25, 0xd5, 0x6b, 0x8d, 0x7a, 0xed, 0x41, 0x49, 0xa8, 0x64, 0xbf, 0xf8, 0x6a, - 0x3d, 0x25, 0x61, 0x5a, 0x80, 0xb8, 0xf5, 0x00, 0x8a, 0x81, 0x1d, 0xf0, 0x3b, 0x68, 0x04, 0x85, - 0xed, 0xa3, 0x83, 0xdd, 0x9d, 0x5a, 0xb5, 0x59, 0x97, 0x8f, 0xf7, 0x9b, 0xf5, 0x92, 0x80, 0x2e, - 0xc1, 0xf2, 0xee, 0xce, 0x0f, 0x1a, 0x4d, 0xb9, 0xb6, 0xbb, 0x53, 0xdf, 0x6b, 0xca, 0xd5, 0x66, - 0xb3, 0x5a, 0x7b, 0x50, 0x8a, 0xde, 0xfe, 0x33, 0x40, 0xb1, 0xba, 0x55, 0xdb, 0x21, 0x17, 0x7d, - 0xb5, 0xa5, 0x50, 0x77, 0x5f, 0x83, 0x38, 0xc5, 0x65, 0xa7, 0x3e, 0xa5, 0xad, 0x4c, 0xaf, 0x2a, - 0xa1, 0x7b, 0x90, 0xa0, 0x90, 0x2d, 0x9a, 0xfe, 0xb6, 0xb6, 0x32, 0xa3, 0xcc, 0x44, 0x06, 0x43, - 0xcf, 0xcd, 0xd4, 0xc7, 0xb6, 0x95, 0xe9, 0x55, 0x27, 0xb4, 0x0b, 0x29, 0x1b, 0x0d, 0x9b, 0xf5, - 0x02, 0xb6, 0x32, 0xb3, 0x14, 0x44, 0xa6, 0xc6, 0x50, 0xc5, 0xe9, 0xef, 0x70, 0x2b, 0x33, 0xea, - 0x51, 0x48, 0x82, 0x8c, 0x0b, 0x04, 0xcf, 0x7e, 0x12, 0x5c, 0x99, 0xa3, 0x3e, 0x86, 0x3e, 0x86, - 0xbc, 0x1f, 0x37, 0x9b, 0xef, 0xb5, 0x6e, 0x65, 0xce, 0xda, 0x15, 0xd1, 0xef, 0x07, 0xd1, 0xe6, - 0x7b, 0xbd, 0x5b, 0x99, 0xb3, 0x94, 0x85, 0x3e, 0x81, 0xa5, 0x71, 0x90, 0x6b, 0xfe, 0xc7, 0xbc, - 0x95, 0x05, 0x8a, 0x5b, 0xa8, 0x0f, 0x68, 0x02, 0x38, 0xb6, 0xc0, 0xdb, 0xde, 0xca, 0x22, 0xb5, - 0x2e, 0xd4, 0x86, 0x62, 0x10, 0x38, 0x9a, 0xf7, 0xad, 0x6f, 0x65, 0xee, 0xba, 0x17, 0xfb, 0x8a, - 0x1f, 0xe1, 0x98, 0xf7, 0xed, 0x6f, 0x65, 0xee, 0x32, 0x18, 0x3a, 0x02, 0xf0, 0xdc, 0x92, 0xe7, - 0x78, 0x0b, 0x5c, 0x99, 0xa7, 0x20, 0x86, 0x74, 0x58, 0x9e, 0x74, 0x2d, 0x5e, 0xe4, 0x69, 0x70, - 0x65, 0xa1, 0x3a, 0x19, 0xb1, 0x67, 0xff, 0x05, 0x77, 0xbe, 0xa7, 0xc2, 0x95, 0x39, 0x0b, 0x66, - 0x5b, 0x5b, 0x5f, 0x3f, 0x5d, 0x15, 0xbe, 0x79, 0xba, 0x2a, 0x7c, 0xfb, 0x74, 0x55, 0xf8, 0xf2, - 0xbb, 0xd5, 0xc8, 0x37, 0xdf, 0xad, 0x46, 0xfe, 0xf4, 0xdd, 0x6a, 0xe4, 0x87, 0x37, 0x3b, 0xaa, - 0xd5, 0x1d, 0x9e, 0x6c, 0xb4, 0xb4, 0x3e, 0xfd, 0xa7, 0x86, 0xae, 0x9c, 0x6f, 0x32, 0x9d, 0xa4, - 0xe5, 0xf9, 0x3f, 0xc8, 0x49, 0x92, 0xc6, 0xba, 0x3b, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x0a, - 0x1d, 0x02, 0xcd, 0x2f, 0x32, 0x00, 0x00, + // 3664 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5b, 0xcd, 0x73, 0x1b, 0x57, + 0x72, 0xc7, 0xe0, 0x1b, 0x8d, 0xaf, 0xe1, 0x23, 0x25, 0x41, 0x90, 0x44, 0xd2, 0xa3, 0xd8, 0x92, + 0x65, 0x9b, 0xb4, 0xa5, 0xd8, 0xb2, 0x63, 0x27, 0x55, 0x20, 0x08, 0x05, 0x94, 0x28, 0x92, 0x1e, + 0x82, 0x74, 0x39, 0x8e, 0x3d, 0x35, 0x04, 0x1e, 0x89, 0xb1, 0x00, 0xcc, 0x78, 0x66, 0x40, 0x81, + 0xbe, 0x26, 0x4e, 0xa5, 0x7c, 0xf2, 0x3f, 0xe0, 0x43, 0xaa, 0x92, 0x63, 0x2e, 0x39, 0xa5, 0x72, + 0x48, 0x2a, 0x37, 0xa7, 0x72, 0xf1, 0x31, 0x97, 0x68, 0x5d, 0xf2, 0x65, 0x6b, 0x6f, 0x7b, 0xda, + 0xdb, 0xd6, 0xd6, 0xfb, 0x98, 0x4f, 0x60, 0xf0, 0x21, 0xb9, 0x6a, 0x6b, 0x6f, 0x78, 0xfd, 0xba, + 0x7b, 0xde, 0x47, 0xbf, 0xee, 0x7e, 0xbf, 0x7e, 0x80, 0x6b, 0x36, 0x1e, 0x74, 0xb0, 0xd9, 0xd7, + 0x06, 0xf6, 0xa6, 0x7a, 0xd2, 0xd6, 0x36, 0xed, 0x0b, 0x03, 0x5b, 0x1b, 0x86, 0xa9, 0xdb, 0x3a, + 0x2a, 0x7b, 0x9d, 0x1b, 0xa4, 0xb3, 0x7a, 0xc3, 0xc7, 0xdd, 0x36, 0x2f, 0x0c, 0x5b, 0xdf, 0x34, + 0x4c, 0x5d, 0x3f, 0x65, 0xfc, 0x55, 0xbf, 0x32, 0xaa, 0x67, 0xb3, 0xa3, 0x5a, 0x5d, 0xde, 0x79, + 0x7d, 0xac, 0xf3, 0xa4, 0xa7, 0xb7, 0x9f, 0x44, 0xf6, 0xfa, 0x06, 0x12, 0xe8, 0xe5, 0xdf, 0x7d, + 0x82, 0x2f, 0x9c, 0xde, 0x1b, 0x63, 0xb2, 0x86, 0x6a, 0xaa, 0x7d, 0xa7, 0x7b, 0xd5, 0xd7, 0x7d, + 0x8e, 0x4d, 0x4b, 0xd3, 0x07, 0x01, 0xe5, 0x6b, 0x67, 0xba, 0x7e, 0xd6, 0xc3, 0x9b, 0xb4, 0x75, + 0x32, 0x3c, 0xdd, 0xb4, 0xb5, 0x3e, 0xb6, 0x6c, 0xb5, 0x6f, 0x70, 0x86, 0x95, 0x33, 0xfd, 0x4c, + 0xa7, 0x3f, 0x37, 0xc9, 0x2f, 0x46, 0x95, 0xbe, 0xc9, 0x41, 0x46, 0xc6, 0x5f, 0x0d, 0xb1, 0x65, + 0xa3, 0xbb, 0x90, 0xc4, 0xed, 0xae, 0x5e, 0x11, 0xd6, 0x85, 0xdb, 0xf9, 0xbb, 0xd7, 0x37, 0x42, + 0xeb, 0xb6, 0xc1, 0xf9, 0x1a, 0xed, 0xae, 0xde, 0x8c, 0xc9, 0x94, 0x17, 0xbd, 0x0b, 0xa9, 0xd3, + 0xde, 0xd0, 0xea, 0x56, 0xe2, 0x54, 0xe8, 0x46, 0x94, 0xd0, 0x03, 0xc2, 0xd4, 0x8c, 0xc9, 0x8c, + 0x9b, 0x7c, 0x4a, 0x1b, 0x9c, 0xea, 0x95, 0xc4, 0xf4, 0x4f, 0xed, 0x0c, 0x4e, 0xe9, 0xa7, 0x08, + 0x2f, 0xda, 0x02, 0xd0, 0x06, 0x9a, 0xad, 0xb4, 0xbb, 0xaa, 0x36, 0xa8, 0x24, 0xa9, 0xe4, 0x2b, + 0xd1, 0x92, 0x9a, 0x5d, 0x27, 0x8c, 0xcd, 0x98, 0x9c, 0xd3, 0x9c, 0x06, 0x19, 0xee, 0x57, 0x43, + 0x6c, 0x5e, 0x54, 0x52, 0xd3, 0x87, 0xfb, 0x31, 0x61, 0x22, 0xc3, 0xa5, 0xdc, 0xe8, 0x23, 0xc8, + 0xb6, 0xbb, 0xb8, 0xfd, 0x44, 0xb1, 0x47, 0x95, 0x0c, 0x95, 0x5c, 0x8b, 0x92, 0xac, 0x13, 0xbe, + 0xd6, 0xa8, 0x19, 0x93, 0x33, 0x6d, 0xf6, 0x13, 0xed, 0x41, 0xa9, 0xa7, 0x59, 0xb6, 0x62, 0x0d, + 0x54, 0xc3, 0xea, 0xea, 0xb6, 0x55, 0xc9, 0x53, 0x1d, 0xaf, 0x46, 0xe9, 0xd8, 0xd5, 0x2c, 0xfb, + 0xd0, 0x61, 0x6e, 0xc6, 0xe4, 0x62, 0xcf, 0x4f, 0x20, 0xfa, 0xf4, 0xd3, 0x53, 0x6c, 0xba, 0x0a, + 0x2b, 0x85, 0xe9, 0xfa, 0xf6, 0x09, 0xb7, 0x23, 0x4f, 0xf4, 0xe9, 0x7e, 0x02, 0xfa, 0x0c, 0x96, + 0x7b, 0xba, 0xda, 0x71, 0xd5, 0x29, 0xed, 0xee, 0x70, 0xf0, 0xa4, 0x52, 0xa4, 0x4a, 0x5f, 0x8f, + 0x1c, 0xa4, 0xae, 0x76, 0x1c, 0x15, 0x75, 0x22, 0xd0, 0x8c, 0xc9, 0x4b, 0xbd, 0x30, 0x11, 0x7d, + 0x01, 0x2b, 0xaa, 0x61, 0xf4, 0x2e, 0xc2, 0xda, 0x4b, 0x54, 0xfb, 0x9d, 0x28, 0xed, 0x35, 0x22, + 0x13, 0x56, 0x8f, 0xd4, 0x31, 0x2a, 0x6a, 0x81, 0x68, 0x98, 0xd8, 0x50, 0x4d, 0xac, 0x18, 0xa6, + 0x6e, 0xe8, 0x96, 0xda, 0xab, 0x94, 0xa9, 0xee, 0x5b, 0x51, 0xba, 0x0f, 0x18, 0xff, 0x01, 0x67, + 0x6f, 0xc6, 0xe4, 0xb2, 0x11, 0x24, 0x31, 0xad, 0x7a, 0x1b, 0x5b, 0x96, 0xa7, 0x55, 0x9c, 0xa5, + 0x95, 0xf2, 0x07, 0xb5, 0x06, 0x48, 0xa8, 0x01, 0x79, 0x3c, 0x22, 0xe2, 0xca, 0xb9, 0x6e, 0xe3, + 0xca, 0x12, 0x55, 0x28, 0x45, 0x9e, 0x33, 0xca, 0x7a, 0xac, 0xdb, 0xb8, 0x19, 0x93, 0x01, 0xbb, + 0x2d, 0xa4, 0xc2, 0xa5, 0x73, 0x6c, 0x6a, 0xa7, 0x17, 0x54, 0x8d, 0x42, 0x7b, 0x88, 0x3f, 0xa8, + 0x20, 0xaa, 0xf0, 0x8d, 0x28, 0x85, 0xc7, 0x54, 0x88, 0xa8, 0x68, 0x38, 0x22, 0xcd, 0x98, 0xbc, + 0x7c, 0x3e, 0x4e, 0x26, 0x26, 0x76, 0xaa, 0x0d, 0xd4, 0x9e, 0xf6, 0x35, 0x56, 0xa8, 0x83, 0xab, + 0x2c, 0x4f, 0x37, 0xb1, 0x07, 0x9c, 0x7b, 0x8b, 0x30, 0x13, 0x13, 0x3b, 0xf5, 0x13, 0xb6, 0x32, + 0x90, 0x3a, 0x57, 0x7b, 0x43, 0xfc, 0x30, 0x99, 0x4d, 0x8b, 0x99, 0x87, 0xc9, 0x6c, 0x56, 0xcc, + 0x3d, 0x4c, 0x66, 0x73, 0x22, 0x3c, 0x4c, 0x66, 0x41, 0xcc, 0x4b, 0xb7, 0x20, 0xef, 0x73, 0x2f, + 0xa8, 0x02, 0x99, 0x3e, 0xb6, 0x2c, 0xf5, 0x0c, 0x53, 0x6f, 0x94, 0x93, 0x9d, 0xa6, 0x54, 0x82, + 0x82, 0xdf, 0xa5, 0x48, 0xdf, 0x09, 0xae, 0x24, 0xf1, 0x16, 0x44, 0x92, 0xbb, 0x47, 0x47, 0x92, + 0x37, 0xd1, 0x4d, 0x28, 0xd2, 0xa9, 0x28, 0x4e, 0x3f, 0x71, 0x59, 0x49, 0xb9, 0x40, 0x89, 0xc7, + 0x9c, 0x69, 0x0d, 0xf2, 0xc6, 0x5d, 0xc3, 0x65, 0x49, 0x50, 0x16, 0x30, 0xee, 0x1a, 0x0e, 0xc3, + 0x2b, 0x50, 0x20, 0xf3, 0x76, 0x39, 0x92, 0xf4, 0x23, 0x79, 0x42, 0xe3, 0x2c, 0xd2, 0xdf, 0x27, + 0x40, 0x0c, 0xbb, 0x21, 0xf4, 0x3e, 0x24, 0x89, 0x47, 0xe6, 0xce, 0xb5, 0xba, 0xc1, 0xdc, 0xf5, + 0x86, 0xe3, 0xae, 0x37, 0x5a, 0x8e, 0xbb, 0xde, 0xca, 0xfe, 0xf0, 0x6c, 0x2d, 0xf6, 0xdd, 0xaf, + 0xd6, 0x04, 0x99, 0x4a, 0xa0, 0xab, 0xc4, 0xf9, 0xa8, 0xda, 0x40, 0xd1, 0x3a, 0x74, 0xc8, 0x39, + 0xe2, 0x59, 0x54, 0x6d, 0xb0, 0xd3, 0x41, 0xbb, 0x20, 0xb6, 0xf5, 0x81, 0x85, 0x07, 0xd6, 0xd0, + 0x52, 0x58, 0xb8, 0xe0, 0x2e, 0x35, 0xe0, 0x18, 0x59, 0x9c, 0xa8, 0x3b, 0x9c, 0x07, 0x94, 0x51, + 0x2e, 0xb7, 0x83, 0x04, 0xb4, 0x07, 0xc5, 0x73, 0xb5, 0xa7, 0x75, 0x54, 0x5b, 0x37, 0x15, 0x0b, + 0xdb, 0xdc, 0xc7, 0xde, 0x1c, 0xdb, 0xf3, 0x63, 0x87, 0xeb, 0x10, 0xdb, 0x47, 0x46, 0x47, 0xb5, + 0xf1, 0x56, 0xf2, 0x87, 0x67, 0x6b, 0x82, 0x5c, 0x38, 0xf7, 0xf5, 0xa0, 0xd7, 0xa0, 0xac, 0x1a, + 0x86, 0x62, 0xd9, 0xaa, 0x8d, 0x95, 0x93, 0x0b, 0x1b, 0x5b, 0xd4, 0xed, 0x16, 0xe4, 0xa2, 0x6a, + 0x18, 0x87, 0x84, 0xba, 0x45, 0x88, 0xe8, 0x55, 0x28, 0x11, 0x0f, 0xad, 0xa9, 0x3d, 0xa5, 0x8b, + 0xb5, 0xb3, 0xae, 0x5d, 0x49, 0xaf, 0x0b, 0xb7, 0x13, 0x72, 0x91, 0x53, 0x9b, 0x94, 0x88, 0x36, + 0x60, 0xd9, 0x61, 0x6b, 0xeb, 0x26, 0x76, 0x78, 0x89, 0x3f, 0x2e, 0xca, 0x4b, 0xbc, 0xab, 0xae, + 0x9b, 0x98, 0xf1, 0x4b, 0x1d, 0xd7, 0x52, 0xa8, 0x37, 0x47, 0x08, 0x92, 0x1d, 0xd5, 0x56, 0xe9, + 0x0e, 0x14, 0x64, 0xfa, 0x9b, 0xd0, 0x0c, 0xd5, 0xee, 0xf2, 0x75, 0xa5, 0xbf, 0xd1, 0x65, 0x48, + 0x73, 0xd5, 0x09, 0x3a, 0x0c, 0xde, 0x42, 0x2b, 0x90, 0x32, 0x4c, 0xfd, 0x1c, 0xd3, 0x65, 0xc9, + 0xca, 0xac, 0x21, 0xc9, 0x50, 0x0a, 0x7a, 0x7e, 0x54, 0x82, 0xb8, 0x3d, 0xe2, 0x5f, 0x89, 0xdb, + 0x23, 0xf4, 0x36, 0x24, 0xc9, 0x06, 0xd0, 0x6f, 0x94, 0x26, 0xc4, 0x3a, 0x2e, 0xd7, 0xba, 0x30, + 0xb0, 0x4c, 0x39, 0xa5, 0xcb, 0xb0, 0x32, 0x29, 0x12, 0x48, 0x5d, 0x97, 0x1e, 0xf0, 0xe8, 0xe8, + 0x5d, 0xc8, 0xba, 0xa1, 0x80, 0xd9, 0xd7, 0xd5, 0xb1, 0xaf, 0x38, 0xcc, 0xb2, 0xcb, 0x4a, 0x0c, + 0x8b, 0xec, 0x4f, 0x57, 0xe5, 0xe1, 0xbb, 0x20, 0x67, 0x54, 0xc3, 0x68, 0xaa, 0x56, 0x57, 0x3a, + 0x83, 0x4a, 0x94, 0x9b, 0xf7, 0xad, 0x8f, 0x40, 0x4f, 0x87, 0xb3, 0x3e, 0xbe, 0x93, 0x17, 0xa7, + 0x7b, 0xe2, 0x9e, 0x3c, 0x6a, 0xc1, 0xc3, 0xc1, 0x13, 0x62, 0xc1, 0x09, 0xf6, 0x21, 0xda, 0xde, + 0xe9, 0x48, 0x1d, 0xb8, 0x1a, 0xe9, 0xf1, 0x03, 0x72, 0x42, 0x40, 0x8e, 0x6c, 0x06, 0x8b, 0x23, + 0x6c, 0xe0, 0xac, 0x41, 0x86, 0x66, 0xd1, 0x79, 0xd3, 0xcf, 0xe4, 0x64, 0xde, 0x92, 0x7e, 0x9b, + 0x84, 0xcb, 0x93, 0x9d, 0x3f, 0x5a, 0x87, 0x42, 0x5f, 0x1d, 0x29, 0xf6, 0x88, 0x5b, 0xa8, 0x40, + 0xf7, 0x1c, 0xfa, 0xea, 0xa8, 0x35, 0x62, 0xe6, 0x29, 0x42, 0xc2, 0x1e, 0x59, 0x95, 0xf8, 0x7a, + 0xe2, 0x76, 0x41, 0x26, 0x3f, 0xd1, 0x63, 0x58, 0xea, 0xe9, 0x6d, 0xb5, 0xa7, 0xf4, 0x54, 0xcb, + 0x56, 0xda, 0x7a, 0xbf, 0xaf, 0xd9, 0xfc, 0xdc, 0x5d, 0x1b, 0xdf, 0x5e, 0xda, 0x4d, 0x7c, 0x13, + 0x3d, 0x24, 0x31, 0xb9, 0x4c, 0x65, 0x77, 0x55, 0xcb, 0x66, 0x5d, 0x68, 0x1b, 0xf2, 0x7d, 0xcd, + 0x3a, 0xc1, 0x5d, 0xf5, 0x5c, 0xd3, 0xcd, 0x4a, 0x72, 0x3d, 0x31, 0x31, 0x27, 0x7a, 0xec, 0xf1, + 0x70, 0x4d, 0x7e, 0x31, 0xdf, 0xb6, 0xa4, 0x02, 0x66, 0xeb, 0x38, 0x9e, 0xf4, 0xc2, 0x8e, 0xe7, + 0x6d, 0x58, 0x19, 0xe0, 0x91, 0xad, 0xb8, 0x87, 0xda, 0x62, 0xb6, 0x92, 0xa1, 0x4b, 0x8e, 0x48, + 0x9f, 0xeb, 0x09, 0x2c, 0x62, 0x36, 0x64, 0x57, 0x4c, 0x7d, 0x38, 0xe8, 0x54, 0xb2, 0xeb, 0xc2, + 0xed, 0x94, 0xcc, 0x1a, 0xe8, 0x3e, 0x54, 0xe8, 0x81, 0x65, 0x5e, 0x8c, 0x78, 0x5b, 0xdc, 0x71, + 0x4e, 0x6f, 0x8e, 0x5a, 0xca, 0x25, 0xd2, 0x4f, 0xfd, 0xe4, 0x2e, 0xed, 0xe5, 0x27, 0x7e, 0x13, + 0x56, 0x58, 0xf4, 0xc5, 0x26, 0x09, 0xc3, 0x64, 0x93, 0xe8, 0x00, 0x80, 0x0e, 0x60, 0xc9, 0xe9, + 0x3b, 0x30, 0xf5, 0xd6, 0x88, 0x7e, 0xff, 0x6d, 0x57, 0xa0, 0xa3, 0x10, 0xd3, 0x76, 0xec, 0x31, + 0x4f, 0x0d, 0x15, 0x39, 0x7d, 0x35, 0xc3, 0x75, 0xe7, 0xf7, 0x3d, 0xa3, 0x2d, 0x8c, 0xa7, 0x84, + 0xbc, 0xcb, 0x73, 0x9d, 0x9e, 0x4d, 0xaf, 0x41, 0xfe, 0xab, 0xa1, 0x6e, 0x0e, 0xfb, 0x6c, 0x48, + 0x45, 0x3a, 0x24, 0x60, 0x24, 0x7a, 0x84, 0xfe, 0x2b, 0xe5, 0xb3, 0xb9, 0x60, 0x1e, 0xc0, 0x2d, + 0x4a, 0xf0, 0x2c, 0xea, 0xd0, 0x37, 0x70, 0xbf, 0x51, 0xc5, 0xe7, 0x35, 0x2a, 0x77, 0x6e, 0xd1, + 0x76, 0x95, 0x78, 0x31, 0xbb, 0x42, 0x90, 0xa4, 0x33, 0x4c, 0x32, 0xb7, 0x49, 0x7e, 0x47, 0xda, + 0x9a, 0xbb, 0xff, 0x69, 0xff, 0xfe, 0x3b, 0x16, 0x98, 0xf9, 0xc5, 0x2c, 0x30, 0x1b, 0x69, 0x81, + 0x2f, 0x6c, 0x6b, 0x2d, 0xb8, 0x1c, 0x12, 0x54, 0x86, 0x34, 0xb4, 0x51, 0x6b, 0x0b, 0x25, 0xfc, + 0x4e, 0x40, 0xf5, 0x29, 0x92, 0x97, 0x03, 0x7a, 0x59, 0x58, 0x8c, 0xb4, 0xe0, 0xfc, 0xa2, 0x16, + 0x5c, 0x98, 0xc7, 0x82, 0x8b, 0x2f, 0x63, 0xc1, 0xa5, 0x31, 0x0b, 0x3e, 0x82, 0xa5, 0xb1, 0x54, + 0xd4, 0x35, 0x07, 0x61, 0xa2, 0x39, 0xc4, 0x27, 0x9b, 0x43, 0xc2, 0x67, 0x0e, 0xd2, 0x3f, 0xc5, + 0xa1, 0x1a, 0x9d, 0x91, 0x4e, 0xfc, 0xc0, 0x3b, 0x70, 0xc9, 0xcb, 0x4c, 0xfc, 0xeb, 0xc8, 0xbc, + 0x3f, 0x72, 0x3b, 0xbd, 0x85, 0x9c, 0x12, 0xc5, 0xd9, 0x98, 0x92, 0x7e, 0x13, 0x7d, 0x0c, 0xe5, + 0x60, 0x2e, 0x4d, 0x52, 0x15, 0x72, 0x5c, 0xfe, 0x6c, 0xec, 0xb8, 0x78, 0x6b, 0xe1, 0x8e, 0x59, + 0x2e, 0x9d, 0xfb, 0x9b, 0x16, 0x7a, 0x03, 0xca, 0x96, 0x76, 0x36, 0x50, 0x4c, 0x36, 0x4d, 0x12, + 0xbf, 0xc8, 0x89, 0x28, 0x90, 0xc4, 0x98, 0x74, 0x38, 0xd9, 0x61, 0xe7, 0x1f, 0x05, 0x61, 0x0b, + 0x81, 0xa8, 0x84, 0xb8, 0xa5, 0xff, 0x8d, 0xbb, 0xa1, 0x3e, 0x90, 0x59, 0xa3, 0x0f, 0x20, 0xcd, + 0x5d, 0x83, 0x30, 0xaf, 0x6b, 0xe0, 0x02, 0x61, 0x77, 0x10, 0x7f, 0x39, 0x77, 0x90, 0x98, 0xb8, + 0xff, 0xc9, 0xc9, 0x6b, 0x9d, 0xf2, 0xaf, 0xf5, 0x5b, 0x90, 0x62, 0x57, 0x0a, 0x16, 0x91, 0xae, + 0x8c, 0x1f, 0x2c, 0x3a, 0x55, 0x99, 0x71, 0xa1, 0x1a, 0x64, 0x59, 0xda, 0xae, 0x75, 0xb8, 0x07, + 0xb9, 0x1a, 0x21, 0xb1, 0xb3, 0xbd, 0x95, 0x7f, 0xfe, 0x6c, 0x2d, 0xc3, 0x1b, 0x72, 0x86, 0xca, + 0xed, 0x74, 0xa4, 0xff, 0xce, 0x41, 0x56, 0xc6, 0x96, 0x41, 0xce, 0x00, 0xda, 0x82, 0x1c, 0x1e, + 0xb5, 0xb1, 0x61, 0x3b, 0x57, 0x84, 0xc9, 0x57, 0x30, 0xc6, 0xdd, 0x70, 0x38, 0x9b, 0x31, 0xd9, + 0x13, 0x43, 0xf7, 0x38, 0x52, 0x12, 0x0d, 0x7a, 0x70, 0x71, 0x3f, 0x54, 0xf2, 0x9e, 0x03, 0x95, + 0xb0, 0x4c, 0x61, 0x35, 0x52, 0x2a, 0x84, 0x95, 0xdc, 0xe3, 0x58, 0x49, 0x72, 0xc6, 0xc7, 0x02, + 0x60, 0x49, 0x3d, 0x00, 0x96, 0xa4, 0x66, 0x4c, 0x33, 0x02, 0x2d, 0x79, 0xcf, 0x41, 0x4b, 0xd2, + 0x33, 0x46, 0x1c, 0x82, 0x4b, 0xfe, 0x72, 0x0c, 0x2e, 0x59, 0x8f, 0x14, 0x9d, 0x80, 0x97, 0xec, + 0x8f, 0xe1, 0x25, 0x59, 0xaa, 0xe4, 0xb5, 0x48, 0x25, 0x33, 0x00, 0x93, 0xfd, 0x31, 0xc0, 0x24, + 0x37, 0x43, 0xe1, 0x0c, 0xc4, 0xe4, 0x6f, 0x27, 0x23, 0x26, 0x10, 0x89, 0x69, 0xf0, 0x61, 0xce, + 0x07, 0x99, 0x28, 0x11, 0x90, 0x49, 0x3e, 0xf2, 0x7a, 0xcf, 0xd4, 0xcf, 0x8d, 0x99, 0x1c, 0x4d, + 0xc0, 0x4c, 0x58, 0xf6, 0x73, 0x3b, 0x52, 0xf9, 0x1c, 0xa0, 0xc9, 0xd1, 0x04, 0xd0, 0xa4, 0x38, + 0x53, 0xed, 0x4c, 0xd4, 0xe4, 0x41, 0x10, 0x35, 0x29, 0x45, 0x5c, 0x4a, 0xbd, 0x23, 0x1b, 0x01, + 0x9b, 0x9c, 0x44, 0xc1, 0x26, 0x0c, 0x2e, 0x7a, 0x33, 0x52, 0xe3, 0x02, 0xb8, 0xc9, 0xfe, 0x18, + 0x6e, 0x22, 0xce, 0xb0, 0xb4, 0x39, 0x81, 0x13, 0xe9, 0x75, 0x12, 0x8c, 0x43, 0x4e, 0x89, 0x38, + 0x58, 0x6c, 0x9a, 0xba, 0xc9, 0xa1, 0x0e, 0xd6, 0x90, 0x6e, 0x93, 0x8b, 0xaf, 0xe7, 0x80, 0xa6, + 0x80, 0x29, 0x65, 0x28, 0x06, 0x9c, 0x8e, 0xf4, 0xef, 0x82, 0x27, 0x4b, 0xe1, 0x14, 0xff, 0xa5, + 0x39, 0xc7, 0x2f, 0xcd, 0xa1, 0x8b, 0x5e, 0x2e, 0x90, 0x52, 0xf8, 0x93, 0x16, 0x8e, 0x9e, 0xa8, + 0x5e, 0xb2, 0x72, 0x07, 0x96, 0x68, 0x7a, 0xcb, 0x3c, 0x7a, 0x20, 0x68, 0x94, 0x49, 0x07, 0x5b, + 0x05, 0x16, 0x3d, 0xde, 0x82, 0x65, 0x1f, 0xaf, 0x7b, 0x53, 0x65, 0x10, 0x82, 0xe8, 0x72, 0xd7, + 0xf8, 0x95, 0xf5, 0xd7, 0x71, 0x6f, 0x85, 0x3c, 0xd8, 0x65, 0x12, 0x42, 0x22, 0xbc, 0x30, 0x42, + 0x12, 0x7d, 0x63, 0x46, 0x9f, 0xc1, 0x4a, 0x00, 0x3c, 0x71, 0xb2, 0xc7, 0xc4, 0x62, 0x18, 0x4a, + 0xcc, 0x97, 0xcc, 0xb8, 0x3d, 0xe8, 0x73, 0xb8, 0x46, 0xf3, 0xe0, 0x88, 0x0c, 0x35, 0x39, 0x5f, + 0x86, 0x7a, 0x85, 0xe8, 0xa8, 0x4f, 0xc8, 0x52, 0x23, 0x90, 0x95, 0x54, 0x14, 0xb2, 0xf2, 0x3b, + 0xc1, 0xb3, 0x1b, 0x17, 0x5b, 0x69, 0xeb, 0x1d, 0x66, 0x5f, 0x45, 0x99, 0xfe, 0x26, 0xb7, 0x9c, + 0x9e, 0x7e, 0xc6, 0x4d, 0x84, 0xfc, 0x24, 0x5c, 0x2e, 0xea, 0x9f, 0xe3, 0x81, 0x6a, 0x05, 0x52, + 0xda, 0xa0, 0x83, 0x47, 0xdc, 0x0a, 0x58, 0x83, 0xc8, 0x3e, 0xc1, 0x17, 0x7c, 0xaf, 0xc9, 0x4f, + 0xc2, 0x47, 0x0f, 0x02, 0x4b, 0xa4, 0x64, 0xd6, 0x40, 0xef, 0x43, 0x8e, 0x96, 0x6e, 0x14, 0xdd, + 0xb0, 0x78, 0xa8, 0x09, 0x64, 0x44, 0xac, 0xcc, 0xb2, 0x71, 0x40, 0x78, 0xf6, 0x0d, 0x4b, 0xce, + 0x1a, 0xfc, 0x97, 0x2f, 0x67, 0xc9, 0x06, 0x72, 0x96, 0xeb, 0x90, 0x23, 0xa3, 0xb7, 0x0c, 0xb5, + 0x8d, 0x69, 0x98, 0xc8, 0xc9, 0x1e, 0x41, 0xfa, 0x4f, 0x01, 0xca, 0xa1, 0xc8, 0x35, 0x71, 0xee, + 0xce, 0xb1, 0x89, 0x07, 0xb1, 0xa6, 0xb1, 0xd9, 0xdf, 0x00, 0x38, 0x53, 0x2d, 0xe5, 0xa9, 0x3a, + 0xb0, 0x71, 0x87, 0x2f, 0x41, 0xee, 0x4c, 0xb5, 0x3e, 0xa1, 0x84, 0xe0, 0x60, 0x52, 0xa1, 0xc1, + 0xf8, 0xd0, 0x8e, 0xb4, 0x1f, 0xed, 0x40, 0x55, 0xc8, 0x1a, 0xa6, 0xa6, 0x9b, 0x9a, 0x7d, 0x41, + 0xd7, 0x24, 0x21, 0xbb, 0x6d, 0xe9, 0x00, 0x2e, 0x4d, 0x0c, 0x9a, 0xe8, 0x3e, 0xe4, 0xbc, 0x78, + 0x2b, 0xd0, 0xdc, 0x70, 0x0a, 0x88, 0xe4, 0xf1, 0x92, 0x25, 0xb9, 0x34, 0x31, 0x6c, 0xa2, 0x06, + 0xa4, 0x4d, 0x6c, 0x0d, 0x7b, 0x2c, 0x57, 0x2d, 0xdd, 0x7d, 0x6b, 0xbe, 0x70, 0x4b, 0xa8, 0xc3, + 0x9e, 0x2d, 0x73, 0x61, 0xe9, 0x0b, 0x48, 0x33, 0x0a, 0xca, 0x43, 0xe6, 0x68, 0xef, 0xd1, 0xde, + 0xfe, 0x27, 0x7b, 0x62, 0x0c, 0x01, 0xa4, 0x6b, 0xf5, 0x7a, 0xe3, 0xa0, 0x25, 0x0a, 0x28, 0x07, + 0xa9, 0xda, 0xd6, 0xbe, 0xdc, 0x12, 0xe3, 0x84, 0x2c, 0x37, 0x1e, 0x36, 0xea, 0x2d, 0x31, 0x81, + 0x96, 0xa0, 0xc8, 0x7e, 0x2b, 0x0f, 0xf6, 0xe5, 0xc7, 0xb5, 0x96, 0x98, 0xf4, 0x91, 0x0e, 0x1b, + 0x7b, 0xdb, 0x0d, 0x59, 0x4c, 0x49, 0xef, 0xc0, 0xd5, 0xc8, 0x00, 0xed, 0xe1, 0x4c, 0x82, 0x0f, + 0x67, 0x92, 0x7e, 0xa4, 0x57, 0x98, 0xa8, 0xa8, 0x8b, 0x1e, 0x86, 0x26, 0x7e, 0x77, 0x81, 0x90, + 0x1d, 0x9a, 0x3d, 0x7a, 0x15, 0x4a, 0x26, 0x3e, 0xc5, 0x76, 0xbb, 0xcb, 0xb2, 0x00, 0x07, 0x88, + 0x2a, 0x72, 0x2a, 0x15, 0xb2, 0x18, 0xdb, 0x97, 0xb8, 0x6d, 0x2b, 0xcc, 0x08, 0x2c, 0x7a, 0xdd, + 0xcf, 0x11, 0x36, 0x42, 0x3d, 0x64, 0x44, 0xe2, 0xa0, 0x99, 0x23, 0x61, 0xaa, 0x92, 0x54, 0x15, + 0x50, 0xbf, 0x40, 0x29, 0xd2, 0xd3, 0x85, 0x16, 0x3b, 0x07, 0x29, 0xb9, 0xd1, 0x92, 0x3f, 0x15, + 0x13, 0x08, 0x41, 0x89, 0xfe, 0x54, 0x0e, 0xf7, 0x6a, 0x07, 0x87, 0xcd, 0x7d, 0xb2, 0xd8, 0xcb, + 0x50, 0x76, 0x16, 0xdb, 0x21, 0xa6, 0xd0, 0x25, 0x58, 0xaa, 0xef, 0x3f, 0x3e, 0xd8, 0x6d, 0xb4, + 0x1a, 0x1e, 0x39, 0x2d, 0xfd, 0x47, 0x02, 0xae, 0x44, 0xe4, 0x1a, 0xe8, 0x7d, 0x00, 0x7b, 0xa4, + 0x98, 0xb8, 0xad, 0x9b, 0x9d, 0x68, 0xe3, 0x6c, 0x8d, 0x64, 0xca, 0x21, 0xe7, 0x6c, 0xfe, 0x6b, + 0xaa, 0xc3, 0xfe, 0x88, 0x2b, 0x25, 0x93, 0xb5, 0x38, 0x38, 0x72, 0x63, 0xc2, 0x6d, 0x0f, 0xb7, + 0x89, 0x62, 0xba, 0x27, 0x54, 0x31, 0xe5, 0x47, 0x9f, 0xc2, 0x95, 0x50, 0x5c, 0xe1, 0xce, 0xd8, + 0x9a, 0x54, 0x99, 0x9c, 0x1c, 0x5e, 0x2e, 0x05, 0xc3, 0x0b, 0x73, 0xc6, 0xd6, 0x14, 0x24, 0x22, + 0xf5, 0x12, 0x48, 0x44, 0x54, 0x7c, 0x4a, 0x2f, 0x8a, 0xf1, 0x4f, 0x88, 0x4f, 0xd2, 0xbf, 0x05, + 0x36, 0x2f, 0x98, 0xbe, 0xed, 0x43, 0xda, 0xb2, 0x55, 0x7b, 0x68, 0xf1, 0xc3, 0x70, 0x7f, 0xde, + 0x5c, 0x70, 0xc3, 0xf9, 0x71, 0x48, 0xc5, 0x65, 0xae, 0xe6, 0x4f, 0x72, 0x4f, 0xa3, 0x56, 0x3f, + 0xf5, 0x4b, 0xac, 0xfe, 0xbb, 0x50, 0x0a, 0x2e, 0x55, 0xf4, 0xd9, 0xf5, 0xbc, 0x63, 0x5c, 0xea, + 0xc1, 0xf2, 0x04, 0x2c, 0x03, 0xdd, 0xe7, 0xe5, 0x0a, 0xb6, 0x5b, 0x37, 0xc7, 0xa7, 0x1c, 0x60, + 0xf7, 0xaa, 0x16, 0x24, 0x58, 0x79, 0x39, 0x35, 0xdb, 0x18, 0x8f, 0x20, 0xb5, 0x01, 0x8d, 0x67, + 0xe8, 0x93, 0x70, 0x17, 0xe1, 0xc5, 0x71, 0x17, 0xe9, 0x5f, 0x04, 0xb8, 0x36, 0x25, 0x6b, 0x47, + 0x1f, 0x87, 0x6c, 0xf1, 0x83, 0x45, 0x72, 0xfe, 0x0d, 0x46, 0x0b, 0x5a, 0xa3, 0x74, 0x0f, 0x0a, + 0x7e, 0xfa, 0x7c, 0x4b, 0xff, 0x0f, 0xbe, 0x98, 0x19, 0xc4, 0x77, 0x9a, 0x90, 0xc6, 0xe7, 0x78, + 0xe0, 0xc6, 0xe0, 0xcb, 0xe3, 0xeb, 0x40, 0xba, 0xb7, 0x2a, 0x24, 0x57, 0xfc, 0xcd, 0xb3, 0x35, + 0x91, 0x71, 0xbf, 0xa9, 0xf7, 0x35, 0x1b, 0xf7, 0x0d, 0xfb, 0x42, 0xe6, 0xf2, 0xe8, 0x26, 0x14, + 0x4d, 0x6c, 0x13, 0x17, 0x12, 0xc0, 0xe6, 0x0a, 0x8c, 0xc8, 0x33, 0xb9, 0xff, 0x11, 0x00, 0x3c, + 0xc0, 0xc8, 0x03, 0x6c, 0x04, 0x3f, 0x60, 0x13, 0x02, 0x0a, 0xe3, 0x61, 0xa0, 0x10, 0xdd, 0x82, + 0x32, 0x4b, 0xd2, 0x2d, 0xed, 0x6c, 0xa0, 0xda, 0x43, 0x13, 0x73, 0x78, 0xa8, 0x44, 0xc9, 0x87, + 0x0e, 0x15, 0x7d, 0x06, 0x57, 0xed, 0xae, 0x89, 0xad, 0xae, 0xde, 0xeb, 0x28, 0xe1, 0x8d, 0x67, + 0x75, 0x8f, 0xb5, 0x19, 0x06, 0x27, 0x5f, 0x71, 0x35, 0x1c, 0x07, 0x37, 0xff, 0x6b, 0x48, 0xd1, + 0xb5, 0x21, 0x89, 0x96, 0x6b, 0xc1, 0x39, 0x6e, 0x9c, 0x9f, 0x03, 0xa8, 0xb6, 0x6d, 0x6a, 0x27, + 0x43, 0x72, 0x9c, 0xe3, 0xe3, 0x9f, 0xf2, 0xd6, 0xb6, 0xe6, 0xf0, 0x6d, 0x5d, 0xe7, 0x8b, 0xbc, + 0xe2, 0x89, 0xfa, 0x16, 0xda, 0xa7, 0x50, 0xda, 0x83, 0x52, 0x50, 0xd6, 0xc9, 0x60, 0xd9, 0x18, + 0x82, 0x19, 0x2c, 0xcb, 0x88, 0x79, 0x06, 0xeb, 0xe6, 0xbf, 0x09, 0x56, 0x55, 0xa4, 0x0d, 0xe9, + 0xf7, 0x02, 0x14, 0xfc, 0x6e, 0x6a, 0xee, 0x24, 0x93, 0x27, 0xdd, 0x89, 0xf1, 0xa4, 0x3b, 0x19, + 0x99, 0x76, 0xa6, 0xc2, 0x69, 0xe7, 0x55, 0xc8, 0x92, 0xee, 0xa1, 0x85, 0x3b, 0xbc, 0x14, 0x9b, + 0x39, 0x53, 0xad, 0x23, 0x0b, 0x77, 0x7c, 0xf6, 0x99, 0x79, 0x49, 0xfb, 0x0c, 0xe4, 0xb6, 0xd9, + 0x70, 0xa2, 0xfd, 0x8d, 0x00, 0x59, 0x77, 0xf2, 0xc1, 0x8a, 0x63, 0x00, 0x5f, 0x64, 0x6b, 0xc7, + 0xea, 0x8d, 0xfc, 0xee, 0xc0, 0xea, 0xaf, 0x09, 0xb7, 0xfe, 0xfa, 0xa1, 0x9b, 0x8d, 0x45, 0x21, + 0x68, 0xfe, 0x95, 0x76, 0x40, 0x53, 0x9e, 0x7c, 0xfe, 0x33, 0x1f, 0x07, 0x49, 0x27, 0xd0, 0x5f, + 0x40, 0x5a, 0x6d, 0xbb, 0xb8, 0x61, 0x69, 0x02, 0xa0, 0xe6, 0xb0, 0x6e, 0xb4, 0x46, 0x35, 0xca, + 0x29, 0x73, 0x09, 0x3e, 0xaa, 0xb8, 0x33, 0x2a, 0x69, 0x97, 0xe8, 0x65, 0x3c, 0x41, 0x9f, 0x51, + 0x02, 0x38, 0xda, 0x7b, 0xbc, 0xbf, 0xbd, 0xf3, 0x60, 0xa7, 0xb1, 0xcd, 0xd3, 0xad, 0xed, 0xed, + 0xc6, 0xb6, 0x18, 0x27, 0x7c, 0x72, 0xe3, 0xf1, 0xfe, 0x71, 0x63, 0x5b, 0x4c, 0x90, 0xc6, 0x76, + 0x63, 0xb7, 0xf6, 0x69, 0x63, 0x5b, 0x4c, 0x4a, 0x35, 0xc8, 0xb9, 0x21, 0x83, 0x16, 0xaa, 0xf5, + 0xa7, 0xd8, 0xe4, 0xab, 0xc5, 0x1a, 0x68, 0x15, 0xf2, 0xe3, 0xc8, 0x39, 0xb9, 0x3d, 0x31, 0xc0, + 0x5c, 0xfa, 0x57, 0x01, 0xca, 0xae, 0x0e, 0x9e, 0x34, 0x7c, 0x08, 0x19, 0x63, 0x78, 0xa2, 0x38, + 0x86, 0x1c, 0x82, 0x8b, 0x9d, 0xcb, 0xd5, 0xf0, 0xa4, 0xa7, 0xb5, 0x1f, 0xe1, 0x0b, 0x1e, 0xa2, + 0xd2, 0xc6, 0xf0, 0xe4, 0x11, 0xb3, 0x77, 0x36, 0x8c, 0xf8, 0x94, 0x61, 0x24, 0x42, 0xc3, 0x40, + 0xb7, 0xa0, 0x30, 0xd0, 0x3b, 0x58, 0x51, 0x3b, 0x1d, 0x13, 0x5b, 0x2c, 0xf2, 0xe6, 0xb8, 0xe6, + 0x3c, 0xe9, 0xa9, 0xb1, 0x0e, 0xe9, 0x27, 0x01, 0xd0, 0x78, 0x98, 0x44, 0x87, 0xb0, 0xe4, 0x45, + 0x5a, 0x27, 0x7c, 0x33, 0x5f, 0xba, 0x1e, 0x1d, 0x66, 0x03, 0x37, 0x70, 0xf1, 0x3c, 0x48, 0x26, + 0x29, 0xd9, 0x8a, 0xe7, 0xb7, 0x0c, 0x3a, 0x5f, 0xba, 0x28, 0xf1, 0x39, 0x17, 0x25, 0x26, 0x23, + 0x57, 0xde, 0xed, 0x09, 0xfb, 0xd5, 0xc4, 0x58, 0x01, 0xc6, 0x80, 0x4a, 0x6b, 0x4c, 0x8c, 0xcf, + 0x33, 0x6a, 0x48, 0xc2, 0xcb, 0x0c, 0x49, 0xba, 0x07, 0xe2, 0xc7, 0xee, 0xf7, 0xf9, 0x97, 0x42, + 0xc3, 0x14, 0xc6, 0x86, 0x79, 0x0e, 0x59, 0xe2, 0x8a, 0x69, 0x04, 0xf9, 0x2b, 0xc8, 0xb9, 0xab, + 0xe7, 0xbe, 0x75, 0x89, 0x5c, 0x76, 0x3e, 0x12, 0x4f, 0x04, 0xdd, 0x81, 0x25, 0x12, 0x44, 0x9c, + 0x32, 0x28, 0xc3, 0xd0, 0xe2, 0xd4, 0x35, 0x96, 0x59, 0xc7, 0xae, 0x03, 0xfc, 0x90, 0x68, 0x2f, + 0xb2, 0xac, 0x00, 0x77, 0xfe, 0x18, 0x03, 0x20, 0x97, 0xae, 0x10, 0x94, 0xc8, 0xf6, 0xb0, 0x18, + 0x48, 0x4b, 0xa4, 0xbf, 0x8b, 0x43, 0xde, 0x57, 0x55, 0x41, 0x7f, 0x1e, 0xc8, 0xb0, 0xd6, 0xa7, + 0x55, 0x60, 0x7c, 0xe9, 0x55, 0x60, 0x62, 0xf1, 0xc5, 0x27, 0x16, 0x55, 0x10, 0x73, 0xaa, 0xb3, + 0xc9, 0x85, 0xab, 0xb3, 0x6f, 0x02, 0xb2, 0x75, 0x5b, 0xed, 0x91, 0x48, 0xae, 0x0d, 0xce, 0x14, + 0x76, 0xda, 0x59, 0x34, 0x11, 0x69, 0xcf, 0x31, 0xed, 0x38, 0x20, 0x74, 0xa9, 0x07, 0x59, 0x17, + 0x19, 0x58, 0xfc, 0x09, 0xc9, 0xa4, 0x2a, 0x74, 0x15, 0xb2, 0x7d, 0x6c, 0xab, 0x34, 0x06, 0x32, + 0xa4, 0xc8, 0x6d, 0xdf, 0xf9, 0x00, 0xf2, 0xbe, 0x77, 0x35, 0x24, 0x2c, 0xee, 0x35, 0x3e, 0x11, + 0x63, 0xd5, 0xcc, 0xb7, 0xdf, 0xaf, 0x27, 0xf6, 0xf0, 0x53, 0xf2, 0x29, 0xb9, 0x51, 0x6f, 0x36, + 0xea, 0x8f, 0x44, 0xa1, 0x9a, 0xff, 0xf6, 0xfb, 0xf5, 0x8c, 0x8c, 0x69, 0x01, 0xe2, 0xce, 0x23, + 0x28, 0x87, 0x76, 0x20, 0xe8, 0xa0, 0x11, 0x94, 0xb6, 0x8f, 0x0e, 0x76, 0x77, 0xea, 0xb5, 0x56, + 0x43, 0x39, 0xde, 0x6f, 0x35, 0x44, 0x01, 0x5d, 0x81, 0xe5, 0xdd, 0x9d, 0xbf, 0x6e, 0xb6, 0x94, + 0xfa, 0xee, 0x4e, 0x63, 0xaf, 0xa5, 0xd4, 0x5a, 0xad, 0x5a, 0xfd, 0x91, 0x18, 0xbf, 0xfb, 0xff, + 0x00, 0xe5, 0xda, 0x56, 0x7d, 0x87, 0x5c, 0xf4, 0xb5, 0xb6, 0x4a, 0xdd, 0x7d, 0x1d, 0x92, 0x14, + 0x97, 0x9d, 0xfa, 0xc2, 0xb6, 0x3a, 0xbd, 0xaa, 0x84, 0x1e, 0x40, 0x8a, 0x42, 0xb6, 0x68, 0xfa, + 0x93, 0xdb, 0xea, 0x8c, 0x32, 0x13, 0x19, 0x0c, 0x3d, 0x37, 0x53, 0xdf, 0xe0, 0x56, 0xa7, 0x57, + 0x9d, 0xd0, 0x2e, 0x64, 0x1c, 0x34, 0x6c, 0xd6, 0xc3, 0xd8, 0xea, 0xcc, 0x52, 0x10, 0x99, 0x1a, + 0x43, 0x15, 0xa7, 0x3f, 0xcf, 0xad, 0xce, 0xa8, 0x47, 0x21, 0x19, 0x72, 0x1e, 0x10, 0x3c, 0xfb, + 0xa5, 0x70, 0x75, 0x8e, 0xfa, 0x18, 0xfa, 0x02, 0x8a, 0x41, 0xdc, 0x6c, 0xbe, 0x47, 0xbc, 0xd5, + 0x39, 0x6b, 0x57, 0x44, 0x7f, 0x10, 0x44, 0x9b, 0xef, 0x51, 0x6f, 0x75, 0xce, 0x52, 0x16, 0xfa, + 0x12, 0x96, 0xc6, 0x41, 0xae, 0xf9, 0xdf, 0xf8, 0x56, 0x17, 0x28, 0x6e, 0xa1, 0x3e, 0xa0, 0x09, + 0xe0, 0xd8, 0x02, 0x4f, 0x7e, 0xab, 0x8b, 0xd4, 0xba, 0x50, 0x07, 0xca, 0x61, 0xe0, 0x68, 0xde, + 0x27, 0xc0, 0xd5, 0xb9, 0xeb, 0x5e, 0xec, 0x2b, 0x41, 0x84, 0x63, 0xde, 0x27, 0xc1, 0xd5, 0xb9, + 0xcb, 0x60, 0xe8, 0x08, 0xc0, 0x77, 0x4b, 0x9e, 0xe3, 0x89, 0x70, 0x75, 0x9e, 0x82, 0x18, 0x32, + 0x60, 0x79, 0xd2, 0xb5, 0x78, 0x91, 0x17, 0xc3, 0xd5, 0x85, 0xea, 0x64, 0xc4, 0x9e, 0x83, 0x17, + 0xdc, 0xf9, 0x5e, 0x10, 0x57, 0xe7, 0x2c, 0x98, 0x6d, 0x6d, 0xfd, 0xf0, 0x7c, 0x55, 0xf8, 0xf1, + 0xf9, 0xaa, 0xf0, 0xd3, 0xf3, 0x55, 0xe1, 0xbb, 0x9f, 0x57, 0x63, 0x3f, 0xfe, 0xbc, 0x1a, 0xfb, + 0xbf, 0x9f, 0x57, 0x63, 0x7f, 0x73, 0xfb, 0x4c, 0xb3, 0xbb, 0xc3, 0x93, 0x8d, 0xb6, 0xde, 0xa7, + 0x7f, 0xe0, 0x30, 0xd4, 0x8b, 0x4d, 0xa6, 0x93, 0xb4, 0x7c, 0x7f, 0x13, 0x39, 0x49, 0xd3, 0x58, + 0x77, 0xef, 0x0f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x17, 0xa2, 0x6a, 0x60, 0x46, 0x32, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -6221,11 +6221,11 @@ func (m *RequestVerifyVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, err _ = i var l int _ = l - if m.XSignId != nil { + if m.XSignRequestId != nil { { - size := m.XSignId.Size() + size := m.XSignRequestId.Size() i -= size - if _, err := m.XSignId.MarshalTo(dAtA[i:]); err != nil { + if _, err := m.XSignRequestId.MarshalTo(dAtA[i:]); err != nil { return 0, err } } @@ -6271,17 +6271,17 @@ func (m *RequestVerifyVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, err return len(dAtA) - i, nil } -func (m *RequestVerifyVoteExtension_SignId) MarshalTo(dAtA []byte) (int, error) { +func (m *RequestVerifyVoteExtension_SignRequestId) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *RequestVerifyVoteExtension_SignId) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *RequestVerifyVoteExtension_SignRequestId) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) - if m.SignId != nil { - i -= len(m.SignId) - copy(dAtA[i:], m.SignId) - i = encodeVarintTypes(dAtA, i, uint64(len(m.SignId))) + if m.SignRequestId != nil { + i -= len(m.SignRequestId) + copy(dAtA[i:], m.SignRequestId) + i = encodeVarintTypes(dAtA, i, uint64(len(m.SignRequestId))) i-- dAtA[i] = 0x32 } @@ -8823,20 +8823,20 @@ func (m *RequestVerifyVoteExtension) Size() (n int) { n += 1 + l + sovTypes(uint64(l)) } } - if m.XSignId != nil { - n += m.XSignId.Size() + if m.XSignRequestId != nil { + n += m.XSignRequestId.Size() } return n } -func (m *RequestVerifyVoteExtension_SignId) Size() (n int) { +func (m *RequestVerifyVoteExtension_SignRequestId) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.SignId != nil { - l = len(m.SignId) + if m.SignRequestId != nil { + l = len(m.SignRequestId) n += 1 + l + sovTypes(uint64(l)) } return n @@ -12744,7 +12744,7 @@ func (m *RequestVerifyVoteExtension) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SignId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SignRequestId", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -12773,7 +12773,7 @@ func (m *RequestVerifyVoteExtension) Unmarshal(dAtA []byte) error { } v := make([]byte, postIndex-iNdEx) copy(v, dAtA[iNdEx:postIndex]) - m.XSignId = &RequestVerifyVoteExtension_SignId{v} + m.XSignRequestId = &RequestVerifyVoteExtension_SignRequestId{v} iNdEx = postIndex default: iNdEx = preIndex diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 167ae0c79c..c166f12993 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -450,13 +450,13 @@ message RequestVerifyVoteExtension { int32 round = 4; // // Round number for the block. // Application-specific information signed by Tenderdash. Can have 0 length. repeated ExtendVoteExtension vote_extensions = 5; - // Sign ID that will be used to sign the vote extensions. + // Sign request ID that will be used to sign the vote extensions. // If not set, Tenderdash will generate it based on height and round. // If set, it SHOULD be unique per voting round, and it MUST start with `dpbvote` string. // // Use with caution - it can have severe security consequences. - optional bytes sign_id = 6; + optional bytes sign_request_id = 6; } // Finalize newly decided block. diff --git a/spec/abci++/api.md b/spec/abci++/api.md index 6af288bf5a..567ee3ddd3 100644 --- a/spec/abci++/api.md +++ b/spec/abci++/api.md @@ -775,8 +775,8 @@ from this condition, but not sure), and _p_ receives a Precommit message for rou | round | [int32](#int32) | | Round number for the block. | | vote_extensions | [ExtendVoteExtension](#tendermint-abci-ExtendVoteExtension) | repeated | Application-specific information signed by Tenderdash. Can have 0 length. -Sign ID that will be used to sign the vote extensions. If not set, Tenderdash will generate it based on height and round. | -| sign_id | [bytes](#bytes) | optional | If set, it SHOULD be unique per voting round, and it MUST start with `dpbvote` string. +Sign request ID that will be used to sign the vote extensions. If not set, Tenderdash will generate it based on height and round. | +| sign_request_id | [bytes](#bytes) | optional | If set, it SHOULD be unique per voting round, and it MUST start with `dpbvote` string. Use with caution - it can have severe security consequences. | From 222bbd37556ee0d8314826a6a0b7993d4b82b7d7 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:30:48 +0100 Subject: [PATCH 04/55] chore: doc --- proto/tendermint/abci/types.proto | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index c166f12993..ab3fe04aac 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -451,8 +451,11 @@ message RequestVerifyVoteExtension { // Application-specific information signed by Tenderdash. Can have 0 length. repeated ExtendVoteExtension vote_extensions = 5; // Sign request ID that will be used to sign the vote extensions. - // If not set, Tenderdash will generate it based on height and round. + // Tenderdash will use checksum of `sign_request_id` when generating quorum signatures of + // THRESHOLD_RECOVER vote extensions. + // If not set, Tenderdash will generate it based on height and round. + // // If set, it SHOULD be unique per voting round, and it MUST start with `dpbvote` string. // // Use with caution - it can have severe security consequences. From c8722f9c9badeb5596d897a98fa88ce7a729ce8b Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 12 Dec 2023 11:21:23 +0100 Subject: [PATCH 05/55] doc: typo --- proto/tendermint/abci/types.proto | 2 +- spec/abci++/api.md | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index ab3fe04aac..253779ed7a 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -456,7 +456,7 @@ message RequestVerifyVoteExtension { // If not set, Tenderdash will generate it based on height and round. // - // If set, it SHOULD be unique per voting round, and it MUST start with `dpbvote` string. + // If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` string. // // Use with caution - it can have severe security consequences. optional bytes sign_request_id = 6; diff --git a/spec/abci++/api.md b/spec/abci++/api.md index 567ee3ddd3..ec037e2c1c 100644 --- a/spec/abci++/api.md +++ b/spec/abci++/api.md @@ -775,8 +775,10 @@ from this condition, but not sure), and _p_ receives a Precommit message for rou | round | [int32](#int32) | | Round number for the block. | | vote_extensions | [ExtendVoteExtension](#tendermint-abci-ExtendVoteExtension) | repeated | Application-specific information signed by Tenderdash. Can have 0 length. -Sign request ID that will be used to sign the vote extensions. If not set, Tenderdash will generate it based on height and round. | -| sign_request_id | [bytes](#bytes) | optional | If set, it SHOULD be unique per voting round, and it MUST start with `dpbvote` string. +Sign request ID that will be used to sign the vote extensions. Tenderdash will use checksum of `sign_request_id` when generating quorum signatures of THRESHOLD_RECOVER vote extensions. | +| sign_request_id | [bytes](#bytes) | optional | If not set, Tenderdash will generate it based on height and round. + +If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` string. Use with caution - it can have severe security consequences. | From 1e28df1cd04d5c104f9eb4fa586db2529566a8ba Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:05:50 +0100 Subject: [PATCH 06/55] feat: add vote extension sign request id --- abci/example/kvstore/verify.go | 7 +- abci/types/types.go | 20 + abci/types/types.pb.go | 666 +++++++++++++++--------------- internal/consensus/vote_signer.go | 6 +- internal/test/factory/commit.go | 5 +- internal/test/factory/vote.go | 6 +- proto/tendermint/abci/types.proto | 22 +- proto/tendermint/types/dash.go | 57 +++ proto/tendermint/types/dash.pb.go | 168 ++++++-- proto/tendermint/types/dash.proto | 19 + spec/abci++/api.md | 20 +- types/canonical.go | 25 +- types/quorum.go | 2 +- types/quorum_sign_data.go | 6 +- types/test_util.go | 11 +- types/vote.go | 18 +- types/vote_dash.go | 12 - types/vote_extension.go | 78 +--- 18 files changed, 655 insertions(+), 493 deletions(-) diff --git a/abci/example/kvstore/verify.go b/abci/example/kvstore/verify.go index 5e81aa18a1..4780375019 100644 --- a/abci/example/kvstore/verify.go +++ b/abci/example/kvstore/verify.go @@ -69,15 +69,20 @@ func makeVoteExtensionSignItems( quorumHash []byte, ) map[types1.VoteExtensionType][]types.SignItem { items := make(map[types1.VoteExtensionType][]types.SignItem) - reqID := types.VoteExtensionRequestID(req.Height, req.Round) protoExtensionsMap := types1.VoteExtensionsToMap(req.Commit.ThresholdVoteExtensions) for t, exts := range protoExtensionsMap { + if t == types1.VoteExtensionType_DEFAULT { + // DEFAULT vote extensions don't support signing + continue + } if items[t] == nil && len(exts) > 0 { items[t] = make([]types.SignItem, len(exts)) } chainID := req.Block.Header.ChainID for i, ext := range exts { raw := types.VoteExtensionSignBytes(chainID, req.Height, req.Round, ext) + reqID := types.VoteExtensionRequestID(ext, req.Height, req.Round) + items[t][i] = types.NewSignItem(quorumType, quorumHash, reqID, raw) } } diff --git a/abci/types/types.go b/abci/types/types.go index c1569c67f8..07adde1ac8 100644 --- a/abci/types/types.go +++ b/abci/types/types.go @@ -370,3 +370,23 @@ func (m *RequestFinalizeBlock) ToCanonicalVote() (types.CanonicalVote, error) { } return cv, nil } + +// Convert to proto.types.VoteExtension. +// Signature field will be nil, as ExtendVoteExtension doesn't have it. +func (m *ExtendVoteExtension) ToVoteExtension() types.VoteExtension { + var requestID *types.VoteExtension_SignRequestId + if m.XSignRequestId != nil { + src := m.GetSignRequestId() + dst := make([]byte, len(src)) + copy(dst, src) + + requestID = &types.VoteExtension_SignRequestId{ + SignRequestId: dst, + } + } + return types.VoteExtension{ + Type: m.Type, + Extension: m.Extension, + XSignRequestId: requestID, + } +} diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 97aba029b9..12e14b93e8 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -1739,10 +1739,6 @@ type RequestVerifyVoteExtension struct { Round int32 `protobuf:"varint,4,opt,name=round,proto3" json:"round,omitempty"` // Application-specific information signed by Tenderdash. Can have 0 length. VoteExtensions []*ExtendVoteExtension `protobuf:"bytes,5,rep,name=vote_extensions,json=voteExtensions,proto3" json:"vote_extensions,omitempty"` - // Types that are valid to be assigned to XSignRequestId: - // - // *RequestVerifyVoteExtension_SignRequestId - XSignRequestId isRequestVerifyVoteExtension_XSignRequestId `protobuf_oneof:"_sign_request_id"` } func (m *RequestVerifyVoteExtension) Reset() { *m = RequestVerifyVoteExtension{} } @@ -1778,25 +1774,6 @@ func (m *RequestVerifyVoteExtension) XXX_DiscardUnknown() { var xxx_messageInfo_RequestVerifyVoteExtension proto.InternalMessageInfo -type isRequestVerifyVoteExtension_XSignRequestId interface { - isRequestVerifyVoteExtension_XSignRequestId() - MarshalTo([]byte) (int, error) - Size() int -} - -type RequestVerifyVoteExtension_SignRequestId struct { - SignRequestId []byte `protobuf:"bytes,6,opt,name=sign_request_id,json=signRequestId,proto3,oneof" json:"sign_request_id,omitempty"` -} - -func (*RequestVerifyVoteExtension_SignRequestId) isRequestVerifyVoteExtension_XSignRequestId() {} - -func (m *RequestVerifyVoteExtension) GetXSignRequestId() isRequestVerifyVoteExtension_XSignRequestId { - if m != nil { - return m.XSignRequestId - } - return nil -} - func (m *RequestVerifyVoteExtension) GetHash() []byte { if m != nil { return m.Hash @@ -1832,20 +1809,6 @@ func (m *RequestVerifyVoteExtension) GetVoteExtensions() []*ExtendVoteExtension return nil } -func (m *RequestVerifyVoteExtension) GetSignRequestId() []byte { - if x, ok := m.GetXSignRequestId().(*RequestVerifyVoteExtension_SignRequestId); ok { - return x.SignRequestId - } - return nil -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*RequestVerifyVoteExtension) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*RequestVerifyVoteExtension_SignRequestId)(nil), - } -} - // Finalize newly decided block. // // #### Usage @@ -3104,13 +3067,17 @@ func (m *ResponseProcessProposal) GetValidatorSetUpdate() *ValidatorSetUpdate { return nil } -// Provides a vote extension for signing. Each field is mandatory for filling +// Provides a vote extension for signing. `type` and `extension` fields are mandatory for filling type ExtendVoteExtension struct { // Vote extension type can be either DEFAULT or THRESHOLD_RECOVER. // The Tenderdash supports only THRESHOLD_RECOVER at this moment. Type types1.VoteExtensionType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.types.VoteExtensionType" json:"type,omitempty"` // Deterministic or (Non-Deterministic) extension provided by the sending validator's Application. Extension []byte `protobuf:"bytes,2,opt,name=extension,proto3" json:"extension,omitempty"` + // Types that are valid to be assigned to XSignRequestId: + // + // *ExtendVoteExtension_SignRequestId + XSignRequestId isExtendVoteExtension_XSignRequestId `protobuf_oneof:"_sign_request_id"` } func (m *ExtendVoteExtension) Reset() { *m = ExtendVoteExtension{} } @@ -3146,6 +3113,25 @@ func (m *ExtendVoteExtension) XXX_DiscardUnknown() { var xxx_messageInfo_ExtendVoteExtension proto.InternalMessageInfo +type isExtendVoteExtension_XSignRequestId interface { + isExtendVoteExtension_XSignRequestId() + MarshalTo([]byte) (int, error) + Size() int +} + +type ExtendVoteExtension_SignRequestId struct { + SignRequestId []byte `protobuf:"bytes,3,opt,name=sign_request_id,json=signRequestId,proto3,oneof" json:"sign_request_id,omitempty"` +} + +func (*ExtendVoteExtension_SignRequestId) isExtendVoteExtension_XSignRequestId() {} + +func (m *ExtendVoteExtension) GetXSignRequestId() isExtendVoteExtension_XSignRequestId { + if m != nil { + return m.XSignRequestId + } + return nil +} + func (m *ExtendVoteExtension) GetType() types1.VoteExtensionType { if m != nil { return m.Type @@ -3160,6 +3146,20 @@ func (m *ExtendVoteExtension) GetExtension() []byte { return nil } +func (m *ExtendVoteExtension) GetSignRequestId() []byte { + if x, ok := m.GetXSignRequestId().(*ExtendVoteExtension_SignRequestId); ok { + return x.SignRequestId + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*ExtendVoteExtension) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*ExtendVoteExtension_SignRequestId)(nil), + } +} + type ResponseExtendVote struct { VoteExtensions []*ExtendVoteExtension `protobuf:"bytes,1,rep,name=vote_extensions,json=voteExtensions,proto3" json:"vote_extensions,omitempty"` } @@ -4315,236 +4315,236 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 3664 bytes of a gzipped FileDescriptorProto + // 3661 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5b, 0xcd, 0x73, 0x1b, 0x57, 0x72, 0xc7, 0xe0, 0x1b, 0x8d, 0xaf, 0xe1, 0x23, 0x25, 0x41, 0x90, 0x44, 0xd2, 0xa3, 0xd8, 0x92, 0x65, 0x9b, 0xb4, 0xa5, 0xd8, 0xb2, 0x63, 0x27, 0x55, 0x20, 0x08, 0x05, 0x94, 0x28, 0x92, 0x1e, 0x82, 0x74, 0x39, 0x8e, 0x3d, 0x35, 0x04, 0x1e, 0x89, 0xb1, 0x00, 0xcc, 0x78, 0x66, 0x40, 0x81, - 0xbe, 0x26, 0x4e, 0xa5, 0x7c, 0xf2, 0x3f, 0xe0, 0x43, 0xaa, 0x92, 0x63, 0x2e, 0x39, 0xa5, 0x72, - 0x48, 0x2a, 0x37, 0xa7, 0x72, 0xf1, 0x31, 0x97, 0x68, 0x5d, 0xf2, 0x65, 0x6b, 0x6f, 0x7b, 0xda, - 0xdb, 0xd6, 0xd6, 0xfb, 0x98, 0x4f, 0x60, 0xf0, 0x21, 0xb9, 0x6a, 0x6b, 0x6f, 0x78, 0xfd, 0xba, - 0x7b, 0xde, 0x47, 0xbf, 0xee, 0x7e, 0xbf, 0x7e, 0x80, 0x6b, 0x36, 0x1e, 0x74, 0xb0, 0xd9, 0xd7, - 0x06, 0xf6, 0xa6, 0x7a, 0xd2, 0xd6, 0x36, 0xed, 0x0b, 0x03, 0x5b, 0x1b, 0x86, 0xa9, 0xdb, 0x3a, - 0x2a, 0x7b, 0x9d, 0x1b, 0xa4, 0xb3, 0x7a, 0xc3, 0xc7, 0xdd, 0x36, 0x2f, 0x0c, 0x5b, 0xdf, 0x34, - 0x4c, 0x5d, 0x3f, 0x65, 0xfc, 0x55, 0xbf, 0x32, 0xaa, 0x67, 0xb3, 0xa3, 0x5a, 0x5d, 0xde, 0x79, - 0x7d, 0xac, 0xf3, 0xa4, 0xa7, 0xb7, 0x9f, 0x44, 0xf6, 0xfa, 0x06, 0x12, 0xe8, 0xe5, 0xdf, 0x7d, - 0x82, 0x2f, 0x9c, 0xde, 0x1b, 0x63, 0xb2, 0x86, 0x6a, 0xaa, 0x7d, 0xa7, 0x7b, 0xd5, 0xd7, 0x7d, - 0x8e, 0x4d, 0x4b, 0xd3, 0x07, 0x01, 0xe5, 0x6b, 0x67, 0xba, 0x7e, 0xd6, 0xc3, 0x9b, 0xb4, 0x75, - 0x32, 0x3c, 0xdd, 0xb4, 0xb5, 0x3e, 0xb6, 0x6c, 0xb5, 0x6f, 0x70, 0x86, 0x95, 0x33, 0xfd, 0x4c, - 0xa7, 0x3f, 0x37, 0xc9, 0x2f, 0x46, 0x95, 0xbe, 0xc9, 0x41, 0x46, 0xc6, 0x5f, 0x0d, 0xb1, 0x65, - 0xa3, 0xbb, 0x90, 0xc4, 0xed, 0xae, 0x5e, 0x11, 0xd6, 0x85, 0xdb, 0xf9, 0xbb, 0xd7, 0x37, 0x42, - 0xeb, 0xb6, 0xc1, 0xf9, 0x1a, 0xed, 0xae, 0xde, 0x8c, 0xc9, 0x94, 0x17, 0xbd, 0x0b, 0xa9, 0xd3, - 0xde, 0xd0, 0xea, 0x56, 0xe2, 0x54, 0xe8, 0x46, 0x94, 0xd0, 0x03, 0xc2, 0xd4, 0x8c, 0xc9, 0x8c, - 0x9b, 0x7c, 0x4a, 0x1b, 0x9c, 0xea, 0x95, 0xc4, 0xf4, 0x4f, 0xed, 0x0c, 0x4e, 0xe9, 0xa7, 0x08, - 0x2f, 0xda, 0x02, 0xd0, 0x06, 0x9a, 0xad, 0xb4, 0xbb, 0xaa, 0x36, 0xa8, 0x24, 0xa9, 0xe4, 0x2b, - 0xd1, 0x92, 0x9a, 0x5d, 0x27, 0x8c, 0xcd, 0x98, 0x9c, 0xd3, 0x9c, 0x06, 0x19, 0xee, 0x57, 0x43, - 0x6c, 0x5e, 0x54, 0x52, 0xd3, 0x87, 0xfb, 0x31, 0x61, 0x22, 0xc3, 0xa5, 0xdc, 0xe8, 0x23, 0xc8, - 0xb6, 0xbb, 0xb8, 0xfd, 0x44, 0xb1, 0x47, 0x95, 0x0c, 0x95, 0x5c, 0x8b, 0x92, 0xac, 0x13, 0xbe, - 0xd6, 0xa8, 0x19, 0x93, 0x33, 0x6d, 0xf6, 0x13, 0xed, 0x41, 0xa9, 0xa7, 0x59, 0xb6, 0x62, 0x0d, - 0x54, 0xc3, 0xea, 0xea, 0xb6, 0x55, 0xc9, 0x53, 0x1d, 0xaf, 0x46, 0xe9, 0xd8, 0xd5, 0x2c, 0xfb, - 0xd0, 0x61, 0x6e, 0xc6, 0xe4, 0x62, 0xcf, 0x4f, 0x20, 0xfa, 0xf4, 0xd3, 0x53, 0x6c, 0xba, 0x0a, - 0x2b, 0x85, 0xe9, 0xfa, 0xf6, 0x09, 0xb7, 0x23, 0x4f, 0xf4, 0xe9, 0x7e, 0x02, 0xfa, 0x0c, 0x96, - 0x7b, 0xba, 0xda, 0x71, 0xd5, 0x29, 0xed, 0xee, 0x70, 0xf0, 0xa4, 0x52, 0xa4, 0x4a, 0x5f, 0x8f, - 0x1c, 0xa4, 0xae, 0x76, 0x1c, 0x15, 0x75, 0x22, 0xd0, 0x8c, 0xc9, 0x4b, 0xbd, 0x30, 0x11, 0x7d, - 0x01, 0x2b, 0xaa, 0x61, 0xf4, 0x2e, 0xc2, 0xda, 0x4b, 0x54, 0xfb, 0x9d, 0x28, 0xed, 0x35, 0x22, - 0x13, 0x56, 0x8f, 0xd4, 0x31, 0x2a, 0x6a, 0x81, 0x68, 0x98, 0xd8, 0x50, 0x4d, 0xac, 0x18, 0xa6, - 0x6e, 0xe8, 0x96, 0xda, 0xab, 0x94, 0xa9, 0xee, 0x5b, 0x51, 0xba, 0x0f, 0x18, 0xff, 0x01, 0x67, - 0x6f, 0xc6, 0xe4, 0xb2, 0x11, 0x24, 0x31, 0xad, 0x7a, 0x1b, 0x5b, 0x96, 0xa7, 0x55, 0x9c, 0xa5, - 0x95, 0xf2, 0x07, 0xb5, 0x06, 0x48, 0xa8, 0x01, 0x79, 0x3c, 0x22, 0xe2, 0xca, 0xb9, 0x6e, 0xe3, - 0xca, 0x12, 0x55, 0x28, 0x45, 0x9e, 0x33, 0xca, 0x7a, 0xac, 0xdb, 0xb8, 0x19, 0x93, 0x01, 0xbb, - 0x2d, 0xa4, 0xc2, 0xa5, 0x73, 0x6c, 0x6a, 0xa7, 0x17, 0x54, 0x8d, 0x42, 0x7b, 0x88, 0x3f, 0xa8, - 0x20, 0xaa, 0xf0, 0x8d, 0x28, 0x85, 0xc7, 0x54, 0x88, 0xa8, 0x68, 0x38, 0x22, 0xcd, 0x98, 0xbc, - 0x7c, 0x3e, 0x4e, 0x26, 0x26, 0x76, 0xaa, 0x0d, 0xd4, 0x9e, 0xf6, 0x35, 0x56, 0xa8, 0x83, 0xab, - 0x2c, 0x4f, 0x37, 0xb1, 0x07, 0x9c, 0x7b, 0x8b, 0x30, 0x13, 0x13, 0x3b, 0xf5, 0x13, 0xb6, 0x32, - 0x90, 0x3a, 0x57, 0x7b, 0x43, 0xfc, 0x30, 0x99, 0x4d, 0x8b, 0x99, 0x87, 0xc9, 0x6c, 0x56, 0xcc, - 0x3d, 0x4c, 0x66, 0x73, 0x22, 0x3c, 0x4c, 0x66, 0x41, 0xcc, 0x4b, 0xb7, 0x20, 0xef, 0x73, 0x2f, - 0xa8, 0x02, 0x99, 0x3e, 0xb6, 0x2c, 0xf5, 0x0c, 0x53, 0x6f, 0x94, 0x93, 0x9d, 0xa6, 0x54, 0x82, - 0x82, 0xdf, 0xa5, 0x48, 0xdf, 0x09, 0xae, 0x24, 0xf1, 0x16, 0x44, 0x92, 0xbb, 0x47, 0x47, 0x92, - 0x37, 0xd1, 0x4d, 0x28, 0xd2, 0xa9, 0x28, 0x4e, 0x3f, 0x71, 0x59, 0x49, 0xb9, 0x40, 0x89, 0xc7, - 0x9c, 0x69, 0x0d, 0xf2, 0xc6, 0x5d, 0xc3, 0x65, 0x49, 0x50, 0x16, 0x30, 0xee, 0x1a, 0x0e, 0xc3, - 0x2b, 0x50, 0x20, 0xf3, 0x76, 0x39, 0x92, 0xf4, 0x23, 0x79, 0x42, 0xe3, 0x2c, 0xd2, 0xdf, 0x27, - 0x40, 0x0c, 0xbb, 0x21, 0xf4, 0x3e, 0x24, 0x89, 0x47, 0xe6, 0xce, 0xb5, 0xba, 0xc1, 0xdc, 0xf5, - 0x86, 0xe3, 0xae, 0x37, 0x5a, 0x8e, 0xbb, 0xde, 0xca, 0xfe, 0xf0, 0x6c, 0x2d, 0xf6, 0xdd, 0xaf, - 0xd6, 0x04, 0x99, 0x4a, 0xa0, 0xab, 0xc4, 0xf9, 0xa8, 0xda, 0x40, 0xd1, 0x3a, 0x74, 0xc8, 0x39, - 0xe2, 0x59, 0x54, 0x6d, 0xb0, 0xd3, 0x41, 0xbb, 0x20, 0xb6, 0xf5, 0x81, 0x85, 0x07, 0xd6, 0xd0, - 0x52, 0x58, 0xb8, 0xe0, 0x2e, 0x35, 0xe0, 0x18, 0x59, 0x9c, 0xa8, 0x3b, 0x9c, 0x07, 0x94, 0x51, - 0x2e, 0xb7, 0x83, 0x04, 0xb4, 0x07, 0xc5, 0x73, 0xb5, 0xa7, 0x75, 0x54, 0x5b, 0x37, 0x15, 0x0b, - 0xdb, 0xdc, 0xc7, 0xde, 0x1c, 0xdb, 0xf3, 0x63, 0x87, 0xeb, 0x10, 0xdb, 0x47, 0x46, 0x47, 0xb5, - 0xf1, 0x56, 0xf2, 0x87, 0x67, 0x6b, 0x82, 0x5c, 0x38, 0xf7, 0xf5, 0xa0, 0xd7, 0xa0, 0xac, 0x1a, - 0x86, 0x62, 0xd9, 0xaa, 0x8d, 0x95, 0x93, 0x0b, 0x1b, 0x5b, 0xd4, 0xed, 0x16, 0xe4, 0xa2, 0x6a, - 0x18, 0x87, 0x84, 0xba, 0x45, 0x88, 0xe8, 0x55, 0x28, 0x11, 0x0f, 0xad, 0xa9, 0x3d, 0xa5, 0x8b, - 0xb5, 0xb3, 0xae, 0x5d, 0x49, 0xaf, 0x0b, 0xb7, 0x13, 0x72, 0x91, 0x53, 0x9b, 0x94, 0x88, 0x36, - 0x60, 0xd9, 0x61, 0x6b, 0xeb, 0x26, 0x76, 0x78, 0x89, 0x3f, 0x2e, 0xca, 0x4b, 0xbc, 0xab, 0xae, - 0x9b, 0x98, 0xf1, 0x4b, 0x1d, 0xd7, 0x52, 0xa8, 0x37, 0x47, 0x08, 0x92, 0x1d, 0xd5, 0x56, 0xe9, - 0x0e, 0x14, 0x64, 0xfa, 0x9b, 0xd0, 0x0c, 0xd5, 0xee, 0xf2, 0x75, 0xa5, 0xbf, 0xd1, 0x65, 0x48, - 0x73, 0xd5, 0x09, 0x3a, 0x0c, 0xde, 0x42, 0x2b, 0x90, 0x32, 0x4c, 0xfd, 0x1c, 0xd3, 0x65, 0xc9, - 0xca, 0xac, 0x21, 0xc9, 0x50, 0x0a, 0x7a, 0x7e, 0x54, 0x82, 0xb8, 0x3d, 0xe2, 0x5f, 0x89, 0xdb, - 0x23, 0xf4, 0x36, 0x24, 0xc9, 0x06, 0xd0, 0x6f, 0x94, 0x26, 0xc4, 0x3a, 0x2e, 0xd7, 0xba, 0x30, - 0xb0, 0x4c, 0x39, 0xa5, 0xcb, 0xb0, 0x32, 0x29, 0x12, 0x48, 0x5d, 0x97, 0x1e, 0xf0, 0xe8, 0xe8, - 0x5d, 0xc8, 0xba, 0xa1, 0x80, 0xd9, 0xd7, 0xd5, 0xb1, 0xaf, 0x38, 0xcc, 0xb2, 0xcb, 0x4a, 0x0c, - 0x8b, 0xec, 0x4f, 0x57, 0xe5, 0xe1, 0xbb, 0x20, 0x67, 0x54, 0xc3, 0x68, 0xaa, 0x56, 0x57, 0x3a, - 0x83, 0x4a, 0x94, 0x9b, 0xf7, 0xad, 0x8f, 0x40, 0x4f, 0x87, 0xb3, 0x3e, 0xbe, 0x93, 0x17, 0xa7, - 0x7b, 0xe2, 0x9e, 0x3c, 0x6a, 0xc1, 0xc3, 0xc1, 0x13, 0x62, 0xc1, 0x09, 0xf6, 0x21, 0xda, 0xde, - 0xe9, 0x48, 0x1d, 0xb8, 0x1a, 0xe9, 0xf1, 0x03, 0x72, 0x42, 0x40, 0x8e, 0x6c, 0x06, 0x8b, 0x23, - 0x6c, 0xe0, 0xac, 0x41, 0x86, 0x66, 0xd1, 0x79, 0xd3, 0xcf, 0xe4, 0x64, 0xde, 0x92, 0x7e, 0x9b, - 0x84, 0xcb, 0x93, 0x9d, 0x3f, 0x5a, 0x87, 0x42, 0x5f, 0x1d, 0x29, 0xf6, 0x88, 0x5b, 0xa8, 0x40, - 0xf7, 0x1c, 0xfa, 0xea, 0xa8, 0x35, 0x62, 0xe6, 0x29, 0x42, 0xc2, 0x1e, 0x59, 0x95, 0xf8, 0x7a, - 0xe2, 0x76, 0x41, 0x26, 0x3f, 0xd1, 0x63, 0x58, 0xea, 0xe9, 0x6d, 0xb5, 0xa7, 0xf4, 0x54, 0xcb, - 0x56, 0xda, 0x7a, 0xbf, 0xaf, 0xd9, 0xfc, 0xdc, 0x5d, 0x1b, 0xdf, 0x5e, 0xda, 0x4d, 0x7c, 0x13, - 0x3d, 0x24, 0x31, 0xb9, 0x4c, 0x65, 0x77, 0x55, 0xcb, 0x66, 0x5d, 0x68, 0x1b, 0xf2, 0x7d, 0xcd, - 0x3a, 0xc1, 0x5d, 0xf5, 0x5c, 0xd3, 0xcd, 0x4a, 0x72, 0x3d, 0x31, 0x31, 0x27, 0x7a, 0xec, 0xf1, - 0x70, 0x4d, 0x7e, 0x31, 0xdf, 0xb6, 0xa4, 0x02, 0x66, 0xeb, 0x38, 0x9e, 0xf4, 0xc2, 0x8e, 0xe7, - 0x6d, 0x58, 0x19, 0xe0, 0x91, 0xad, 0xb8, 0x87, 0xda, 0x62, 0xb6, 0x92, 0xa1, 0x4b, 0x8e, 0x48, - 0x9f, 0xeb, 0x09, 0x2c, 0x62, 0x36, 0x64, 0x57, 0x4c, 0x7d, 0x38, 0xe8, 0x54, 0xb2, 0xeb, 0xc2, - 0xed, 0x94, 0xcc, 0x1a, 0xe8, 0x3e, 0x54, 0xe8, 0x81, 0x65, 0x5e, 0x8c, 0x78, 0x5b, 0xdc, 0x71, - 0x4e, 0x6f, 0x8e, 0x5a, 0xca, 0x25, 0xd2, 0x4f, 0xfd, 0xe4, 0x2e, 0xed, 0xe5, 0x27, 0x7e, 0x13, - 0x56, 0x58, 0xf4, 0xc5, 0x26, 0x09, 0xc3, 0x64, 0x93, 0xe8, 0x00, 0x80, 0x0e, 0x60, 0xc9, 0xe9, - 0x3b, 0x30, 0xf5, 0xd6, 0x88, 0x7e, 0xff, 0x6d, 0x57, 0xa0, 0xa3, 0x10, 0xd3, 0x76, 0xec, 0x31, - 0x4f, 0x0d, 0x15, 0x39, 0x7d, 0x35, 0xc3, 0x75, 0xe7, 0xf7, 0x3d, 0xa3, 0x2d, 0x8c, 0xa7, 0x84, - 0xbc, 0xcb, 0x73, 0x9d, 0x9e, 0x4d, 0xaf, 0x41, 0xfe, 0xab, 0xa1, 0x6e, 0x0e, 0xfb, 0x6c, 0x48, - 0x45, 0x3a, 0x24, 0x60, 0x24, 0x7a, 0x84, 0xfe, 0x2b, 0xe5, 0xb3, 0xb9, 0x60, 0x1e, 0xc0, 0x2d, - 0x4a, 0xf0, 0x2c, 0xea, 0xd0, 0x37, 0x70, 0xbf, 0x51, 0xc5, 0xe7, 0x35, 0x2a, 0x77, 0x6e, 0xd1, - 0x76, 0x95, 0x78, 0x31, 0xbb, 0x42, 0x90, 0xa4, 0x33, 0x4c, 0x32, 0xb7, 0x49, 0x7e, 0x47, 0xda, - 0x9a, 0xbb, 0xff, 0x69, 0xff, 0xfe, 0x3b, 0x16, 0x98, 0xf9, 0xc5, 0x2c, 0x30, 0x1b, 0x69, 0x81, - 0x2f, 0x6c, 0x6b, 0x2d, 0xb8, 0x1c, 0x12, 0x54, 0x86, 0x34, 0xb4, 0x51, 0x6b, 0x0b, 0x25, 0xfc, - 0x4e, 0x40, 0xf5, 0x29, 0x92, 0x97, 0x03, 0x7a, 0x59, 0x58, 0x8c, 0xb4, 0xe0, 0xfc, 0xa2, 0x16, - 0x5c, 0x98, 0xc7, 0x82, 0x8b, 0x2f, 0x63, 0xc1, 0xa5, 0x31, 0x0b, 0x3e, 0x82, 0xa5, 0xb1, 0x54, - 0xd4, 0x35, 0x07, 0x61, 0xa2, 0x39, 0xc4, 0x27, 0x9b, 0x43, 0xc2, 0x67, 0x0e, 0xd2, 0x3f, 0xc5, - 0xa1, 0x1a, 0x9d, 0x91, 0x4e, 0xfc, 0xc0, 0x3b, 0x70, 0xc9, 0xcb, 0x4c, 0xfc, 0xeb, 0xc8, 0xbc, - 0x3f, 0x72, 0x3b, 0xbd, 0x85, 0x9c, 0x12, 0xc5, 0xd9, 0x98, 0x92, 0x7e, 0x13, 0x7d, 0x0c, 0xe5, - 0x60, 0x2e, 0x4d, 0x52, 0x15, 0x72, 0x5c, 0xfe, 0x6c, 0xec, 0xb8, 0x78, 0x6b, 0xe1, 0x8e, 0x59, - 0x2e, 0x9d, 0xfb, 0x9b, 0x16, 0x7a, 0x03, 0xca, 0x96, 0x76, 0x36, 0x50, 0x4c, 0x36, 0x4d, 0x12, - 0xbf, 0xc8, 0x89, 0x28, 0x90, 0xc4, 0x98, 0x74, 0x38, 0xd9, 0x61, 0xe7, 0x1f, 0x05, 0x61, 0x0b, - 0x81, 0xa8, 0x84, 0xb8, 0xa5, 0xff, 0x8d, 0xbb, 0xa1, 0x3e, 0x90, 0x59, 0xa3, 0x0f, 0x20, 0xcd, - 0x5d, 0x83, 0x30, 0xaf, 0x6b, 0xe0, 0x02, 0x61, 0x77, 0x10, 0x7f, 0x39, 0x77, 0x90, 0x98, 0xb8, - 0xff, 0xc9, 0xc9, 0x6b, 0x9d, 0xf2, 0xaf, 0xf5, 0x5b, 0x90, 0x62, 0x57, 0x0a, 0x16, 0x91, 0xae, - 0x8c, 0x1f, 0x2c, 0x3a, 0x55, 0x99, 0x71, 0xa1, 0x1a, 0x64, 0x59, 0xda, 0xae, 0x75, 0xb8, 0x07, - 0xb9, 0x1a, 0x21, 0xb1, 0xb3, 0xbd, 0x95, 0x7f, 0xfe, 0x6c, 0x2d, 0xc3, 0x1b, 0x72, 0x86, 0xca, - 0xed, 0x74, 0xa4, 0xff, 0xce, 0x41, 0x56, 0xc6, 0x96, 0x41, 0xce, 0x00, 0xda, 0x82, 0x1c, 0x1e, - 0xb5, 0xb1, 0x61, 0x3b, 0x57, 0x84, 0xc9, 0x57, 0x30, 0xc6, 0xdd, 0x70, 0x38, 0x9b, 0x31, 0xd9, - 0x13, 0x43, 0xf7, 0x38, 0x52, 0x12, 0x0d, 0x7a, 0x70, 0x71, 0x3f, 0x54, 0xf2, 0x9e, 0x03, 0x95, - 0xb0, 0x4c, 0x61, 0x35, 0x52, 0x2a, 0x84, 0x95, 0xdc, 0xe3, 0x58, 0x49, 0x72, 0xc6, 0xc7, 0x02, - 0x60, 0x49, 0x3d, 0x00, 0x96, 0xa4, 0x66, 0x4c, 0x33, 0x02, 0x2d, 0x79, 0xcf, 0x41, 0x4b, 0xd2, - 0x33, 0x46, 0x1c, 0x82, 0x4b, 0xfe, 0x72, 0x0c, 0x2e, 0x59, 0x8f, 0x14, 0x9d, 0x80, 0x97, 0xec, - 0x8f, 0xe1, 0x25, 0x59, 0xaa, 0xe4, 0xb5, 0x48, 0x25, 0x33, 0x00, 0x93, 0xfd, 0x31, 0xc0, 0x24, - 0x37, 0x43, 0xe1, 0x0c, 0xc4, 0xe4, 0x6f, 0x27, 0x23, 0x26, 0x10, 0x89, 0x69, 0xf0, 0x61, 0xce, - 0x07, 0x99, 0x28, 0x11, 0x90, 0x49, 0x3e, 0xf2, 0x7a, 0xcf, 0xd4, 0xcf, 0x8d, 0x99, 0x1c, 0x4d, - 0xc0, 0x4c, 0x58, 0xf6, 0x73, 0x3b, 0x52, 0xf9, 0x1c, 0xa0, 0xc9, 0xd1, 0x04, 0xd0, 0xa4, 0x38, - 0x53, 0xed, 0x4c, 0xd4, 0xe4, 0x41, 0x10, 0x35, 0x29, 0x45, 0x5c, 0x4a, 0xbd, 0x23, 0x1b, 0x01, - 0x9b, 0x9c, 0x44, 0xc1, 0x26, 0x0c, 0x2e, 0x7a, 0x33, 0x52, 0xe3, 0x02, 0xb8, 0xc9, 0xfe, 0x18, - 0x6e, 0x22, 0xce, 0xb0, 0xb4, 0x39, 0x81, 0x13, 0xe9, 0x75, 0x12, 0x8c, 0x43, 0x4e, 0x89, 0x38, - 0x58, 0x6c, 0x9a, 0xba, 0xc9, 0xa1, 0x0e, 0xd6, 0x90, 0x6e, 0x93, 0x8b, 0xaf, 0xe7, 0x80, 0xa6, - 0x80, 0x29, 0x65, 0x28, 0x06, 0x9c, 0x8e, 0xf4, 0xef, 0x82, 0x27, 0x4b, 0xe1, 0x14, 0xff, 0xa5, - 0x39, 0xc7, 0x2f, 0xcd, 0xa1, 0x8b, 0x5e, 0x2e, 0x90, 0x52, 0xf8, 0x93, 0x16, 0x8e, 0x9e, 0xa8, - 0x5e, 0xb2, 0x72, 0x07, 0x96, 0x68, 0x7a, 0xcb, 0x3c, 0x7a, 0x20, 0x68, 0x94, 0x49, 0x07, 0x5b, - 0x05, 0x16, 0x3d, 0xde, 0x82, 0x65, 0x1f, 0xaf, 0x7b, 0x53, 0x65, 0x10, 0x82, 0xe8, 0x72, 0xd7, - 0xf8, 0x95, 0xf5, 0xd7, 0x71, 0x6f, 0x85, 0x3c, 0xd8, 0x65, 0x12, 0x42, 0x22, 0xbc, 0x30, 0x42, - 0x12, 0x7d, 0x63, 0x46, 0x9f, 0xc1, 0x4a, 0x00, 0x3c, 0x71, 0xb2, 0xc7, 0xc4, 0x62, 0x18, 0x4a, - 0xcc, 0x97, 0xcc, 0xb8, 0x3d, 0xe8, 0x73, 0xb8, 0x46, 0xf3, 0xe0, 0x88, 0x0c, 0x35, 0x39, 0x5f, - 0x86, 0x7a, 0x85, 0xe8, 0xa8, 0x4f, 0xc8, 0x52, 0x23, 0x90, 0x95, 0x54, 0x14, 0xb2, 0xf2, 0x3b, - 0xc1, 0xb3, 0x1b, 0x17, 0x5b, 0x69, 0xeb, 0x1d, 0x66, 0x5f, 0x45, 0x99, 0xfe, 0x26, 0xb7, 0x9c, - 0x9e, 0x7e, 0xc6, 0x4d, 0x84, 0xfc, 0x24, 0x5c, 0x2e, 0xea, 0x9f, 0xe3, 0x81, 0x6a, 0x05, 0x52, - 0xda, 0xa0, 0x83, 0x47, 0xdc, 0x0a, 0x58, 0x83, 0xc8, 0x3e, 0xc1, 0x17, 0x7c, 0xaf, 0xc9, 0x4f, - 0xc2, 0x47, 0x0f, 0x02, 0x4b, 0xa4, 0x64, 0xd6, 0x40, 0xef, 0x43, 0x8e, 0x96, 0x6e, 0x14, 0xdd, - 0xb0, 0x78, 0xa8, 0x09, 0x64, 0x44, 0xac, 0xcc, 0xb2, 0x71, 0x40, 0x78, 0xf6, 0x0d, 0x4b, 0xce, + 0xbe, 0x26, 0x4e, 0xa5, 0x7c, 0xf2, 0x3f, 0xe0, 0x5b, 0x72, 0xcc, 0x25, 0xa7, 0x54, 0x0e, 0x49, + 0xed, 0xcd, 0x5b, 0x7b, 0xf1, 0x71, 0x2f, 0xab, 0x75, 0xc9, 0x97, 0xad, 0xbd, 0xed, 0x69, 0x6f, + 0x5b, 0x5b, 0xef, 0x63, 0x3e, 0x81, 0xc1, 0x87, 0xe5, 0xaa, 0xad, 0xbd, 0xe1, 0xf5, 0xeb, 0xee, + 0x79, 0x1f, 0xfd, 0xba, 0xfb, 0xfd, 0xfa, 0x01, 0xae, 0xd9, 0x78, 0xd0, 0xc1, 0x66, 0x5f, 0x1b, + 0xd8, 0x9b, 0xea, 0x49, 0x5b, 0xdb, 0xb4, 0x2f, 0x0c, 0x6c, 0x6d, 0x18, 0xa6, 0x6e, 0xeb, 0xa8, + 0xec, 0x75, 0x6e, 0x90, 0xce, 0xea, 0x0d, 0x1f, 0x77, 0xdb, 0xbc, 0x30, 0x6c, 0x7d, 0xd3, 0x30, + 0x75, 0xfd, 0x94, 0xf1, 0x57, 0xfd, 0xca, 0xa8, 0x9e, 0xcd, 0x8e, 0x6a, 0x75, 0x79, 0xe7, 0xf5, + 0xb1, 0xce, 0x93, 0x9e, 0xde, 0x7e, 0x12, 0xd9, 0xeb, 0x1b, 0x48, 0xa0, 0x97, 0x7f, 0xf7, 0x09, + 0xbe, 0x70, 0x7a, 0x6f, 0x8c, 0xc9, 0x1a, 0xaa, 0xa9, 0xf6, 0x9d, 0xee, 0x55, 0x5f, 0xf7, 0x39, + 0x36, 0x2d, 0x4d, 0x1f, 0x04, 0x94, 0xaf, 0x9d, 0xe9, 0xfa, 0x59, 0x0f, 0x6f, 0xd2, 0xd6, 0xc9, + 0xf0, 0x74, 0xd3, 0xd6, 0xfa, 0xd8, 0xb2, 0xd5, 0xbe, 0xc1, 0x19, 0x56, 0xce, 0xf4, 0x33, 0x9d, + 0xfe, 0xdc, 0x24, 0xbf, 0x18, 0x55, 0xfa, 0x2a, 0x07, 0x19, 0x19, 0x7f, 0x31, 0xc4, 0x96, 0x8d, + 0xee, 0x42, 0x12, 0xb7, 0xbb, 0x7a, 0x45, 0x58, 0x17, 0x6e, 0xe7, 0xef, 0x5e, 0xdf, 0x08, 0xad, + 0xdb, 0x06, 0xe7, 0x6b, 0xb4, 0xbb, 0x7a, 0x33, 0x26, 0x53, 0x5e, 0xf4, 0x36, 0xa4, 0x4e, 0x7b, + 0x43, 0xab, 0x5b, 0x89, 0x53, 0xa1, 0x1b, 0x51, 0x42, 0x0f, 0x08, 0x53, 0x33, 0x26, 0x33, 0x6e, + 0xf2, 0x29, 0x6d, 0x70, 0xaa, 0x57, 0x12, 0xd3, 0x3f, 0xb5, 0x33, 0x38, 0xa5, 0x9f, 0x22, 0xbc, + 0x68, 0x0b, 0x40, 0x1b, 0x68, 0xb6, 0xd2, 0xee, 0xaa, 0xda, 0xa0, 0x92, 0xa4, 0x92, 0x2f, 0x45, + 0x4b, 0x6a, 0x76, 0x9d, 0x30, 0x36, 0x63, 0x72, 0x4e, 0x73, 0x1a, 0x64, 0xb8, 0x5f, 0x0c, 0xb1, + 0x79, 0x51, 0x49, 0x4d, 0x1f, 0xee, 0x87, 0x84, 0x89, 0x0c, 0x97, 0x72, 0xa3, 0x0f, 0x20, 0xdb, + 0xee, 0xe2, 0xf6, 0x13, 0xc5, 0x1e, 0x55, 0x32, 0x54, 0x72, 0x2d, 0x4a, 0xb2, 0x4e, 0xf8, 0x5a, + 0xa3, 0x66, 0x4c, 0xce, 0xb4, 0xd9, 0x4f, 0xb4, 0x07, 0xa5, 0x9e, 0x66, 0xd9, 0x8a, 0x35, 0x50, + 0x0d, 0xab, 0xab, 0xdb, 0x56, 0x25, 0x4f, 0x75, 0xbc, 0x1c, 0xa5, 0x63, 0x57, 0xb3, 0xec, 0x43, + 0x87, 0xb9, 0x19, 0x93, 0x8b, 0x3d, 0x3f, 0x81, 0xe8, 0xd3, 0x4f, 0x4f, 0xb1, 0xe9, 0x2a, 0xac, + 0x14, 0xa6, 0xeb, 0xdb, 0x27, 0xdc, 0x8e, 0x3c, 0xd1, 0xa7, 0xfb, 0x09, 0xe8, 0x13, 0x58, 0xee, + 0xe9, 0x6a, 0xc7, 0x55, 0xa7, 0xb4, 0xbb, 0xc3, 0xc1, 0x93, 0x4a, 0x91, 0x2a, 0x7d, 0x35, 0x72, + 0x90, 0xba, 0xda, 0x71, 0x54, 0xd4, 0x89, 0x40, 0x33, 0x26, 0x2f, 0xf5, 0xc2, 0x44, 0xf4, 0x19, + 0xac, 0xa8, 0x86, 0xd1, 0xbb, 0x08, 0x6b, 0x2f, 0x51, 0xed, 0x77, 0xa2, 0xb4, 0xd7, 0x88, 0x4c, + 0x58, 0x3d, 0x52, 0xc7, 0xa8, 0xa8, 0x05, 0xa2, 0x61, 0x62, 0x43, 0x35, 0xb1, 0x62, 0x98, 0xba, + 0xa1, 0x5b, 0x6a, 0xaf, 0x52, 0xa6, 0xba, 0x6f, 0x45, 0xe9, 0x3e, 0x60, 0xfc, 0x07, 0x9c, 0xbd, + 0x19, 0x93, 0xcb, 0x46, 0x90, 0xc4, 0xb4, 0xea, 0x6d, 0x6c, 0x59, 0x9e, 0x56, 0x71, 0x96, 0x56, + 0xca, 0x1f, 0xd4, 0x1a, 0x20, 0xa1, 0x06, 0xe4, 0xf1, 0x88, 0x88, 0x2b, 0xe7, 0xba, 0x8d, 0x2b, + 0x4b, 0x54, 0xa1, 0x14, 0x79, 0xce, 0x28, 0xeb, 0xb1, 0x6e, 0xe3, 0x66, 0x4c, 0x06, 0xec, 0xb6, + 0x90, 0x0a, 0x97, 0xce, 0xb1, 0xa9, 0x9d, 0x5e, 0x50, 0x35, 0x0a, 0xed, 0x21, 0xfe, 0xa0, 0x82, + 0xa8, 0xc2, 0xd7, 0xa2, 0x14, 0x1e, 0x53, 0x21, 0xa2, 0xa2, 0xe1, 0x88, 0x34, 0x63, 0xf2, 0xf2, + 0xf9, 0x38, 0x99, 0x98, 0xd8, 0xa9, 0x36, 0x50, 0x7b, 0xda, 0x97, 0x58, 0xa1, 0x0e, 0xae, 0xb2, + 0x3c, 0xdd, 0xc4, 0x1e, 0x70, 0xee, 0x2d, 0xc2, 0x4c, 0x4c, 0xec, 0xd4, 0x4f, 0xd8, 0xca, 0x40, + 0xea, 0x5c, 0xed, 0x0d, 0xf1, 0xc3, 0x64, 0x36, 0x2d, 0x66, 0x1e, 0x26, 0xb3, 0x59, 0x31, 0xf7, + 0x30, 0x99, 0xcd, 0x89, 0xf0, 0x30, 0x99, 0x05, 0x31, 0x2f, 0xdd, 0x82, 0xbc, 0xcf, 0xbd, 0xa0, + 0x0a, 0x64, 0xfa, 0xd8, 0xb2, 0xd4, 0x33, 0x4c, 0xbd, 0x51, 0x4e, 0x76, 0x9a, 0x52, 0x09, 0x0a, + 0x7e, 0x97, 0x22, 0x7d, 0x23, 0xb8, 0x92, 0xc4, 0x5b, 0x10, 0x49, 0xee, 0x1e, 0x1d, 0x49, 0xde, + 0x44, 0x37, 0xa1, 0x48, 0xa7, 0xa2, 0x38, 0xfd, 0xc4, 0x65, 0x25, 0xe5, 0x02, 0x25, 0x1e, 0x73, + 0xa6, 0x35, 0xc8, 0x1b, 0x77, 0x0d, 0x97, 0x25, 0x41, 0x59, 0xc0, 0xb8, 0x6b, 0x38, 0x0c, 0x2f, + 0x41, 0x81, 0xcc, 0xdb, 0xe5, 0x48, 0xd2, 0x8f, 0xe4, 0x09, 0x8d, 0xb3, 0x48, 0xff, 0x9a, 0x00, + 0x31, 0xec, 0x86, 0xd0, 0xbb, 0x90, 0x24, 0x1e, 0x99, 0x3b, 0xd7, 0xea, 0x06, 0x73, 0xd7, 0x1b, + 0x8e, 0xbb, 0xde, 0x68, 0x39, 0xee, 0x7a, 0x2b, 0xfb, 0xdd, 0xb3, 0xb5, 0xd8, 0x37, 0xbf, 0x5d, + 0x13, 0x64, 0x2a, 0x81, 0xae, 0x12, 0xe7, 0xa3, 0x6a, 0x03, 0x45, 0xeb, 0xd0, 0x21, 0xe7, 0x88, + 0x67, 0x51, 0xb5, 0xc1, 0x4e, 0x07, 0xed, 0x82, 0xd8, 0xd6, 0x07, 0x16, 0x1e, 0x58, 0x43, 0x4b, + 0x61, 0xe1, 0x82, 0xbb, 0xd4, 0x80, 0x63, 0x64, 0x71, 0xa2, 0xee, 0x70, 0x1e, 0x50, 0x46, 0xb9, + 0xdc, 0x0e, 0x12, 0xd0, 0x1e, 0x14, 0xcf, 0xd5, 0x9e, 0xd6, 0x51, 0x6d, 0xdd, 0x54, 0x2c, 0x6c, + 0x73, 0x1f, 0x7b, 0x73, 0x6c, 0xcf, 0x8f, 0x1d, 0xae, 0x43, 0x6c, 0x1f, 0x19, 0x1d, 0xd5, 0xc6, + 0x5b, 0xc9, 0xef, 0x9e, 0xad, 0x09, 0x72, 0xe1, 0xdc, 0xd7, 0x83, 0x5e, 0x81, 0xb2, 0x6a, 0x18, + 0x8a, 0x65, 0xab, 0x36, 0x56, 0x4e, 0x2e, 0x6c, 0x6c, 0x51, 0xb7, 0x5b, 0x90, 0x8b, 0xaa, 0x61, + 0x1c, 0x12, 0xea, 0x16, 0x21, 0xa2, 0x97, 0xa1, 0x44, 0x3c, 0xb4, 0xa6, 0xf6, 0x94, 0x2e, 0xd6, + 0xce, 0xba, 0x76, 0x25, 0xbd, 0x2e, 0xdc, 0x4e, 0xc8, 0x45, 0x4e, 0x6d, 0x52, 0x22, 0xda, 0x80, + 0x65, 0x87, 0xad, 0xad, 0x9b, 0xd8, 0xe1, 0x25, 0xfe, 0xb8, 0x28, 0x2f, 0xf1, 0xae, 0xba, 0x6e, + 0x62, 0xc6, 0x2f, 0x75, 0x5c, 0x4b, 0xa1, 0xde, 0x1c, 0x21, 0x48, 0x76, 0x54, 0x5b, 0xa5, 0x3b, + 0x50, 0x90, 0xe9, 0x6f, 0x42, 0x33, 0x54, 0xbb, 0xcb, 0xd7, 0x95, 0xfe, 0x46, 0x97, 0x21, 0xcd, + 0x55, 0x27, 0xe8, 0x30, 0x78, 0x0b, 0xad, 0x40, 0xca, 0x30, 0xf5, 0x73, 0x4c, 0x97, 0x25, 0x2b, + 0xb3, 0x86, 0x24, 0x43, 0x29, 0xe8, 0xf9, 0x51, 0x09, 0xe2, 0xf6, 0x88, 0x7f, 0x25, 0x6e, 0x8f, + 0xd0, 0x9b, 0x90, 0x24, 0x1b, 0x40, 0xbf, 0x51, 0x9a, 0x10, 0xeb, 0xb8, 0x5c, 0xeb, 0xc2, 0xc0, + 0x32, 0xe5, 0x94, 0x2e, 0xc3, 0xca, 0xa4, 0x48, 0x20, 0x75, 0x5d, 0x7a, 0xc0, 0xa3, 0xa3, 0xb7, + 0x21, 0xeb, 0x86, 0x02, 0x66, 0x5f, 0x57, 0xc7, 0xbe, 0xe2, 0x30, 0xcb, 0x2e, 0x2b, 0x31, 0x2c, + 0xb2, 0x3f, 0x5d, 0x95, 0x87, 0xef, 0x82, 0x9c, 0x51, 0x0d, 0xa3, 0xa9, 0x5a, 0x5d, 0xe9, 0x0c, + 0x2a, 0x51, 0x6e, 0xde, 0xb7, 0x3e, 0x02, 0x3d, 0x1d, 0xce, 0xfa, 0xf8, 0x4e, 0x5e, 0x9c, 0xee, + 0x89, 0x7b, 0xf2, 0xa8, 0x05, 0x0f, 0x07, 0x4f, 0x88, 0x05, 0x27, 0xd8, 0x87, 0x68, 0x7b, 0xa7, + 0x23, 0x75, 0xe0, 0x6a, 0xa4, 0xc7, 0x0f, 0xc8, 0x09, 0x01, 0x39, 0xb2, 0x19, 0x2c, 0x8e, 0xb0, + 0x81, 0xb3, 0x06, 0x19, 0x9a, 0x45, 0xe7, 0x4d, 0x3f, 0x93, 0x93, 0x79, 0x4b, 0xfa, 0x43, 0x12, + 0x2e, 0x4f, 0x76, 0xfe, 0x68, 0x1d, 0x0a, 0x7d, 0x75, 0xa4, 0xd8, 0x23, 0x6e, 0xa1, 0x02, 0xdd, + 0x73, 0xe8, 0xab, 0xa3, 0xd6, 0x88, 0x99, 0xa7, 0x08, 0x09, 0x7b, 0x64, 0x55, 0xe2, 0xeb, 0x89, + 0xdb, 0x05, 0x99, 0xfc, 0x44, 0x8f, 0x61, 0xa9, 0xa7, 0xb7, 0xd5, 0x9e, 0xd2, 0x53, 0x2d, 0x5b, + 0x69, 0xeb, 0xfd, 0xbe, 0x66, 0xf3, 0x73, 0x77, 0x6d, 0x7c, 0x7b, 0x69, 0x37, 0xf1, 0x4d, 0xf4, + 0x90, 0xc4, 0xe4, 0x32, 0x95, 0xdd, 0x55, 0x2d, 0x9b, 0x75, 0xa1, 0x6d, 0xc8, 0xf7, 0x35, 0xeb, + 0x04, 0x77, 0xd5, 0x73, 0x4d, 0x37, 0x2b, 0xc9, 0xf5, 0xc4, 0xc4, 0x9c, 0xe8, 0xb1, 0xc7, 0xc3, + 0x35, 0xf9, 0xc5, 0x7c, 0xdb, 0x92, 0x0a, 0x98, 0xad, 0xe3, 0x78, 0xd2, 0x0b, 0x3b, 0x9e, 0x37, + 0x61, 0x65, 0x80, 0x47, 0xb6, 0xe2, 0x1e, 0x6a, 0x8b, 0xd9, 0x4a, 0x86, 0x2e, 0x39, 0x22, 0x7d, + 0xae, 0x27, 0xb0, 0x88, 0xd9, 0x90, 0x5d, 0x31, 0xf5, 0xe1, 0xa0, 0x53, 0xc9, 0xae, 0x0b, 0xb7, + 0x53, 0x32, 0x6b, 0xa0, 0xfb, 0x50, 0xa1, 0x07, 0x96, 0x79, 0x31, 0xe2, 0x6d, 0x71, 0xc7, 0x39, + 0xbd, 0x39, 0x6a, 0x29, 0x97, 0x48, 0x3f, 0xf5, 0x93, 0xbb, 0xb4, 0x97, 0x9f, 0xf8, 0x4d, 0x58, + 0x61, 0xd1, 0x17, 0x9b, 0x24, 0x0c, 0x93, 0x4d, 0xa2, 0x03, 0x00, 0x3a, 0x80, 0x25, 0xa7, 0xef, + 0xc0, 0xd4, 0x5b, 0x23, 0xfa, 0xfd, 0x37, 0x5d, 0x81, 0x8e, 0x42, 0x4c, 0xdb, 0xb1, 0xc7, 0x3c, + 0x35, 0x54, 0xe4, 0xf4, 0xd5, 0x0c, 0xd7, 0x9d, 0xdf, 0xf7, 0x8c, 0xb6, 0x30, 0x9e, 0x12, 0xf2, + 0x2e, 0xcf, 0x75, 0x7a, 0x36, 0xbd, 0x06, 0xf9, 0x2f, 0x86, 0xba, 0x39, 0xec, 0xb3, 0x21, 0x15, + 0xe9, 0x90, 0x80, 0x91, 0xe8, 0x11, 0xfa, 0xff, 0x94, 0xcf, 0xe6, 0x82, 0x79, 0x00, 0xb7, 0x28, + 0xc1, 0xb3, 0xa8, 0x43, 0xdf, 0xc0, 0xfd, 0x46, 0x15, 0x9f, 0xd7, 0xa8, 0xdc, 0xb9, 0x45, 0xdb, + 0x55, 0xe2, 0xa7, 0xd9, 0x15, 0x82, 0x24, 0x9d, 0x61, 0x92, 0xb9, 0x4d, 0xf2, 0x3b, 0xd2, 0xd6, + 0xdc, 0xfd, 0x4f, 0xfb, 0xf7, 0xdf, 0xb1, 0xc0, 0xcc, 0xcf, 0x66, 0x81, 0xd9, 0x48, 0x0b, 0xfc, + 0xc9, 0xb6, 0xd6, 0x82, 0xcb, 0x21, 0x41, 0x65, 0x48, 0x43, 0x1b, 0xb5, 0xb6, 0x50, 0xc2, 0xef, + 0x04, 0x54, 0x9f, 0x22, 0x79, 0x39, 0xa0, 0x97, 0x85, 0xc5, 0x48, 0x0b, 0xce, 0x2f, 0x6a, 0xc1, + 0x85, 0x79, 0x2c, 0xb8, 0xf8, 0x22, 0x16, 0x5c, 0x1a, 0xb3, 0xe0, 0x23, 0x58, 0x1a, 0x4b, 0x45, + 0x5d, 0x73, 0x10, 0x26, 0x9a, 0x43, 0x7c, 0xb2, 0x39, 0x24, 0x7c, 0xe6, 0x20, 0xfd, 0x20, 0x40, + 0x35, 0x3a, 0x23, 0x9d, 0xf8, 0x81, 0xb7, 0xe0, 0x92, 0x97, 0x99, 0xf8, 0xd7, 0x91, 0x79, 0x7f, + 0xe4, 0x76, 0x7a, 0x0b, 0x39, 0x25, 0x8a, 0xb3, 0x31, 0x25, 0xfd, 0x26, 0xfa, 0x18, 0xca, 0xc1, + 0x5c, 0x9a, 0xa4, 0x2a, 0xe4, 0xb8, 0xfc, 0xcd, 0xd8, 0x71, 0xf1, 0xd6, 0xc2, 0x1d, 0xb3, 0x5c, + 0x3a, 0xf7, 0x37, 0x2d, 0xe9, 0x57, 0x71, 0x37, 0x52, 0x07, 0x12, 0x63, 0xf4, 0x1e, 0xa4, 0xf9, + 0xc9, 0x16, 0xe6, 0x3d, 0xd9, 0x5c, 0x20, 0x7c, 0x9a, 0xe3, 0x2f, 0x76, 0x9a, 0x13, 0x13, 0xb7, + 0x2f, 0x39, 0x79, 0xa9, 0x52, 0xfe, 0xa5, 0x7a, 0x03, 0x52, 0xec, 0x46, 0xc0, 0x02, 0xca, 0x95, + 0xf1, 0x73, 0x41, 0xa7, 0x2a, 0x33, 0x2e, 0x54, 0x83, 0x2c, 0xcb, 0xba, 0xb5, 0x0e, 0x77, 0x00, + 0x57, 0x23, 0x24, 0x76, 0xb6, 0xb7, 0xf2, 0xcf, 0x9f, 0xad, 0x65, 0x78, 0x43, 0xce, 0x50, 0xb9, + 0x9d, 0x8e, 0xf4, 0x8b, 0x1c, 0x64, 0x65, 0x6c, 0x19, 0xc4, 0x84, 0xd1, 0x16, 0xe4, 0xf0, 0xa8, + 0x8d, 0x0d, 0xdb, 0xc9, 0xf0, 0x27, 0xdf, 0xa0, 0x18, 0x77, 0xc3, 0xe1, 0x6c, 0xc6, 0x64, 0x4f, + 0x0c, 0xdd, 0xe3, 0x40, 0x47, 0x34, 0x66, 0xc1, 0xc5, 0xfd, 0x48, 0xc7, 0x3b, 0x0e, 0xd2, 0xc1, + 0x02, 0xfd, 0x6a, 0xa4, 0x54, 0x08, 0xea, 0xb8, 0xc7, 0xa1, 0x8e, 0xe4, 0x8c, 0x8f, 0x05, 0xb0, + 0x8e, 0x7a, 0x00, 0xeb, 0x48, 0xcd, 0x98, 0x66, 0x04, 0xd8, 0xf1, 0x8e, 0x03, 0x76, 0xa4, 0x67, + 0x8c, 0x38, 0x84, 0x76, 0xfc, 0xfd, 0x18, 0xda, 0xb1, 0x1e, 0x29, 0x3a, 0x01, 0xee, 0xd8, 0x1f, + 0x83, 0x3b, 0xb2, 0x54, 0xc9, 0x2b, 0x91, 0x4a, 0x66, 0xe0, 0x1d, 0xfb, 0x63, 0x78, 0x47, 0x6e, + 0x86, 0xc2, 0x19, 0x80, 0xc7, 0x3f, 0x4f, 0x06, 0x3c, 0x20, 0x12, 0x92, 0xe0, 0xc3, 0x9c, 0x0f, + 0xf1, 0x50, 0x22, 0x10, 0x8f, 0x7c, 0xe4, 0xed, 0x9c, 0xa9, 0x9f, 0x1b, 0xf2, 0x38, 0x9a, 0x00, + 0x79, 0xb0, 0xe4, 0xe5, 0x76, 0xa4, 0xf2, 0x39, 0x30, 0x8f, 0xa3, 0x09, 0x98, 0x47, 0x71, 0xa6, + 0xda, 0x99, 0xa0, 0xc7, 0x83, 0x20, 0xe8, 0x51, 0x8a, 0xb8, 0x53, 0x7a, 0x47, 0x36, 0x02, 0xf5, + 0x38, 0x89, 0x42, 0x3d, 0x18, 0xda, 0xf3, 0x7a, 0xa4, 0xc6, 0x05, 0x60, 0x8f, 0xfd, 0x31, 0xd8, + 0x43, 0x9c, 0x61, 0x69, 0x73, 0xe2, 0x1e, 0xd2, 0xab, 0x24, 0x96, 0x86, 0x9c, 0x12, 0x71, 0xb0, + 0xd8, 0x34, 0x75, 0x93, 0x23, 0x15, 0xac, 0x21, 0xdd, 0x26, 0xf7, 0x56, 0xcf, 0x01, 0x4d, 0xc1, + 0x42, 0xca, 0x50, 0x0c, 0x38, 0x1d, 0xe9, 0x7f, 0x04, 0x4f, 0x96, 0xa2, 0x21, 0xfe, 0x3b, 0x6f, + 0x8e, 0xdf, 0x79, 0x43, 0xf7, 0xb4, 0x5c, 0x20, 0x23, 0xf0, 0xe7, 0x1c, 0x1c, 0xfc, 0x50, 0xbd, + 0x5c, 0xe3, 0x0e, 0x2c, 0xd1, 0xec, 0x94, 0x79, 0xf4, 0x40, 0xd0, 0x28, 0x93, 0x0e, 0xb6, 0x0a, + 0x2c, 0x7a, 0xbc, 0x01, 0xcb, 0x3e, 0x5e, 0xf7, 0xa2, 0xc9, 0x10, 0x00, 0xd1, 0xe5, 0xae, 0xf1, + 0x1b, 0xe7, 0xef, 0xe2, 0xde, 0x0a, 0x79, 0xa8, 0xc9, 0x24, 0x80, 0x43, 0xf8, 0xc9, 0x00, 0x47, + 0xf4, 0x85, 0x17, 0x7d, 0x02, 0x2b, 0x01, 0xec, 0xc3, 0x49, 0xfe, 0x12, 0x8b, 0x41, 0x20, 0x31, + 0x5f, 0x2e, 0xe2, 0xf6, 0xa0, 0x4f, 0xe1, 0x1a, 0x4d, 0x63, 0x23, 0x12, 0xcc, 0xe4, 0x7c, 0x09, + 0xe6, 0x15, 0xa2, 0xa3, 0x3e, 0x21, 0xc9, 0x8c, 0x00, 0x46, 0x52, 0x51, 0xc0, 0xc8, 0x1f, 0x05, + 0xcf, 0x6e, 0x5c, 0x68, 0xa4, 0xad, 0x77, 0x98, 0x7d, 0x15, 0x65, 0xfa, 0x9b, 0x5c, 0x52, 0x7a, + 0xfa, 0x19, 0x37, 0x11, 0xf2, 0x93, 0x70, 0xb9, 0xa0, 0x7d, 0x8e, 0x07, 0xaa, 0x15, 0x48, 0x69, + 0x83, 0x0e, 0x1e, 0x71, 0x2b, 0x60, 0x0d, 0x22, 0xfb, 0x04, 0x5f, 0xf0, 0xbd, 0x26, 0x3f, 0x09, + 0x1f, 0x3d, 0x08, 0x34, 0x16, 0x15, 0x64, 0xd6, 0x40, 0xef, 0x42, 0x8e, 0x56, 0x5e, 0x14, 0xdd, + 0xb0, 0x78, 0xa8, 0x09, 0x64, 0x44, 0xac, 0x4a, 0xb2, 0x71, 0x40, 0x78, 0xf6, 0x0d, 0x4b, 0xce, 0x1a, 0xfc, 0x97, 0x2f, 0x67, 0xc9, 0x06, 0x72, 0x96, 0xeb, 0x90, 0x23, 0xa3, 0xb7, 0x0c, 0xb5, - 0x8d, 0x69, 0x98, 0xc8, 0xc9, 0x1e, 0x41, 0xfa, 0x4f, 0x01, 0xca, 0xa1, 0xc8, 0x35, 0x71, 0xee, - 0xce, 0xb1, 0x89, 0x07, 0xb1, 0xa6, 0xb1, 0xd9, 0xdf, 0x00, 0x38, 0x53, 0x2d, 0xe5, 0xa9, 0x3a, - 0xb0, 0x71, 0x87, 0x2f, 0x41, 0xee, 0x4c, 0xb5, 0x3e, 0xa1, 0x84, 0xe0, 0x60, 0x52, 0xa1, 0xc1, - 0xf8, 0xd0, 0x8e, 0xb4, 0x1f, 0xed, 0x40, 0x55, 0xc8, 0x1a, 0xa6, 0xa6, 0x9b, 0x9a, 0x7d, 0x41, + 0x8d, 0x69, 0x98, 0xc8, 0xc9, 0x1e, 0x41, 0xfa, 0x3f, 0x01, 0xca, 0xa1, 0xc8, 0x35, 0x71, 0xee, + 0xce, 0xb1, 0x89, 0x07, 0xa1, 0xa2, 0xb1, 0xd9, 0xdf, 0x00, 0x38, 0x53, 0x2d, 0xe5, 0xa9, 0x3a, + 0xb0, 0x71, 0x87, 0x2f, 0x41, 0xee, 0x4c, 0xb5, 0x3e, 0xa2, 0x84, 0xe0, 0x60, 0x52, 0xa1, 0xc1, + 0xf8, 0xc0, 0x8a, 0xb4, 0x1f, 0xac, 0x40, 0x55, 0xc8, 0x1a, 0xa6, 0xa6, 0x9b, 0x9a, 0x7d, 0x41, 0xd7, 0x24, 0x21, 0xbb, 0x6d, 0xe9, 0x00, 0x2e, 0x4d, 0x0c, 0x9a, 0xe8, 0x3e, 0xe4, 0xbc, 0x78, - 0x2b, 0xd0, 0xdc, 0x70, 0x0a, 0x88, 0xe4, 0xf1, 0x92, 0x25, 0xb9, 0x34, 0x31, 0x6c, 0xa2, 0x06, - 0xa4, 0x4d, 0x6c, 0x0d, 0x7b, 0x2c, 0x57, 0x2d, 0xdd, 0x7d, 0x6b, 0xbe, 0x70, 0x4b, 0xa8, 0xc3, - 0x9e, 0x2d, 0x73, 0x61, 0xe9, 0x0b, 0x48, 0x33, 0x0a, 0xca, 0x43, 0xe6, 0x68, 0xef, 0xd1, 0xde, - 0xfe, 0x27, 0x7b, 0x62, 0x0c, 0x01, 0xa4, 0x6b, 0xf5, 0x7a, 0xe3, 0xa0, 0x25, 0x0a, 0x28, 0x07, + 0x2b, 0xd0, 0xdc, 0x70, 0x0a, 0x06, 0xe4, 0xf1, 0x92, 0x25, 0xb9, 0x34, 0x31, 0x6c, 0xa2, 0x06, + 0xa4, 0x4d, 0x6c, 0x0d, 0x7b, 0x2c, 0x57, 0x2d, 0xdd, 0x7d, 0x63, 0xbe, 0x70, 0x4b, 0xa8, 0xc3, + 0x9e, 0x2d, 0x73, 0x61, 0xe9, 0x33, 0x48, 0x33, 0x0a, 0xca, 0x43, 0xe6, 0x68, 0xef, 0xd1, 0xde, + 0xfe, 0x47, 0x7b, 0x62, 0x0c, 0x01, 0xa4, 0x6b, 0xf5, 0x7a, 0xe3, 0xa0, 0x25, 0x0a, 0x28, 0x07, 0xa9, 0xda, 0xd6, 0xbe, 0xdc, 0x12, 0xe3, 0x84, 0x2c, 0x37, 0x1e, 0x36, 0xea, 0x2d, 0x31, 0x81, 0x96, 0xa0, 0xc8, 0x7e, 0x2b, 0x0f, 0xf6, 0xe5, 0xc7, 0xb5, 0x96, 0x98, 0xf4, 0x91, 0x0e, 0x1b, - 0x7b, 0xdb, 0x0d, 0x59, 0x4c, 0x49, 0xef, 0xc0, 0xd5, 0xc8, 0x00, 0xed, 0xe1, 0x4c, 0x82, 0x0f, - 0x67, 0x92, 0x7e, 0xa4, 0x57, 0x98, 0xa8, 0xa8, 0x8b, 0x1e, 0x86, 0x26, 0x7e, 0x77, 0x81, 0x90, - 0x1d, 0x9a, 0x3d, 0x7a, 0x15, 0x4a, 0x26, 0x3e, 0xc5, 0x76, 0xbb, 0xcb, 0xb2, 0x00, 0x07, 0x88, - 0x2a, 0x72, 0x2a, 0x15, 0xb2, 0x18, 0xdb, 0x97, 0xb8, 0x6d, 0x2b, 0xcc, 0x08, 0x2c, 0x7a, 0xdd, - 0xcf, 0x11, 0x36, 0x42, 0x3d, 0x64, 0x44, 0xe2, 0xa0, 0x99, 0x23, 0x61, 0xaa, 0x92, 0x54, 0x15, - 0x50, 0xbf, 0x40, 0x29, 0xd2, 0xd3, 0x85, 0x16, 0x3b, 0x07, 0x29, 0xb9, 0xd1, 0x92, 0x3f, 0x15, - 0x13, 0x08, 0x41, 0x89, 0xfe, 0x54, 0x0e, 0xf7, 0x6a, 0x07, 0x87, 0xcd, 0x7d, 0xb2, 0xd8, 0xcb, - 0x50, 0x76, 0x16, 0xdb, 0x21, 0xa6, 0xd0, 0x25, 0x58, 0xaa, 0xef, 0x3f, 0x3e, 0xd8, 0x6d, 0xb4, - 0x1a, 0x1e, 0x39, 0x2d, 0xfd, 0x47, 0x02, 0xae, 0x44, 0xe4, 0x1a, 0xe8, 0x7d, 0x00, 0x7b, 0xa4, - 0x98, 0xb8, 0xad, 0x9b, 0x9d, 0x68, 0xe3, 0x6c, 0x8d, 0x64, 0xca, 0x21, 0xe7, 0x6c, 0xfe, 0x6b, - 0xaa, 0xc3, 0xfe, 0x88, 0x2b, 0x25, 0x93, 0xb5, 0x38, 0x38, 0x72, 0x63, 0xc2, 0x6d, 0x0f, 0xb7, - 0x89, 0x62, 0xba, 0x27, 0x54, 0x31, 0xe5, 0x47, 0x9f, 0xc2, 0x95, 0x50, 0x5c, 0xe1, 0xce, 0xd8, - 0x9a, 0x54, 0x99, 0x9c, 0x1c, 0x5e, 0x2e, 0x05, 0xc3, 0x0b, 0x73, 0xc6, 0xd6, 0x14, 0x24, 0x22, - 0xf5, 0x12, 0x48, 0x44, 0x54, 0x7c, 0x4a, 0x2f, 0x8a, 0xf1, 0x4f, 0x88, 0x4f, 0xd2, 0xbf, 0x05, - 0x36, 0x2f, 0x98, 0xbe, 0xed, 0x43, 0xda, 0xb2, 0x55, 0x7b, 0x68, 0xf1, 0xc3, 0x70, 0x7f, 0xde, - 0x5c, 0x70, 0xc3, 0xf9, 0x71, 0x48, 0xc5, 0x65, 0xae, 0xe6, 0x4f, 0x72, 0x4f, 0xa3, 0x56, 0x3f, - 0xf5, 0x4b, 0xac, 0xfe, 0xbb, 0x50, 0x0a, 0x2e, 0x55, 0xf4, 0xd9, 0xf5, 0xbc, 0x63, 0x5c, 0xea, - 0xc1, 0xf2, 0x04, 0x2c, 0x03, 0xdd, 0xe7, 0xe5, 0x0a, 0xb6, 0x5b, 0x37, 0xc7, 0xa7, 0x1c, 0x60, - 0xf7, 0xaa, 0x16, 0x24, 0x58, 0x79, 0x39, 0x35, 0xdb, 0x18, 0x8f, 0x20, 0xb5, 0x01, 0x8d, 0x67, - 0xe8, 0x93, 0x70, 0x17, 0xe1, 0xc5, 0x71, 0x17, 0xe9, 0x5f, 0x04, 0xb8, 0x36, 0x25, 0x6b, 0x47, - 0x1f, 0x87, 0x6c, 0xf1, 0x83, 0x45, 0x72, 0xfe, 0x0d, 0x46, 0x0b, 0x5a, 0xa3, 0x74, 0x0f, 0x0a, - 0x7e, 0xfa, 0x7c, 0x4b, 0xff, 0x0f, 0xbe, 0x98, 0x19, 0xc4, 0x77, 0x9a, 0x90, 0xc6, 0xe7, 0x78, - 0xe0, 0xc6, 0xe0, 0xcb, 0xe3, 0xeb, 0x40, 0xba, 0xb7, 0x2a, 0x24, 0x57, 0xfc, 0xcd, 0xb3, 0x35, - 0x91, 0x71, 0xbf, 0xa9, 0xf7, 0x35, 0x1b, 0xf7, 0x0d, 0xfb, 0x42, 0xe6, 0xf2, 0xe8, 0x26, 0x14, - 0x4d, 0x6c, 0x13, 0x17, 0x12, 0xc0, 0xe6, 0x0a, 0x8c, 0xc8, 0x33, 0xb9, 0xff, 0x11, 0x00, 0x3c, - 0xc0, 0xc8, 0x03, 0x6c, 0x04, 0x3f, 0x60, 0x13, 0x02, 0x0a, 0xe3, 0x61, 0xa0, 0x10, 0xdd, 0x82, - 0x32, 0x4b, 0xd2, 0x2d, 0xed, 0x6c, 0xa0, 0xda, 0x43, 0x13, 0x73, 0x78, 0xa8, 0x44, 0xc9, 0x87, - 0x0e, 0x15, 0x7d, 0x06, 0x57, 0xed, 0xae, 0x89, 0xad, 0xae, 0xde, 0xeb, 0x28, 0xe1, 0x8d, 0x67, - 0x75, 0x8f, 0xb5, 0x19, 0x06, 0x27, 0x5f, 0x71, 0x35, 0x1c, 0x07, 0x37, 0xff, 0x6b, 0x48, 0xd1, - 0xb5, 0x21, 0x89, 0x96, 0x6b, 0xc1, 0x39, 0x6e, 0x9c, 0x9f, 0x03, 0xa8, 0xb6, 0x6d, 0x6a, 0x27, - 0x43, 0x72, 0x9c, 0xe3, 0xe3, 0x9f, 0xf2, 0xd6, 0xb6, 0xe6, 0xf0, 0x6d, 0x5d, 0xe7, 0x8b, 0xbc, - 0xe2, 0x89, 0xfa, 0x16, 0xda, 0xa7, 0x50, 0xda, 0x83, 0x52, 0x50, 0xd6, 0xc9, 0x60, 0xd9, 0x18, - 0x82, 0x19, 0x2c, 0xcb, 0x88, 0x79, 0x06, 0xeb, 0xe6, 0xbf, 0x09, 0x56, 0x55, 0xa4, 0x0d, 0xe9, - 0xf7, 0x02, 0x14, 0xfc, 0x6e, 0x6a, 0xee, 0x24, 0x93, 0x27, 0xdd, 0x89, 0xf1, 0xa4, 0x3b, 0x19, - 0x99, 0x76, 0xa6, 0xc2, 0x69, 0xe7, 0x55, 0xc8, 0x92, 0xee, 0xa1, 0x85, 0x3b, 0xbc, 0x14, 0x9b, - 0x39, 0x53, 0xad, 0x23, 0x0b, 0x77, 0x7c, 0xf6, 0x99, 0x79, 0x49, 0xfb, 0x0c, 0xe4, 0xb6, 0xd9, - 0x70, 0xa2, 0xfd, 0x8d, 0x00, 0x59, 0x77, 0xf2, 0xc1, 0x8a, 0x63, 0x00, 0x5f, 0x64, 0x6b, 0xc7, - 0xea, 0x8d, 0xfc, 0xee, 0xc0, 0xea, 0xaf, 0x09, 0xb7, 0xfe, 0xfa, 0xa1, 0x9b, 0x8d, 0x45, 0x21, - 0x68, 0xfe, 0x95, 0x76, 0x40, 0x53, 0x9e, 0x7c, 0xfe, 0x33, 0x1f, 0x07, 0x49, 0x27, 0xd0, 0x5f, - 0x40, 0x5a, 0x6d, 0xbb, 0xb8, 0x61, 0x69, 0x02, 0xa0, 0xe6, 0xb0, 0x6e, 0xb4, 0x46, 0x35, 0xca, - 0x29, 0x73, 0x09, 0x3e, 0xaa, 0xb8, 0x33, 0x2a, 0x69, 0x97, 0xe8, 0x65, 0x3c, 0x41, 0x9f, 0x51, - 0x02, 0x38, 0xda, 0x7b, 0xbc, 0xbf, 0xbd, 0xf3, 0x60, 0xa7, 0xb1, 0xcd, 0xd3, 0xad, 0xed, 0xed, - 0xc6, 0xb6, 0x18, 0x27, 0x7c, 0x72, 0xe3, 0xf1, 0xfe, 0x71, 0x63, 0x5b, 0x4c, 0x90, 0xc6, 0x76, - 0x63, 0xb7, 0xf6, 0x69, 0x63, 0x5b, 0x4c, 0x4a, 0x35, 0xc8, 0xb9, 0x21, 0x83, 0x16, 0xaa, 0xf5, - 0xa7, 0xd8, 0xe4, 0xab, 0xc5, 0x1a, 0x68, 0x15, 0xf2, 0xe3, 0xc8, 0x39, 0xb9, 0x3d, 0x31, 0xc0, - 0x5c, 0xfa, 0x57, 0x01, 0xca, 0xae, 0x0e, 0x9e, 0x34, 0x7c, 0x08, 0x19, 0x63, 0x78, 0xa2, 0x38, - 0x86, 0x1c, 0x82, 0x8b, 0x9d, 0xcb, 0xd5, 0xf0, 0xa4, 0xa7, 0xb5, 0x1f, 0xe1, 0x0b, 0x1e, 0xa2, - 0xd2, 0xc6, 0xf0, 0xe4, 0x11, 0xb3, 0x77, 0x36, 0x8c, 0xf8, 0x94, 0x61, 0x24, 0x42, 0xc3, 0x40, - 0xb7, 0xa0, 0x30, 0xd0, 0x3b, 0x58, 0x51, 0x3b, 0x1d, 0x13, 0x5b, 0x2c, 0xf2, 0xe6, 0xb8, 0xe6, - 0x3c, 0xe9, 0xa9, 0xb1, 0x0e, 0xe9, 0x27, 0x01, 0xd0, 0x78, 0x98, 0x44, 0x87, 0xb0, 0xe4, 0x45, - 0x5a, 0x27, 0x7c, 0x33, 0x5f, 0xba, 0x1e, 0x1d, 0x66, 0x03, 0x37, 0x70, 0xf1, 0x3c, 0x48, 0x26, - 0x29, 0xd9, 0x8a, 0xe7, 0xb7, 0x0c, 0x3a, 0x5f, 0xba, 0x28, 0xf1, 0x39, 0x17, 0x25, 0x26, 0x23, - 0x57, 0xde, 0xed, 0x09, 0xfb, 0xd5, 0xc4, 0x58, 0x01, 0xc6, 0x80, 0x4a, 0x6b, 0x4c, 0x8c, 0xcf, - 0x33, 0x6a, 0x48, 0xc2, 0xcb, 0x0c, 0x49, 0xba, 0x07, 0xe2, 0xc7, 0xee, 0xf7, 0xf9, 0x97, 0x42, - 0xc3, 0x14, 0xc6, 0x86, 0x79, 0x0e, 0x59, 0xe2, 0x8a, 0x69, 0x04, 0xf9, 0x2b, 0xc8, 0xb9, 0xab, - 0xe7, 0xbe, 0x75, 0x89, 0x5c, 0x76, 0x3e, 0x12, 0x4f, 0x04, 0xdd, 0x81, 0x25, 0x12, 0x44, 0x9c, - 0x32, 0x28, 0xc3, 0xd0, 0xe2, 0xd4, 0x35, 0x96, 0x59, 0xc7, 0xae, 0x03, 0xfc, 0x90, 0x68, 0x2f, - 0xb2, 0xac, 0x00, 0x77, 0xfe, 0x18, 0x03, 0x20, 0x97, 0xae, 0x10, 0x94, 0xc8, 0xf6, 0xb0, 0x18, - 0x48, 0x4b, 0xa4, 0xbf, 0x8b, 0x43, 0xde, 0x57, 0x55, 0x41, 0x7f, 0x1e, 0xc8, 0xb0, 0xd6, 0xa7, - 0x55, 0x60, 0x7c, 0xe9, 0x55, 0x60, 0x62, 0xf1, 0xc5, 0x27, 0x16, 0x55, 0x10, 0x73, 0xaa, 0xb3, - 0xc9, 0x85, 0xab, 0xb3, 0x6f, 0x02, 0xb2, 0x75, 0x5b, 0xed, 0x91, 0x48, 0xae, 0x0d, 0xce, 0x14, - 0x76, 0xda, 0x59, 0x34, 0x11, 0x69, 0xcf, 0x31, 0xed, 0x38, 0x20, 0x74, 0xa9, 0x07, 0x59, 0x17, - 0x19, 0x58, 0xfc, 0x09, 0xc9, 0xa4, 0x2a, 0x74, 0x15, 0xb2, 0x7d, 0x6c, 0xab, 0x34, 0x06, 0x32, - 0xa4, 0xc8, 0x6d, 0xdf, 0xf9, 0x00, 0xf2, 0xbe, 0x77, 0x35, 0x24, 0x2c, 0xee, 0x35, 0x3e, 0x11, - 0x63, 0xd5, 0xcc, 0xb7, 0xdf, 0xaf, 0x27, 0xf6, 0xf0, 0x53, 0xf2, 0x29, 0xb9, 0x51, 0x6f, 0x36, - 0xea, 0x8f, 0x44, 0xa1, 0x9a, 0xff, 0xf6, 0xfb, 0xf5, 0x8c, 0x8c, 0x69, 0x01, 0xe2, 0xce, 0x23, - 0x28, 0x87, 0x76, 0x20, 0xe8, 0xa0, 0x11, 0x94, 0xb6, 0x8f, 0x0e, 0x76, 0x77, 0xea, 0xb5, 0x56, - 0x43, 0x39, 0xde, 0x6f, 0x35, 0x44, 0x01, 0x5d, 0x81, 0xe5, 0xdd, 0x9d, 0xbf, 0x6e, 0xb6, 0x94, - 0xfa, 0xee, 0x4e, 0x63, 0xaf, 0xa5, 0xd4, 0x5a, 0xad, 0x5a, 0xfd, 0x91, 0x18, 0xbf, 0xfb, 0xff, - 0x00, 0xe5, 0xda, 0x56, 0x7d, 0x87, 0x5c, 0xf4, 0xb5, 0xb6, 0x4a, 0xdd, 0x7d, 0x1d, 0x92, 0x14, - 0x97, 0x9d, 0xfa, 0xc2, 0xb6, 0x3a, 0xbd, 0xaa, 0x84, 0x1e, 0x40, 0x8a, 0x42, 0xb6, 0x68, 0xfa, - 0x93, 0xdb, 0xea, 0x8c, 0x32, 0x13, 0x19, 0x0c, 0x3d, 0x37, 0x53, 0xdf, 0xe0, 0x56, 0xa7, 0x57, - 0x9d, 0xd0, 0x2e, 0x64, 0x1c, 0x34, 0x6c, 0xd6, 0xc3, 0xd8, 0xea, 0xcc, 0x52, 0x10, 0x99, 0x1a, - 0x43, 0x15, 0xa7, 0x3f, 0xcf, 0xad, 0xce, 0xa8, 0x47, 0x21, 0x19, 0x72, 0x1e, 0x10, 0x3c, 0xfb, - 0xa5, 0x70, 0x75, 0x8e, 0xfa, 0x18, 0xfa, 0x02, 0x8a, 0x41, 0xdc, 0x6c, 0xbe, 0x47, 0xbc, 0xd5, - 0x39, 0x6b, 0x57, 0x44, 0x7f, 0x10, 0x44, 0x9b, 0xef, 0x51, 0x6f, 0x75, 0xce, 0x52, 0x16, 0xfa, - 0x12, 0x96, 0xc6, 0x41, 0xae, 0xf9, 0xdf, 0xf8, 0x56, 0x17, 0x28, 0x6e, 0xa1, 0x3e, 0xa0, 0x09, - 0xe0, 0xd8, 0x02, 0x4f, 0x7e, 0xab, 0x8b, 0xd4, 0xba, 0x50, 0x07, 0xca, 0x61, 0xe0, 0x68, 0xde, - 0x27, 0xc0, 0xd5, 0xb9, 0xeb, 0x5e, 0xec, 0x2b, 0x41, 0x84, 0x63, 0xde, 0x27, 0xc1, 0xd5, 0xb9, - 0xcb, 0x60, 0xe8, 0x08, 0xc0, 0x77, 0x4b, 0x9e, 0xe3, 0x89, 0x70, 0x75, 0x9e, 0x82, 0x18, 0x32, - 0x60, 0x79, 0xd2, 0xb5, 0x78, 0x91, 0x17, 0xc3, 0xd5, 0x85, 0xea, 0x64, 0xc4, 0x9e, 0x83, 0x17, - 0xdc, 0xf9, 0x5e, 0x10, 0x57, 0xe7, 0x2c, 0x98, 0x6d, 0x6d, 0xfd, 0xf0, 0x7c, 0x55, 0xf8, 0xf1, - 0xf9, 0xaa, 0xf0, 0xd3, 0xf3, 0x55, 0xe1, 0xbb, 0x9f, 0x57, 0x63, 0x3f, 0xfe, 0xbc, 0x1a, 0xfb, - 0xbf, 0x9f, 0x57, 0x63, 0x7f, 0x73, 0xfb, 0x4c, 0xb3, 0xbb, 0xc3, 0x93, 0x8d, 0xb6, 0xde, 0xa7, - 0x7f, 0xe0, 0x30, 0xd4, 0x8b, 0x4d, 0xa6, 0x93, 0xb4, 0x7c, 0x7f, 0x13, 0x39, 0x49, 0xd3, 0x58, - 0x77, 0xef, 0x0f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x17, 0xa2, 0x6a, 0x60, 0x46, 0x32, 0x00, 0x00, + 0x7b, 0xdb, 0x0d, 0x59, 0x4c, 0x49, 0x6f, 0xc1, 0xd5, 0xc8, 0x00, 0xed, 0xc1, 0x44, 0x82, 0x0f, + 0x26, 0x92, 0xbe, 0x8f, 0x93, 0x1b, 0x48, 0x54, 0xd4, 0x45, 0x0f, 0x43, 0x13, 0xbf, 0xbb, 0x40, + 0xc8, 0x0e, 0xcd, 0x1e, 0xbd, 0x0c, 0x25, 0x13, 0x9f, 0x62, 0xbb, 0xdd, 0x65, 0x59, 0x80, 0x83, + 0x23, 0x15, 0x39, 0x95, 0x0a, 0x59, 0x8c, 0xed, 0x73, 0xdc, 0xb6, 0x15, 0x66, 0x04, 0x16, 0xbd, + 0xad, 0xe7, 0x08, 0x1b, 0xa1, 0x1e, 0x32, 0x22, 0x71, 0xd0, 0xcc, 0x91, 0x30, 0x55, 0x49, 0xaa, + 0x0a, 0xa8, 0x5f, 0xa0, 0x14, 0xe9, 0xe9, 0x42, 0x8b, 0x9d, 0x83, 0x94, 0xdc, 0x68, 0xc9, 0x1f, + 0x8b, 0x09, 0x84, 0xa0, 0x44, 0x7f, 0x2a, 0x87, 0x7b, 0xb5, 0x83, 0xc3, 0xe6, 0x3e, 0x59, 0xec, + 0x65, 0x28, 0x3b, 0x8b, 0xed, 0x10, 0x53, 0xe8, 0x12, 0x2c, 0xd5, 0xf7, 0x1f, 0x1f, 0xec, 0x36, + 0x5a, 0x0d, 0x8f, 0x9c, 0x96, 0xfe, 0x37, 0x01, 0x57, 0x22, 0x72, 0x0d, 0xf4, 0x2e, 0x80, 0x3d, + 0x52, 0x4c, 0xdc, 0xd6, 0xcd, 0x4e, 0xb4, 0x71, 0xb6, 0x46, 0x32, 0xe5, 0x90, 0x73, 0x36, 0xff, + 0x35, 0xd5, 0x61, 0x7f, 0xc0, 0x95, 0x92, 0xc9, 0x5a, 0x1c, 0xdb, 0xb8, 0x31, 0xe1, 0xb2, 0x86, + 0xdb, 0x44, 0x31, 0xdd, 0x13, 0xaa, 0x98, 0xf2, 0xa3, 0x8f, 0xe1, 0x4a, 0x28, 0xae, 0x70, 0x67, + 0x6c, 0x4d, 0x2a, 0x2c, 0x4e, 0x0e, 0x2f, 0x97, 0x82, 0xe1, 0x85, 0x39, 0x63, 0x6b, 0x0a, 0x90, + 0x90, 0x7a, 0x01, 0x20, 0x21, 0x2a, 0x3e, 0xa5, 0x17, 0x85, 0xe8, 0x27, 0xc4, 0x27, 0xe9, 0xbf, + 0x03, 0x9b, 0x17, 0x4c, 0xdf, 0xf6, 0x21, 0x6d, 0xd9, 0xaa, 0x3d, 0xb4, 0xf8, 0x61, 0xb8, 0x3f, + 0x6f, 0x2e, 0xb8, 0xe1, 0xfc, 0x38, 0xa4, 0xe2, 0x32, 0x57, 0xf3, 0x57, 0xb9, 0xa7, 0x51, 0xab, + 0x9f, 0xfa, 0x39, 0x56, 0xff, 0x6d, 0x28, 0x05, 0x97, 0x2a, 0xfa, 0xec, 0x7a, 0xde, 0x31, 0x2e, + 0xfd, 0x97, 0x00, 0xcb, 0x13, 0xb0, 0x08, 0x74, 0x9f, 0x97, 0x1b, 0xd8, 0x76, 0xdd, 0x1c, 0x9f, + 0x73, 0x80, 0xdd, 0xab, 0x3a, 0x90, 0x68, 0xe5, 0x25, 0xd5, 0x6c, 0x67, 0x3c, 0x02, 0x7a, 0x0d, + 0xca, 0x96, 0x76, 0x36, 0x50, 0x4c, 0x06, 0x6b, 0xb8, 0x50, 0x3e, 0xc9, 0x79, 0x49, 0x87, 0x53, + 0xf0, 0xea, 0xfc, 0xbb, 0x20, 0x6c, 0x21, 0x10, 0x95, 0x10, 0xb7, 0xd4, 0x06, 0x34, 0x9e, 0xe3, + 0x4f, 0x02, 0x5e, 0x84, 0x17, 0x00, 0x5e, 0xfe, 0x53, 0x80, 0x6b, 0x53, 0xf2, 0x7e, 0xf4, 0x61, + 0xc8, 0x9a, 0xdf, 0x5b, 0xe4, 0xd6, 0xb0, 0xc1, 0x68, 0x41, 0x7b, 0x96, 0xee, 0x41, 0xc1, 0x4f, + 0x9f, 0x6f, 0xf3, 0xfe, 0xcd, 0x17, 0x75, 0x83, 0x08, 0x51, 0x13, 0xd2, 0xf8, 0x1c, 0x0f, 0xdc, + 0x28, 0x7e, 0x79, 0x7c, 0x1d, 0x48, 0xf7, 0x56, 0x85, 0x64, 0x9b, 0xbf, 0x7f, 0xb6, 0x26, 0x32, + 0xee, 0xd7, 0xf5, 0xbe, 0x66, 0xe3, 0xbe, 0x61, 0x5f, 0xc8, 0x5c, 0x1e, 0xdd, 0x84, 0xa2, 0x89, + 0x6d, 0xe2, 0x84, 0x02, 0xe0, 0x5c, 0x81, 0x11, 0x79, 0x2e, 0xf8, 0x4b, 0x01, 0xc0, 0x83, 0x9c, + 0x3c, 0xc8, 0x47, 0xf0, 0x43, 0x3e, 0x21, 0xa4, 0x30, 0x1e, 0x46, 0x0a, 0xd1, 0x2d, 0x28, 0xb3, + 0x34, 0x9f, 0x6c, 0xba, 0x6a, 0x0f, 0x4d, 0xcc, 0x01, 0xa6, 0x12, 0x25, 0x1f, 0x3a, 0x54, 0xf4, + 0x09, 0x5c, 0xb5, 0xbb, 0x26, 0xb6, 0xba, 0x7a, 0xaf, 0xa3, 0x84, 0x37, 0x9e, 0x15, 0x3e, 0xd6, + 0x66, 0x58, 0xac, 0x7c, 0xc5, 0xd5, 0x70, 0x1c, 0xdc, 0xfc, 0x2f, 0x21, 0x45, 0xd7, 0x86, 0xa4, + 0x6a, 0xee, 0x11, 0xc8, 0x71, 0xeb, 0xfe, 0x14, 0x40, 0xb5, 0x6d, 0x53, 0x3b, 0x19, 0x12, 0x87, + 0x10, 0x1f, 0xff, 0x94, 0xb7, 0xb6, 0x35, 0x87, 0x6f, 0xeb, 0x3a, 0x5f, 0xe4, 0x15, 0x4f, 0xd4, + 0xb7, 0xd0, 0x3e, 0x85, 0xd2, 0x1e, 0x94, 0x82, 0xb2, 0x4e, 0x0e, 0xcc, 0xc6, 0x10, 0xcc, 0x81, + 0x59, 0x4e, 0xcd, 0x73, 0x60, 0x37, 0x83, 0x4e, 0xb0, 0xb2, 0x22, 0x6d, 0x48, 0x7f, 0x12, 0xa0, + 0xe0, 0x77, 0x74, 0x73, 0xa7, 0xa9, 0x3c, 0x6d, 0x4f, 0x8c, 0xa7, 0xed, 0xc9, 0xc8, 0xc4, 0x35, + 0x15, 0x4e, 0x5c, 0xaf, 0x42, 0x96, 0x74, 0x0f, 0x2d, 0xdc, 0xe1, 0xb5, 0xd8, 0xcc, 0x99, 0x6a, + 0x1d, 0x59, 0xb8, 0xe3, 0xb3, 0xcf, 0xcc, 0x0b, 0xda, 0x67, 0x20, 0x3b, 0xce, 0x86, 0x53, 0xf5, + 0xaf, 0x04, 0xc8, 0xba, 0x93, 0x0f, 0x96, 0x1c, 0x03, 0x08, 0x25, 0x5b, 0x3b, 0x56, 0x70, 0xe4, + 0xb7, 0x0f, 0x56, 0x80, 0x4d, 0xb8, 0x05, 0xd8, 0xf7, 0xdd, 0x7c, 0x2e, 0x0a, 0x83, 0xf3, 0xaf, + 0xb4, 0x03, 0xbb, 0xf2, 0xf4, 0xf5, 0x3f, 0xf8, 0x38, 0x48, 0x42, 0x82, 0xfe, 0x0e, 0xd2, 0x6a, + 0xdb, 0x45, 0x1e, 0x4b, 0x13, 0x20, 0x39, 0x87, 0x75, 0xa3, 0x35, 0xaa, 0x51, 0x4e, 0x99, 0x4b, + 0xf0, 0x51, 0xc5, 0x9d, 0x51, 0x49, 0xbb, 0x44, 0x2f, 0xe3, 0x09, 0xfa, 0x8c, 0x12, 0xc0, 0xd1, + 0xde, 0xe3, 0xfd, 0xed, 0x9d, 0x07, 0x3b, 0x8d, 0x6d, 0x9e, 0xb0, 0x6d, 0x6f, 0x37, 0xb6, 0xc5, + 0x38, 0xe1, 0x93, 0x1b, 0x8f, 0xf7, 0x8f, 0x1b, 0xdb, 0x62, 0x82, 0x34, 0xb6, 0x1b, 0xbb, 0xb5, + 0x8f, 0x1b, 0xdb, 0x62, 0x52, 0xaa, 0x41, 0xce, 0x0d, 0x3a, 0xb4, 0x52, 0xad, 0x3f, 0xc5, 0x26, + 0x5f, 0x2d, 0xd6, 0x40, 0xab, 0x90, 0x1f, 0x87, 0xce, 0xc9, 0xfd, 0x8b, 0x21, 0xe6, 0x24, 0xa0, + 0x94, 0x5d, 0x1d, 0x3c, 0xed, 0x78, 0x1f, 0x32, 0xc6, 0xf0, 0x44, 0x71, 0x0c, 0x39, 0x04, 0x38, + 0x3b, 0xd7, 0xb3, 0xe1, 0x49, 0x4f, 0x6b, 0x3f, 0xc2, 0x17, 0x3c, 0xc8, 0xa5, 0x8d, 0xe1, 0xc9, + 0x23, 0x66, 0xef, 0x6c, 0x18, 0xf1, 0x29, 0xc3, 0x48, 0x84, 0x86, 0x81, 0x6e, 0x41, 0x61, 0xa0, + 0x77, 0xb0, 0xa2, 0x76, 0x3a, 0x26, 0xb6, 0x58, 0xec, 0xce, 0x71, 0xcd, 0x79, 0xd2, 0x53, 0x63, + 0x1d, 0xd2, 0x0f, 0x02, 0xa0, 0xf1, 0x40, 0x8b, 0x0e, 0x61, 0xc9, 0x8b, 0xd5, 0x4e, 0x02, 0xc0, + 0x7c, 0xe9, 0x7a, 0x74, 0xa0, 0x0e, 0xdc, 0xe1, 0xc5, 0xf3, 0x20, 0x99, 0x24, 0x75, 0x2b, 0x9e, + 0xdf, 0x32, 0xe8, 0x7c, 0xe9, 0xa2, 0xc4, 0xe7, 0x5c, 0x94, 0x98, 0x8c, 0x5c, 0x79, 0xb7, 0x27, + 0xec, 0x57, 0x13, 0x63, 0x15, 0x18, 0x03, 0x2a, 0xad, 0x31, 0x31, 0x3e, 0xcf, 0xa8, 0x21, 0x09, + 0x2f, 0x32, 0x24, 0xe9, 0x1e, 0x88, 0x1f, 0xba, 0xdf, 0xe7, 0x5f, 0x0a, 0x0d, 0x53, 0x18, 0x1b, + 0xe6, 0x39, 0x64, 0x89, 0x2b, 0xa6, 0x11, 0xe4, 0x1f, 0x20, 0xe7, 0xae, 0x9e, 0xfb, 0xd8, 0x25, + 0x72, 0xd9, 0xf9, 0x48, 0x3c, 0x11, 0x74, 0x07, 0x96, 0x48, 0x10, 0x71, 0xea, 0xa0, 0x0c, 0x85, + 0x8b, 0x53, 0xd7, 0x58, 0x66, 0x1d, 0xbb, 0x0e, 0x74, 0x44, 0xa2, 0xbd, 0xc8, 0xb2, 0x02, 0xdc, + 0xf9, 0x4b, 0x0c, 0x80, 0x5c, 0xdb, 0x42, 0x60, 0x24, 0xdb, 0xc3, 0x62, 0x20, 0x2d, 0x91, 0xfe, + 0x25, 0x0e, 0x79, 0x5f, 0x5d, 0x06, 0xfd, 0x6d, 0x20, 0x45, 0x5b, 0x9f, 0x56, 0xc3, 0xf1, 0xe5, + 0x67, 0x81, 0x89, 0xc5, 0x17, 0x9f, 0x58, 0x54, 0x45, 0xcc, 0x29, 0xcf, 0x26, 0x17, 0x2e, 0xcf, + 0xbe, 0x0e, 0xc8, 0xd6, 0x6d, 0xb5, 0x47, 0x22, 0xb9, 0x36, 0x38, 0x53, 0xd8, 0x69, 0x67, 0xd1, + 0x44, 0xa4, 0x3d, 0xc7, 0xb4, 0xe3, 0x80, 0xd0, 0xa5, 0x1e, 0x64, 0x5d, 0x6c, 0x61, 0xf1, 0x37, + 0x24, 0x93, 0xca, 0xd0, 0x55, 0xc8, 0xf6, 0xb1, 0xad, 0xd2, 0x18, 0xc8, 0xb0, 0x26, 0xb7, 0x7d, + 0xe7, 0x3d, 0xc8, 0xfb, 0x1e, 0xd6, 0x90, 0xb0, 0xb8, 0xd7, 0xf8, 0x48, 0x8c, 0x55, 0x33, 0x5f, + 0x7f, 0xbb, 0x9e, 0xd8, 0xc3, 0x4f, 0xc9, 0xa7, 0xe4, 0x46, 0xbd, 0xd9, 0xa8, 0x3f, 0x12, 0x85, + 0x6a, 0xfe, 0xeb, 0x6f, 0xd7, 0x33, 0x32, 0xa6, 0x25, 0x8c, 0x3b, 0x8f, 0xa0, 0x1c, 0xda, 0x81, + 0xa0, 0x83, 0x46, 0x50, 0xda, 0x3e, 0x3a, 0xd8, 0xdd, 0xa9, 0xd7, 0x5a, 0x0d, 0xe5, 0x78, 0xbf, + 0xd5, 0x10, 0x05, 0x74, 0x05, 0x96, 0x77, 0x77, 0xfe, 0xb1, 0xd9, 0x52, 0xea, 0xbb, 0x3b, 0x8d, + 0xbd, 0x96, 0x52, 0x6b, 0xb5, 0x6a, 0xf5, 0x47, 0x62, 0xfc, 0xee, 0x6f, 0x00, 0xca, 0xb5, 0xad, + 0xfa, 0x4e, 0xcd, 0x30, 0x7a, 0x5a, 0x5b, 0xa5, 0xee, 0xbe, 0x0e, 0x49, 0x8a, 0xec, 0x4e, 0x7d, + 0x62, 0x5b, 0x9d, 0x5e, 0x97, 0x42, 0x0f, 0x20, 0x45, 0x41, 0x5f, 0x34, 0xfd, 0xcd, 0x6d, 0x75, + 0x46, 0xa1, 0x8a, 0x0c, 0x86, 0x9e, 0x9b, 0xa9, 0x8f, 0x70, 0xab, 0xd3, 0xeb, 0x56, 0x68, 0x17, + 0x32, 0x0e, 0x9e, 0x36, 0xeb, 0x65, 0x6c, 0x75, 0x66, 0x31, 0x89, 0x4c, 0x8d, 0xe1, 0x92, 0xd3, + 0xdf, 0xe7, 0x56, 0x67, 0x54, 0xb4, 0x90, 0x0c, 0x39, 0x0f, 0x4a, 0x9e, 0xfd, 0x54, 0xb8, 0x3a, + 0x47, 0x85, 0x0d, 0x7d, 0x06, 0xc5, 0x20, 0xf2, 0x36, 0xdf, 0x2b, 0xde, 0xea, 0x9c, 0xd5, 0x2f, + 0xa2, 0x3f, 0x08, 0xc3, 0xcd, 0xf7, 0xaa, 0xb7, 0x3a, 0x67, 0x31, 0x0c, 0x7d, 0x0e, 0x4b, 0xe3, + 0x30, 0xd9, 0xfc, 0x8f, 0x7c, 0xab, 0x0b, 0x94, 0xc7, 0x50, 0x1f, 0xd0, 0x04, 0x78, 0x6d, 0x81, + 0x37, 0xbf, 0xd5, 0x45, 0xaa, 0x65, 0xa8, 0x03, 0xe5, 0x30, 0xf4, 0x34, 0xef, 0x1b, 0xe0, 0xea, + 0xdc, 0x95, 0x33, 0xf6, 0x95, 0x20, 0x46, 0x32, 0xef, 0x9b, 0xe0, 0xea, 0xdc, 0x85, 0x34, 0x74, + 0x04, 0xe0, 0xbb, 0x25, 0xcf, 0xf1, 0x46, 0xb8, 0x3a, 0x4f, 0x49, 0x0d, 0x19, 0xb0, 0x3c, 0xe9, + 0x5a, 0xbc, 0xc8, 0x93, 0xe1, 0xea, 0x42, 0x95, 0x36, 0x62, 0xcf, 0xc1, 0x0b, 0xee, 0x7c, 0x4f, + 0x88, 0xab, 0x73, 0x96, 0xdc, 0xb6, 0xb6, 0xbe, 0x7b, 0xbe, 0x2a, 0x7c, 0xff, 0x7c, 0x55, 0xf8, + 0xe1, 0xf9, 0xaa, 0xf0, 0xcd, 0x8f, 0xab, 0xb1, 0xef, 0x7f, 0x5c, 0x8d, 0xfd, 0xfa, 0xc7, 0xd5, + 0xd8, 0x3f, 0xdd, 0x3e, 0xd3, 0xec, 0xee, 0xf0, 0x64, 0xa3, 0xad, 0xf7, 0xe9, 0x3f, 0x38, 0x0c, + 0xf5, 0x62, 0x93, 0xe9, 0x24, 0x2d, 0xdf, 0xff, 0x44, 0x4e, 0xd2, 0x34, 0xd6, 0xdd, 0xfb, 0x73, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x2a, 0x14, 0xac, 0xb9, 0x47, 0x32, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -6221,15 +6221,6 @@ func (m *RequestVerifyVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, err _ = i var l int _ = l - if m.XSignRequestId != nil { - { - size := m.XSignRequestId.Size() - i -= size - if _, err := m.XSignRequestId.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - } - } if len(m.VoteExtensions) > 0 { for iNdEx := len(m.VoteExtensions) - 1; iNdEx >= 0; iNdEx-- { { @@ -6271,22 +6262,6 @@ func (m *RequestVerifyVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, err return len(dAtA) - i, nil } -func (m *RequestVerifyVoteExtension_SignRequestId) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *RequestVerifyVoteExtension_SignRequestId) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.SignRequestId != nil { - i -= len(m.SignRequestId) - copy(dAtA[i:], m.SignRequestId) - i = encodeVarintTypes(dAtA, i, uint64(len(m.SignRequestId))) - i-- - dAtA[i] = 0x32 - } - return len(dAtA) - i, nil -} func (m *RequestFinalizeBlock) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -7439,6 +7414,15 @@ func (m *ExtendVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.XSignRequestId != nil { + { + size := m.XSignRequestId.Size() + i -= size + if _, err := m.XSignRequestId.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } if len(m.Extension) > 0 { i -= len(m.Extension) copy(dAtA[i:], m.Extension) @@ -7454,6 +7438,22 @@ func (m *ExtendVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ExtendVoteExtension_SignRequestId) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExtendVoteExtension_SignRequestId) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.SignRequestId != nil { + i -= len(m.SignRequestId) + copy(dAtA[i:], m.SignRequestId) + i = encodeVarintTypes(dAtA, i, uint64(len(m.SignRequestId))) + i-- + dAtA[i] = 0x1a + } + return len(dAtA) - i, nil +} func (m *ResponseExtendVote) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -8823,24 +8823,9 @@ func (m *RequestVerifyVoteExtension) Size() (n int) { n += 1 + l + sovTypes(uint64(l)) } } - if m.XSignRequestId != nil { - n += m.XSignRequestId.Size() - } return n } -func (m *RequestVerifyVoteExtension_SignRequestId) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.SignRequestId != nil { - l = len(m.SignRequestId) - n += 1 + l + sovTypes(uint64(l)) - } - return n -} func (m *RequestFinalizeBlock) Size() (n int) { if m == nil { return 0 @@ -9394,9 +9379,24 @@ func (m *ExtendVoteExtension) Size() (n int) { if l > 0 { n += 1 + l + sovTypes(uint64(l)) } + if m.XSignRequestId != nil { + n += m.XSignRequestId.Size() + } return n } +func (m *ExtendVoteExtension_SignRequestId) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SignRequestId != nil { + l = len(m.SignRequestId) + n += 1 + l + sovTypes(uint64(l)) + } + return n +} func (m *ResponseExtendVote) Size() (n int) { if m == nil { return 0 @@ -12742,39 +12742,6 @@ func (m *RequestVerifyVoteExtension) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SignRequestId", 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 - } - v := make([]byte, postIndex-iNdEx) - copy(v, dAtA[iNdEx:postIndex]) - m.XSignRequestId = &RequestVerifyVoteExtension_SignRequestId{v} - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -15772,6 +15739,39 @@ func (m *ExtendVoteExtension) Unmarshal(dAtA []byte) error { m.Extension = []byte{} } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SignRequestId", 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 + } + v := make([]byte, postIndex-iNdEx) + copy(v, dAtA[iNdEx:postIndex]) + m.XSignRequestId = &ExtendVoteExtension_SignRequestId{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) diff --git a/internal/consensus/vote_signer.go b/internal/consensus/vote_signer.go index 62ef6cee30..3f1e145a04 100644 --- a/internal/consensus/vote_signer.go +++ b/internal/consensus/vote_signer.go @@ -103,10 +103,8 @@ func (s *voteSigner) signVote( if err != nil { return nil, err } - err = vote.PopulateSignsFromProto(protoVote) - if err != nil { - return nil, err - } + // Deep copy vote extensions + vote.VoteExtensions = types.VoteExtensionsFromProto(protoVote.VoteExtensions) return vote, nil } diff --git a/internal/test/factory/commit.go b/internal/test/factory/commit.go index 80c52ea7e8..f1fb42b140 100644 --- a/internal/test/factory/commit.go +++ b/internal/test/factory/commit.go @@ -38,10 +38,7 @@ func MakeCommit( return nil, err } vote.BlockSignature = v.BlockSignature - err = vote.VoteExtensions.CopySignsFromProto(v.VoteExtensionsToMap()) - if err != nil { - return nil, err - } + vote.VoteExtensions = types.VoteExtensionsFromProto(v.VoteExtensions) if _, err := voteSet.AddVote(vote); err != nil { return nil, err } diff --git a/internal/test/factory/vote.go b/internal/test/factory/vote.go index 40c0a33c40..1cbd15e3dd 100644 --- a/internal/test/factory/vote.go +++ b/internal/test/factory/vote.go @@ -39,9 +39,7 @@ func MakeVote( } v.BlockSignature = vpb.BlockSignature - err = v.VoteExtensions.CopySignsFromProto(vpb.VoteExtensionsToMap()) - if err != nil { - return nil, err - } + v.VoteExtensions = types.VoteExtensionsFromProto(vpb.VoteExtensions) + return v, nil } diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 253779ed7a..392eee3d40 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -450,16 +450,6 @@ message RequestVerifyVoteExtension { int32 round = 4; // // Round number for the block. // Application-specific information signed by Tenderdash. Can have 0 length. repeated ExtendVoteExtension vote_extensions = 5; - // Sign request ID that will be used to sign the vote extensions. - // Tenderdash will use checksum of `sign_request_id` when generating quorum signatures of - // THRESHOLD_RECOVER vote extensions. - - // If not set, Tenderdash will generate it based on height and round. - // - // If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` string. - // - // Use with caution - it can have severe security consequences. - optional bytes sign_request_id = 6; } // Finalize newly decided block. @@ -670,13 +660,23 @@ message ResponseProcessProposal { ValidatorSetUpdate validator_set_update = 5 [(gogoproto.nullable) = true]; } -// Provides a vote extension for signing. Each field is mandatory for filling +// Provides a vote extension for signing. `type` and `extension` fields are mandatory for filling message ExtendVoteExtension { // Vote extension type can be either DEFAULT or THRESHOLD_RECOVER. // The Tenderdash supports only THRESHOLD_RECOVER at this moment. tendermint.types.VoteExtensionType type = 1; // Deterministic or (Non-Deterministic) extension provided by the sending validator's Application. bytes extension = 2; + // Sign request ID that will be used to sign the vote extensions. + // Tenderdash will use checksum of `sign_request_id` when generating quorum signatures of + // THRESHOLD_RECOVER vote extensions. + + // If not set, Tenderdash will generate it based on height and round. + // + // If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` string. + // + // Use with caution - it can have severe security consequences. + optional bytes sign_request_id = 3; } message ResponseExtendVote { diff --git a/proto/tendermint/types/dash.go b/proto/tendermint/types/dash.go index 46e0f7f41b..fa0914f0a5 100644 --- a/proto/tendermint/types/dash.go +++ b/proto/tendermint/types/dash.go @@ -1,4 +1,61 @@ package types +import ( + "errors" + fmt "fmt" + "strings" + + "github.com/dashpay/tenderdash/crypto/bls12381" +) + // VoteExtensions is a container type for grouped vote extensions by type type VoteExtensions map[VoteExtensionType][]*VoteExtension + +var ( + errExtensionSignEmpty = errors.New("vote extension signature is missing") + errExtensionSignTooBig = fmt.Errorf("vote extension signature is too big (max: %d)", bls12381.SignatureSize) + errExtensionSignRequestIdNotSupported = errors.New("vote extension sign request id is not supported") + errExtensionSignRequestIdMissingPrefix = errors.New("vote extension sign request id must have dpevote prefix") +) + +// Clone returns a copy of current vote-extension +func (v *VoteExtension) Clone() VoteExtension { + var xSignRequestID *VoteExtension_SignRequestId + + if v.XSignRequestId != nil { + src := v.GetSignRequestId() + dst := make([]byte, len(src)) + copy(dst, src) + xSignRequestID = &VoteExtension_SignRequestId{ + SignRequestId: dst, + } + } + + return VoteExtension{ + Extension: v.Extension, + Signature: v.Signature, + XSignRequestId: xSignRequestID, + } +} + +// Validate checks the validity of the vote-extension +func (v *VoteExtension) Validate() error { + if len(v.Extension) > 0 && len(v.Signature) == 0 { + return errExtensionSignEmpty + } + if len(v.Signature) > bls12381.SignatureSize { + return errExtensionSignTooBig + } + + if v.XSignRequestId != nil { + if v.Type != VoteExtensionType_THRESHOLD_RECOVER_RAW { + return errExtensionSignRequestIdNotSupported + } + requestID := v.GetSignRequestId() + if !strings.HasPrefix(string(requestID), "dpevote") { + return errExtensionSignRequestIdMissingPrefix + } + } + + return nil +} diff --git a/proto/tendermint/types/dash.pb.go b/proto/tendermint/types/dash.pb.go index 661526d33a..58f85b9cd0 100644 --- a/proto/tendermint/types/dash.pb.go +++ b/proto/tendermint/types/dash.pb.go @@ -29,18 +29,25 @@ type VoteExtensionType int32 const ( // Unsupported VoteExtensionType_DEFAULT VoteExtensionType = 0 + // Sign canonical form of vote extension and threshold-recover signatures. + // // Deterministic vote extension - each validator in a quorum must provide the same vote extension data. VoteExtensionType_THRESHOLD_RECOVER VoteExtensionType = 1 + // Use with caution - it can have severe security consequences, like replay attacks. + // + VoteExtensionType_THRESHOLD_RECOVER_RAW VoteExtensionType = 2 ) var VoteExtensionType_name = map[int32]string{ 0: "DEFAULT", 1: "THRESHOLD_RECOVER", + 2: "THRESHOLD_RECOVER_RAW", } var VoteExtensionType_value = map[string]int32{ - "DEFAULT": 0, - "THRESHOLD_RECOVER": 1, + "DEFAULT": 0, + "THRESHOLD_RECOVER": 1, + "THRESHOLD_RECOVER_RAW": 2, } func (x VoteExtensionType) String() string { @@ -116,6 +123,9 @@ type VoteExtension struct { Type VoteExtensionType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.types.VoteExtensionType" json:"type,omitempty"` Extension []byte `protobuf:"bytes,2,opt,name=extension,proto3" json:"extension,omitempty"` Signature []byte `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"` + // Types that are valid to be assigned to XSignRequestId: + // *VoteExtension_SignRequestId + XSignRequestId isVoteExtension_XSignRequestId `protobuf_oneof:"_sign_request_id"` } func (m *VoteExtension) Reset() { *m = VoteExtension{} } @@ -151,6 +161,25 @@ func (m *VoteExtension) XXX_DiscardUnknown() { var xxx_messageInfo_VoteExtension proto.InternalMessageInfo +type isVoteExtension_XSignRequestId interface { + isVoteExtension_XSignRequestId() + MarshalTo([]byte) (int, error) + Size() int +} + +type VoteExtension_SignRequestId struct { + SignRequestId []byte `protobuf:"bytes,4,opt,name=sign_request_id,json=signRequestId,proto3,oneof" json:"sign_request_id,omitempty"` +} + +func (*VoteExtension_SignRequestId) isVoteExtension_XSignRequestId() {} + +func (m *VoteExtension) GetXSignRequestId() isVoteExtension_XSignRequestId { + if m != nil { + return m.XSignRequestId + } + return nil +} + func (m *VoteExtension) GetType() VoteExtensionType { if m != nil { return m.Type @@ -172,6 +201,20 @@ func (m *VoteExtension) GetSignature() []byte { return nil } +func (m *VoteExtension) GetSignRequestId() []byte { + if x, ok := m.GetXSignRequestId().(*VoteExtension_SignRequestId); ok { + return x.SignRequestId + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*VoteExtension) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*VoteExtension_SignRequestId)(nil), + } +} + func init() { proto.RegisterEnum("tendermint.types.VoteExtensionType", VoteExtensionType_name, VoteExtensionType_value) proto.RegisterType((*CoreChainLock)(nil), "tendermint.types.CoreChainLock") @@ -181,28 +224,31 @@ func init() { func init() { proto.RegisterFile("tendermint/types/dash.proto", fileDescriptor_098b09a14a95d15e) } var fileDescriptor_098b09a14a95d15e = []byte{ - // 332 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2e, 0x49, 0xcd, 0x4b, - 0x49, 0x2d, 0xca, 0xcd, 0xcc, 0x2b, 0xd1, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, 0x4f, 0x49, 0x2c, - 0xce, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x40, 0x48, 0xea, 0x81, 0x25, 0xa5, 0x44, - 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x92, 0xfa, 0x20, 0x16, 0x44, 0x9d, 0x52, 0x3b, 0x23, 0x17, 0xaf, - 0x73, 0x7e, 0x51, 0xaa, 0x73, 0x46, 0x62, 0x66, 0x9e, 0x4f, 0x7e, 0x72, 0xb6, 0x90, 0x16, 0x97, - 0x60, 0x72, 0x7e, 0x51, 0x6a, 0x7c, 0x52, 0x4e, 0x7e, 0x72, 0x76, 0x7c, 0x46, 0x6a, 0x66, 0x7a, - 0x46, 0x89, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x6f, 0x10, 0x3f, 0x48, 0xc2, 0x09, 0x24, 0xee, 0x01, - 0x16, 0x16, 0x52, 0xe3, 0xe2, 0x47, 0x56, 0x9b, 0x58, 0x9c, 0x21, 0xc1, 0xa4, 0xc0, 0xa8, 0xc1, - 0x13, 0xc4, 0x8b, 0x50, 0x99, 0x58, 0x9c, 0x21, 0x24, 0xc3, 0xc5, 0x59, 0x9c, 0x99, 0x9e, 0x97, - 0x58, 0x52, 0x5a, 0x94, 0x2a, 0xc1, 0x0c, 0x56, 0x81, 0x10, 0xb0, 0x62, 0x79, 0xb1, 0x40, 0x9e, - 0x51, 0xa9, 0x85, 0x91, 0x8b, 0x37, 0x2c, 0xbf, 0x24, 0xd5, 0xb5, 0xa2, 0x24, 0x35, 0xaf, 0x38, - 0x33, 0x3f, 0x4f, 0xc8, 0x9c, 0x8b, 0x05, 0xe4, 0x74, 0xb0, 0xe5, 0x7c, 0x46, 0xca, 0x7a, 0xe8, - 0x5e, 0xd2, 0x43, 0x51, 0x1e, 0x52, 0x59, 0x90, 0x1a, 0x04, 0xd6, 0x00, 0xb2, 0x2e, 0x15, 0x26, - 0x0c, 0x75, 0x10, 0x42, 0x00, 0xbf, 0x63, 0xb4, 0xcc, 0xb9, 0x04, 0x31, 0x8c, 0x15, 0xe2, 0xe6, - 0x62, 0x77, 0x71, 0x75, 0x73, 0x0c, 0xf5, 0x09, 0x11, 0x60, 0x10, 0x12, 0xe5, 0x12, 0x0c, 0xf1, - 0x08, 0x72, 0x0d, 0xf6, 0xf0, 0xf7, 0x71, 0x89, 0x0f, 0x72, 0x75, 0xf6, 0x0f, 0x73, 0x0d, 0x12, - 0x60, 0x74, 0xf2, 0x3b, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, - 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0x93, 0xf4, - 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0x70, 0x14, 0x15, 0x24, 0x56, 0xea, 0x43, - 0xfc, 0x02, 0xe2, 0xe9, 0x43, 0xe2, 0x04, 0x3d, 0x32, 0x93, 0xd8, 0xc0, 0xe2, 0xc6, 0x80, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x57, 0xe9, 0x12, 0xcd, 0xe7, 0x01, 0x00, 0x00, + // 384 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0xcf, 0x4a, 0xe3, 0x40, + 0x1c, 0xc7, 0x33, 0xdd, 0xb2, 0xcb, 0xce, 0x6e, 0xb6, 0xe9, 0xb0, 0x85, 0xf8, 0x87, 0x58, 0x2a, + 0x48, 0xa9, 0x90, 0x80, 0x0a, 0x82, 0xb7, 0xfe, 0x89, 0x44, 0x28, 0x16, 0xc6, 0x5a, 0xc1, 0x4b, + 0x48, 0x93, 0x21, 0x09, 0xb5, 0x99, 0x98, 0x4c, 0xc1, 0x3e, 0x81, 0x1e, 0x7d, 0x04, 0x5f, 0x46, + 0xf0, 0xd8, 0xa3, 0x47, 0x69, 0x2f, 0x3e, 0x86, 0xcc, 0x44, 0x89, 0xb6, 0xe0, 0x2d, 0xf3, 0xf9, + 0x7e, 0xc2, 0xef, 0x9b, 0xfc, 0x06, 0x6e, 0x30, 0x12, 0x79, 0x24, 0x19, 0x87, 0x11, 0x33, 0xd8, + 0x34, 0x26, 0xa9, 0xe1, 0x39, 0x69, 0xa0, 0xc7, 0x09, 0x65, 0x14, 0x29, 0x79, 0xa8, 0x8b, 0x70, + 0xfd, 0xbf, 0x4f, 0x7d, 0x2a, 0x42, 0x83, 0x3f, 0x65, 0x5e, 0xed, 0x16, 0x40, 0xb9, 0x4d, 0x13, + 0xd2, 0x0e, 0x9c, 0x30, 0xea, 0x52, 0x77, 0x84, 0x1a, 0xb0, 0xec, 0xd2, 0x84, 0xd8, 0xc3, 0x2b, + 0xea, 0x8e, 0xec, 0x80, 0x84, 0x7e, 0xc0, 0x54, 0x50, 0x05, 0x75, 0x19, 0x97, 0x78, 0xd0, 0xe2, + 0xdc, 0x12, 0x18, 0xed, 0xc0, 0xd2, 0x67, 0xd7, 0x49, 0x03, 0xb5, 0x50, 0x05, 0xf5, 0xbf, 0x58, + 0xce, 0x4d, 0x27, 0x0d, 0xd0, 0x26, 0xfc, 0x9d, 0x86, 0x7e, 0xe4, 0xb0, 0x49, 0x42, 0xd4, 0x1f, + 0xc2, 0xc8, 0xc1, 0x51, 0xf1, 0xf5, 0x61, 0x0b, 0xd4, 0x1e, 0x01, 0x94, 0x07, 0x94, 0x11, 0xf3, + 0x86, 0x91, 0x28, 0x0d, 0x69, 0x84, 0x0e, 0x61, 0x91, 0x57, 0x17, 0xc3, 0xff, 0xed, 0x6d, 0xeb, + 0xcb, 0x9f, 0xa4, 0x7f, 0xd1, 0xfb, 0xd3, 0x98, 0x60, 0xf1, 0x02, 0x1f, 0x47, 0x3e, 0xf0, 0x7b, + 0xa1, 0x1c, 0x7c, 0x5f, 0x06, 0xed, 0xc2, 0x12, 0x3f, 0xd8, 0x09, 0xb9, 0x9e, 0x90, 0x94, 0xd9, + 0xa1, 0xa7, 0x16, 0xb9, 0x63, 0x49, 0x58, 0xe6, 0x01, 0xce, 0xf8, 0x89, 0x77, 0x07, 0x40, 0x0b, + 0x41, 0xc5, 0x5e, 0xb2, 0x1b, 0x18, 0x96, 0x57, 0x7a, 0xa1, 0x3f, 0xf0, 0x57, 0xc7, 0x3c, 0x6e, + 0x9e, 0x77, 0xfb, 0x8a, 0x84, 0x2a, 0xb0, 0xdc, 0xb7, 0xb0, 0x79, 0x66, 0xf5, 0xba, 0x1d, 0x1b, + 0x9b, 0xed, 0xde, 0xc0, 0xc4, 0x0a, 0x40, 0x6b, 0xb0, 0xb2, 0x82, 0x6d, 0xdc, 0xbc, 0x50, 0x0a, + 0xad, 0xd3, 0xa7, 0xb9, 0x06, 0x66, 0x73, 0x0d, 0xbc, 0xcc, 0x35, 0x70, 0xbf, 0xd0, 0xa4, 0xd9, + 0x42, 0x93, 0x9e, 0x17, 0x9a, 0x74, 0x79, 0xe0, 0x87, 0x2c, 0x98, 0x0c, 0x75, 0x97, 0x8e, 0xc5, + 0xfa, 0x63, 0x67, 0x6a, 0x64, 0xff, 0x89, 0x9f, 0x8c, 0x6c, 0xdf, 0xcb, 0x17, 0x65, 0xf8, 0x53, + 0xf0, 0xfd, 0xb7, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1b, 0x70, 0x1d, 0xe4, 0x43, 0x02, 0x00, 0x00, } func (this *CoreChainLock) Equal(that interface{}) bool { @@ -297,6 +343,15 @@ func (m *VoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.XSignRequestId != nil { + { + size := m.XSignRequestId.Size() + i -= size + if _, err := m.XSignRequestId.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } if len(m.Signature) > 0 { i -= len(m.Signature) copy(dAtA[i:], m.Signature) @@ -319,6 +374,22 @@ func (m *VoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *VoteExtension_SignRequestId) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *VoteExtension_SignRequestId) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.SignRequestId != nil { + i -= len(m.SignRequestId) + copy(dAtA[i:], m.SignRequestId) + i = encodeVarintDash(dAtA, i, uint64(len(m.SignRequestId))) + i-- + dAtA[i] = 0x22 + } + return len(dAtA) - i, nil +} func encodeVarintDash(dAtA []byte, offset int, v uint64) int { offset -= sovDash(v) base := offset @@ -367,6 +438,22 @@ func (m *VoteExtension) Size() (n int) { if l > 0 { n += 1 + l + sovDash(uint64(l)) } + if m.XSignRequestId != nil { + n += m.XSignRequestId.Size() + } + return n +} + +func (m *VoteExtension_SignRequestId) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SignRequestId != nil { + l = len(m.SignRequestId) + n += 1 + l + sovDash(uint64(l)) + } return n } @@ -629,6 +716,39 @@ func (m *VoteExtension) Unmarshal(dAtA []byte) error { m.Signature = []byte{} } iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SignRequestId", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDash + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthDash + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthDash + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := make([]byte, postIndex-iNdEx) + copy(v, dAtA[iNdEx:postIndex]) + m.XSignRequestId = &VoteExtension_SignRequestId{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipDash(dAtA[iNdEx:]) diff --git a/proto/tendermint/types/dash.proto b/proto/tendermint/types/dash.proto index 237c3ed768..d93cec5954 100644 --- a/proto/tendermint/types/dash.proto +++ b/proto/tendermint/types/dash.proto @@ -16,12 +16,31 @@ message CoreChainLock { enum VoteExtensionType { // Unsupported DEFAULT = 0; + // Sign canonical form of vote extension and threshold-recover signatures. + // // Deterministic vote extension - each validator in a quorum must provide the same vote extension data. THRESHOLD_RECOVER = 1; + // Sign raw form of vote extension and threshold-recover signatures. + // + // Deterministic vote extension - each validator in a quorum must provide the same vote extension data. + + // Use with caution - it can have severe security consequences, like replay attacks. + // + THRESHOLD_RECOVER_RAW = 2; } message VoteExtension { VoteExtensionType type = 1; bytes extension = 2; bytes signature = 3; + // Sign request ID that will be used to sign the vote extensions. + // Tenderdash will use checksum of `sign_request_id` when generating quorum signatures of + // THRESHOLD_RECOVER vote extensions. + + // If not set, Tenderdash will generate it based on height and round. + // + // If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` string. + // + // Use with caution - it can have severe security consequences. + optional bytes sign_request_id = 4; } diff --git a/spec/abci++/api.md b/spec/abci++/api.md index ec037e2c1c..7c187b1861 100644 --- a/spec/abci++/api.md +++ b/spec/abci++/api.md @@ -155,13 +155,20 @@ ExecTxResult contains results of executing one individual transaction. ### ExtendVoteExtension -Provides a vote extension for signing. Each field is mandatory for filling +Provides a vote extension for signing. `type` and `extension` fields are mandatory for filling | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | type | [tendermint.types.VoteExtensionType](#tendermint-types-VoteExtensionType) | | Vote extension type can be either DEFAULT or THRESHOLD_RECOVER. The Tenderdash supports only THRESHOLD_RECOVER at this moment. | -| extension | [bytes](#bytes) | | Deterministic or (Non-Deterministic) extension provided by the sending validator's Application. | +| extension | [bytes](#bytes) | | Deterministic or (Non-Deterministic) extension provided by the sending validator's Application. + +Sign request ID that will be used to sign the vote extensions. Tenderdash will use checksum of `sign_request_id` when generating quorum signatures of THRESHOLD_RECOVER vote extensions. | +| sign_request_id | [bytes](#bytes) | optional | If not set, Tenderdash will generate it based on height and round. + +If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` string. + +Use with caution - it can have severe security consequences. | @@ -773,14 +780,7 @@ from this condition, but not sure), and _p_ receives a Precommit message for rou | validator_pro_tx_hash | [bytes](#bytes) | | ProTxHash of the validator that signed the extensions. | | height | [int64](#int64) | | Height of the block (for sanity check). | | round | [int32](#int32) | | Round number for the block. | -| vote_extensions | [ExtendVoteExtension](#tendermint-abci-ExtendVoteExtension) | repeated | Application-specific information signed by Tenderdash. Can have 0 length. - -Sign request ID that will be used to sign the vote extensions. Tenderdash will use checksum of `sign_request_id` when generating quorum signatures of THRESHOLD_RECOVER vote extensions. | -| sign_request_id | [bytes](#bytes) | optional | If not set, Tenderdash will generate it based on height and round. - -If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` string. - -Use with caution - it can have severe security consequences. | +| vote_extensions | [ExtendVoteExtension](#tendermint-abci-ExtendVoteExtension) | repeated | Application-specific information signed by Tenderdash. Can have 0 length. | diff --git a/types/canonical.go b/types/canonical.go index e4c5d74f51..d931b5e419 100644 --- a/types/canonical.go +++ b/types/canonical.go @@ -1,8 +1,10 @@ package types import ( + "errors" "time" + "github.com/dashpay/tenderdash/internal/libs/protoio" tmtime "github.com/dashpay/tenderdash/libs/time" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" ) @@ -31,14 +33,23 @@ func CanonicalizeProposal(chainID string, proposal *tmproto.Proposal) tmproto.Ca // CanonicalizeVoteExtension extracts the vote extension from the given vote // and constructs a CanonicalizeVoteExtension struct, whose representation in // bytes is what is signed in order to produce the vote extension's signature. -func CanonicalizeVoteExtension(chainID string, ext *tmproto.VoteExtension, height int64, round int32) tmproto.CanonicalVoteExtension { - return tmproto.CanonicalVoteExtension{ - Extension: ext.Extension, - Type: ext.Type, - Height: height, - Round: int64(round), - ChainId: chainID, +func CanonicalizeVoteExtension(chainID string, ext *tmproto.VoteExtension, height int64, round int32) ([]byte, error) { + switch ext.Type { + case tmproto.VoteExtensionType_THRESHOLD_RECOVER: + { + canonical := tmproto.CanonicalVoteExtension{ + Extension: ext.Extension, + Type: ext.Type, + Height: height, + Round: int64(round), + ChainId: chainID, + } + return protoio.MarshalDelimited(&canonical) + } + case tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW: + return ext.Extension, nil } + return nil, errors.New("provided vote extension type does not have canonical form for signing") } // CanonicalTime can be used to stringify time in a canonical way. diff --git a/types/quorum.go b/types/quorum.go index 5e0a5c7e67..86d05db8e6 100644 --- a/types/quorum.go +++ b/types/quorum.go @@ -94,7 +94,7 @@ func ThresholdExtensionSignToProto(extensions []ThresholdExtensionSign) []*tmpro // MakeThresholdVoteExtensions creates a list of ThresholdExtensionSign from the list of VoteExtension // and recovered threshold signatures. The lengths of vote-extensions and threshold signatures must be the same -func MakeThresholdVoteExtensions(extensions []VoteExtension, thresholdSigs [][]byte) []ThresholdExtensionSign { +func MakeThresholdVoteExtensions(extensions []tmproto.VoteExtension, thresholdSigs [][]byte) []ThresholdExtensionSign { thresholdExtensions := make([]ThresholdExtensionSign, len(extensions)) for i, ext := range extensions { thresholdExtensions[i] = ThresholdExtensionSign{ diff --git a/types/quorum_sign_data.go b/types/quorum_sign_data.go index 9607131d6e..e15ff0c2c9 100644 --- a/types/quorum_sign_data.go +++ b/types/quorum_sign_data.go @@ -109,13 +109,17 @@ func MakeVoteExtensionSignItems( return nil, nil } items := make(map[types.VoteExtensionType][]SignItem) - reqID := VoteExtensionRequestID(protoVote.Height, protoVote.Round) protoExtensionsMap := protoVote.VoteExtensionsToMap() for t, exts := range protoExtensionsMap { if items[t] == nil && len(exts) > 0 { items[t] = make([]SignItem, len(exts)) } + if t == types.VoteExtensionType_DEFAULT { + // DEFAULT vote extensions don't support signing + continue + } for i, ext := range exts { + reqID := VoteExtensionRequestID(ext, protoVote.Height, protoVote.Round) raw := VoteExtensionSignBytes(chainID, protoVote.Height, protoVote.Round, ext) items[t][i] = NewSignItem(quorumType, quorumHash, reqID, raw) } diff --git a/types/test_util.go b/types/test_util.go index 1f0ca2b7f7..9dfe62d281 100644 --- a/types/test_util.go +++ b/types/test_util.go @@ -46,8 +46,8 @@ func makeCommit( Type: tmproto.PrecommitType, BlockID: blockID, VoteExtensions: VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []VoteExtension{{Extension: []byte("default")}}, - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []VoteExtension{{Extension: []byte("threshold")}}, + tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("default")}}, + tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{Extension: []byte("threshold")}}, }, } @@ -68,9 +68,8 @@ func signAddVote(ctx context.Context, privVal PrivValidator, vote *Vote, voteSet if err != nil { return false, err } - err = vote.PopulateSignsFromProto(v) - if err != nil { - return false, err - } + + vote.VoteExtensions = VoteExtensionsFromProto(v.VoteExtensions) + return voteSet.AddVote(vote) } diff --git a/types/vote.go b/types/vote.go index bf6b19c205..8a02806ea8 100644 --- a/types/vote.go +++ b/types/vote.go @@ -11,7 +11,6 @@ import ( "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/crypto/bls12381" - "github.com/dashpay/tenderdash/internal/libs/protoio" tmbytes "github.com/dashpay/tenderdash/libs/bytes" tmcons "github.com/dashpay/tenderdash/proto/tendermint/consensus" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" @@ -29,6 +28,7 @@ const ( var VoteExtensionTypes = []tmproto.VoteExtensionType{ tmproto.VoteExtensionType_DEFAULT, tmproto.VoteExtensionType_THRESHOLD_RECOVER, + tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, } func MaxVoteBytesForKeyType(keyType crypto.KeyType) int64 { @@ -118,8 +118,7 @@ func VoteFromProto(pv *tmproto.Vote) (*Vote, error) { // Similar to VoteSignBytes, the encoded Protobuf message is varint // length-prefixed for backwards-compatibility with the Amino encoding. func VoteExtensionSignBytes(chainID string, height int64, round int32, ext *tmproto.VoteExtension) []byte { - pb := CanonicalizeVoteExtension(chainID, ext, height, round) - bz, err := protoio.MarshalDelimited(&pb) + bz, err := CanonicalizeVoteExtension(chainID, ext, height, round) if err != nil { panic(err) } @@ -127,7 +126,17 @@ func VoteExtensionSignBytes(chainID string, height int64, round int32, ext *tmpr } // VoteExtensionRequestID returns vote extension request ID -func VoteExtensionRequestID(height int64, round int32) []byte { +func VoteExtensionRequestID(ext *tmproto.VoteExtension, height int64, round int32) []byte { + signRequestID := ext.GetSignRequestId() + + if signRequestID != nil { + if ext.Type == tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW { + return signRequestID + } + + panic(fmt.Sprintf("unexpected sign request id for vote extension type %s", ext.Type.String())) + } + return heightRoundRequestID("dpevote", height, round) } @@ -236,6 +245,7 @@ func (vote *Vote) Verify( return err } + // TODO check why we don't verify extensions here return vote.verifySign(pubKey, quorumSignData, WithVerifyExtensions(false)) } diff --git a/types/vote_dash.go b/types/vote_dash.go index aae8f430b8..6dbdc65855 100644 --- a/types/vote_dash.go +++ b/types/vote_dash.go @@ -2,18 +2,6 @@ package types import tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" -// PopulateSignsFromProto updates the signatures of the current Vote with values are taken from the Vote's protobuf -func (vote *Vote) PopulateSignsFromProto(pv *tmproto.Vote) error { - vote.BlockSignature = pv.BlockSignature - return vote.VoteExtensions.CopySignsFromProto(pv.VoteExtensionsToMap()) -} - -// PopulateSignsToProto updates the signatures of the given protobuf Vote entity with values are taken from the current Vote's -func (vote *Vote) PopulateSignsToProto(pv *tmproto.Vote) error { - pv.BlockSignature = vote.BlockSignature - return vote.VoteExtensions.CopySignsToProto(pv.VoteExtensionsToMap()) -} - // GetVoteExtensionsSigns returns the list of signatures for given vote-extension type func (vote *Vote) GetVoteExtensionsSigns(extType tmproto.VoteExtensionType) [][]byte { if vote.VoteExtensions == nil { diff --git a/types/vote_extension.go b/types/vote_extension.go index dcce659a33..47c0d5e9d4 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -2,35 +2,28 @@ package types import ( "bytes" - "errors" - "fmt" abci "github.com/dashpay/tenderdash/abci/types" tmbytes "github.com/dashpay/tenderdash/libs/bytes" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" ) -var ( - errExtensionSignEmpty = errors.New("vote extension signature is missing") - errExtensionSignTooBig = fmt.Errorf("vote extension signature is too big (max: %d)", SignatureSize) - errUnableCopySigns = errors.New("unable copy signatures the sizes of extensions are not equal") -) - // VoteExtensions is a container where the key is vote-extension type and value is a list of VoteExtension -type VoteExtensions map[tmproto.VoteExtensionType][]VoteExtension +type VoteExtensions map[tmproto.VoteExtensionType][]tmproto.VoteExtension // NewVoteExtensionsFromABCIExtended returns vote-extensions container for given ExtendVoteExtension func NewVoteExtensionsFromABCIExtended(exts []*abci.ExtendVoteExtension) VoteExtensions { voteExtensions := make(VoteExtensions) for _, ext := range exts { - voteExtensions.Add(ext.Type, ext.Extension) + ve := ext.ToVoteExtension() + voteExtensions.Add(ext.Type, ve) } return voteExtensions } // Add creates and adds VoteExtension into a container by vote-extension type -func (e VoteExtensions) Add(t tmproto.VoteExtensionType, ext []byte) { - e[t] = append(e[t], VoteExtension{Extension: ext}) +func (e VoteExtensions) Add(t tmproto.VoteExtensionType, ext tmproto.VoteExtension) { + e[t] = append(e[t], ext) } // Validate returns error if an added vote-extension is invalid @@ -124,31 +117,6 @@ func (e VoteExtensions) totalCount() int { return cnt } -// VoteExtension represents a vote extension data, with possible types: default or threshold recover -type VoteExtension struct { - Extension []byte `json:"extension"` - Signature tmbytes.HexBytes `json:"signature"` -} - -// Validate ... -func (v *VoteExtension) Validate() error { - if len(v.Extension) > 0 && len(v.Signature) == 0 { - return errExtensionSignEmpty - } - if len(v.Signature) > SignatureSize { - return errExtensionSignTooBig - } - return nil -} - -// Clone returns a copy of current vote-extension -func (v *VoteExtension) Clone() VoteExtension { - return VoteExtension{ - Extension: v.Extension, - Signature: v.Signature, - } -} - // VoteExtensionsFromProto creates VoteExtensions container from VoteExtensions's protobuf func VoteExtensionsFromProto(pve []*tmproto.VoteExtension) VoteExtensions { if pve == nil { @@ -156,10 +124,7 @@ func VoteExtensionsFromProto(pve []*tmproto.VoteExtension) VoteExtensions { } voteExtensions := make(VoteExtensions) for _, ext := range pve { - voteExtensions[ext.Type] = append(voteExtensions[ext.Type], VoteExtension{ - Extension: ext.Extension, - Signature: ext.Signature, - }) + voteExtensions[ext.Type] = append(voteExtensions[ext.Type], ext.Clone()) } return voteExtensions } @@ -168,7 +133,7 @@ func VoteExtensionsFromProto(pve []*tmproto.VoteExtension) VoteExtensions { func (e VoteExtensions) Copy() VoteExtensions { copied := make(VoteExtensions, len(e)) for extType, extensions := range e { - copied[extType] = make([]VoteExtension, len(extensions)) + copied[extType] = make([]tmproto.VoteExtension, len(extensions)) for k, v := range extensions { copied[extType][k] = v.Clone() } @@ -176,32 +141,3 @@ func (e VoteExtensions) Copy() VoteExtensions { return copied } - -// CopySignsFromProto copies the signatures from VoteExtensions's protobuf into the current VoteExtension state -func (e VoteExtensions) CopySignsFromProto(src tmproto.VoteExtensions) error { - return e.copySigns(src, func(a *tmproto.VoteExtension, b *VoteExtension) { - b.Signature = a.Signature - }) -} - -// CopySignsToProto copies the signatures from the current VoteExtensions into VoteExtension's protobuf -func (e VoteExtensions) CopySignsToProto(dist tmproto.VoteExtensions) error { - return e.copySigns(dist, func(a *tmproto.VoteExtension, b *VoteExtension) { - a.Signature = b.Signature - }) -} - -func (e VoteExtensions) copySigns( - protoMap tmproto.VoteExtensions, - modifier func(a *tmproto.VoteExtension, b *VoteExtension), -) error { - for t, exts := range e { - if len(exts) != len(protoMap[t]) { - return errUnableCopySigns - } - for i := range exts { - modifier(protoMap[t][i], &exts[i]) - } - } - return nil -} From 37a1b36f7819fdaf69483e98d89a1d9930279137 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 12 Dec 2023 16:11:59 +0100 Subject: [PATCH 07/55] test: fix tests build --- internal/consensus/common_test.go | 2 +- internal/consensus/msgs_test.go | 2 +- internal/consensus/state_test.go | 4 +-- internal/consensus/vote_signer_test.go | 2 +- privval/file_test.go | 4 +-- privval/msgs_test.go | 2 +- types/quorum_sign_data_test.go | 50 ++++++++++++++++++++++++-- types/signs_recoverer_test.go | 2 +- types/vote.go | 2 +- types/vote_dash.go | 12 +++++++ types/vote_extension.go | 34 ++++++++++++++++++ types/vote_test.go | 32 +++++++++++++---- 12 files changed, 129 insertions(+), 19 deletions(-) diff --git a/internal/consensus/common_test.go b/internal/consensus/common_test.go index 807dbea5d0..5b725acd0c 100644 --- a/internal/consensus/common_test.go +++ b/internal/consensus/common_test.go @@ -159,7 +159,7 @@ func signVote( quorumHash crypto.QuorumHash) *types.Vote { exts := make(types.VoteExtensions) if voteType == tmproto.PrecommitType && !blockID.IsNil() { - exts.Add(tmproto.VoteExtensionType_DEFAULT, []byte("extension")) + exts.Add(tmproto.VoteExtensionType_DEFAULT, tmproto.VoteExtension{Extension: []byte("extension")}) } v, err := vs.signVote(ctx, voteType, chainID, blockID, quorumType, quorumHash, exts) require.NoError(t, err, "failed to sign vote") diff --git a/internal/consensus/msgs_test.go b/internal/consensus/msgs_test.go index 73b5a1dede..cf0078c944 100644 --- a/internal/consensus/msgs_test.go +++ b/internal/consensus/msgs_test.go @@ -385,7 +385,7 @@ func TestConsMsgsVectors(t *testing.T) { Type: tmproto.PrecommitType, BlockID: bi, VoteExtensions: types.VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []types.VoteExtension{{Extension: []byte("extension")}}, + tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("extension")}}, }, } diff --git a/internal/consensus/state_test.go b/internal/consensus/state_test.go index 2c3587b114..ff71f68ccb 100644 --- a/internal/consensus/state_test.go +++ b/internal/consensus/state_test.go @@ -2454,10 +2454,10 @@ func TestPrepareProposalReceivesVoteExtensions(t *testing.T) { // create a precommit for each validator with the associated vote extension. for _, vs := range vss[1:] { voteExtensions := types.VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []types.VoteExtension{ + tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{ {Extension: []byte("extension")}, }, - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []types.VoteExtension{ + tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{ {Extension: []byte("deterministic")}, }, } diff --git a/internal/consensus/vote_signer_test.go b/internal/consensus/vote_signer_test.go index c9b2369691..829ab52125 100644 --- a/internal/consensus/vote_signer_test.go +++ b/internal/consensus/vote_signer_test.go @@ -40,7 +40,7 @@ func TestVoteSigner_signAddVote(t *testing.T) { ProTxHash: proTxHash, } voteExtensions := types.VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []types.VoteExtension{ + tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{ {Extension: tmbytes.MustHexDecode("524F1D03D1D81E94A099042736D40BD9681B867321443FF58A4568E274DBD83B")}, }, } diff --git a/privval/file_test.go b/privval/file_test.go index 2a89fa1925..132d109cf3 100644 --- a/privval/file_test.go +++ b/privval/file_test.go @@ -360,7 +360,7 @@ func TestVoteExtensionsAreAlwaysSigned(t *testing.T) { voteType := tmproto.PrecommitType exts := types.VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []types.VoteExtension{{Extension: []byte("extension")}}, + tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("extension")}}, } // We initially sign this vote without an extension vote1 := newVote(proTxHash, 0, height, round, voteType, blockID, exts) @@ -378,7 +378,7 @@ func TestVoteExtensionsAreAlwaysSigned(t *testing.T) { // its extension vote2 := vote1.Copy() vote2.VoteExtensions = types.VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []types.VoteExtension{{Extension: []byte("new extension")}}, + tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("new extension")}}, } vpb2 := vote2.ToProto() diff --git a/privval/msgs_test.go b/privval/msgs_test.go index bbb4d5f339..833d042b20 100644 --- a/privval/msgs_test.go +++ b/privval/msgs_test.go @@ -45,7 +45,7 @@ func exampleVote() *types.Vote { ValidatorProTxHash: crypto.ProTxHashFromSeedBytes([]byte("validator_pro_tx_hash")), ValidatorIndex: 56789, VoteExtensions: types.VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []types.VoteExtension{{Extension: []byte("extension")}}, + tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("extension")}}, }, } } diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index 54467ab895..6d8891a205 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "fmt" "testing" @@ -12,6 +13,7 @@ import ( tmbytes "github.com/dashpay/tenderdash/libs/bytes" "github.com/dashpay/tenderdash/libs/log" "github.com/dashpay/tenderdash/proto/tendermint/types" + tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" ) func TestBlockRequestID(t *testing.T) { @@ -69,8 +71,8 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { Height: 1001, ValidatorProTxHash: tmbytes.MustHexDecode("9CC13F685BC3EA0FCA99B87F42ABCC934C6305AA47F62A32266A2B9D55306B7B"), VoteExtensions: VoteExtensions{ - types.VoteExtensionType_DEFAULT: []VoteExtension{{Extension: []byte("default")}}, - types.VoteExtensionType_THRESHOLD_RECOVER: []VoteExtension{{Extension: []byte("threshold")}}, + types.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("default")}}, + types.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{Extension: []byte("threshold")}}, }, }, quorumHash: tmbytes.MustHexDecode("6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD"), @@ -116,6 +118,50 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { } } +// TestVoteExtensionsRawSignData checks signed data for a VoteExtensionType_THRESHOLD_RECOVER_RAW vote extension type. +// +// Given some vote extension, llmq type, quorum hash and sign request id, sign data should match predefined test vector. +func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { + extension := []byte{1, 2, 3, 4, 5, 6, 7, 8} + quorumHash := bytes.Repeat([]byte{4, 3, 2, 1}, 8) + + requestID := []byte("dpevote-someSignRequestID") + llmq := btcjson.LLMQType_100_67 + chainID := "some-chain" + + ve := tmproto.VoteExtension{ + Extension: extension, + Signature: []byte{}, + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, + XSignRequestId: &tmproto.VoteExtension_SignRequestId{ + SignRequestId: requestID, + }, + } + + signItems, err := MakeVoteExtensionSignItems(chainID, &tmproto.Vote{ + Type: tmproto.PrecommitType, + VoteExtensions: []*tmproto.VoteExtension{&ve}, + }, llmq, quorumHash) + assert.NoError(t, err) + + item := signItems[tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW][0] + actual := item.ID + + // SHA256(llmqType, quorumHash, ABCI_sign_requestId, ABCI_extension) + // blsSignHash := bls.BuildSignHash(uint8(llmqType), blsQuorumHash, blsRequestID, blsMessageHash) + + expected := []byte{uint8(llmq)} + expected = append(expected, tmbytes.Reverse(quorumHash)...) + expected = append(expected, tmbytes.Reverse(crypto.Checksum(requestID))...) + expected = append(expected, tmbytes.Reverse(crypto.Checksum(extension))...) + + fmt.Printf("Expected: %v \n", expected) + + expected = crypto.Checksum(crypto.Checksum(expected)) + t.Logf("sign bytes: %x", actual) + assert.EqualValues(t, expected, actual) +} + func newSignItem(reqID, ID, raw string) SignItem { item := SignItem{ ReqID: tmbytes.MustHexDecode(reqID), diff --git a/types/signs_recoverer_test.go b/types/signs_recoverer_test.go index e805df56f8..50ed1b3067 100644 --- a/types/signs_recoverer_test.go +++ b/types/signs_recoverer_test.go @@ -141,7 +141,7 @@ func mockVoteExtensions(t *testing.T, pairs ...interface{}) VoteExtensions { if !ok { t.Fatalf("given unsupported type %T", pairs[i]) } - ext := VoteExtension{} + ext := tmproto.VoteExtension{} switch v := pairs[i+1].(type) { case string: ext.Extension = []byte(v) diff --git a/types/vote.go b/types/vote.go index 8a02806ea8..db73752131 100644 --- a/types/vote.go +++ b/types/vote.go @@ -131,7 +131,7 @@ func VoteExtensionRequestID(ext *tmproto.VoteExtension, height int64, round int3 if signRequestID != nil { if ext.Type == tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW { - return signRequestID + return crypto.Checksum(signRequestID) } panic(fmt.Sprintf("unexpected sign request id for vote extension type %s", ext.Type.String())) diff --git a/types/vote_dash.go b/types/vote_dash.go index 6dbdc65855..aae8f430b8 100644 --- a/types/vote_dash.go +++ b/types/vote_dash.go @@ -2,6 +2,18 @@ package types import tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" +// PopulateSignsFromProto updates the signatures of the current Vote with values are taken from the Vote's protobuf +func (vote *Vote) PopulateSignsFromProto(pv *tmproto.Vote) error { + vote.BlockSignature = pv.BlockSignature + return vote.VoteExtensions.CopySignsFromProto(pv.VoteExtensionsToMap()) +} + +// PopulateSignsToProto updates the signatures of the given protobuf Vote entity with values are taken from the current Vote's +func (vote *Vote) PopulateSignsToProto(pv *tmproto.Vote) error { + pv.BlockSignature = vote.BlockSignature + return vote.VoteExtensions.CopySignsToProto(pv.VoteExtensionsToMap()) +} + // GetVoteExtensionsSigns returns the list of signatures for given vote-extension type func (vote *Vote) GetVoteExtensionsSigns(extType tmproto.VoteExtensionType) [][]byte { if vote.VoteExtensions == nil { diff --git a/types/vote_extension.go b/types/vote_extension.go index 47c0d5e9d4..8fe5af4989 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -2,12 +2,17 @@ package types import ( "bytes" + "errors" abci "github.com/dashpay/tenderdash/abci/types" tmbytes "github.com/dashpay/tenderdash/libs/bytes" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" ) +var ( + errUnableCopySigns = errors.New("unable copy signatures the sizes of extensions are not equal") +) + // VoteExtensions is a container where the key is vote-extension type and value is a list of VoteExtension type VoteExtensions map[tmproto.VoteExtensionType][]tmproto.VoteExtension @@ -141,3 +146,32 @@ func (e VoteExtensions) Copy() VoteExtensions { return copied } + +// CopySignsFromProto copies the signatures from VoteExtensions's protobuf into the current VoteExtension state +func (e VoteExtensions) CopySignsFromProto(src tmproto.VoteExtensions) error { + return e.copySigns(src, func(a *tmproto.VoteExtension, b *tmproto.VoteExtension) { + b.Signature = a.Signature + }) +} + +// CopySignsToProto copies the signatures from the current VoteExtensions into VoteExtension's protobuf +func (e VoteExtensions) CopySignsToProto(dist tmproto.VoteExtensions) error { + return e.copySigns(dist, func(a *tmproto.VoteExtension, b *tmproto.VoteExtension) { + a.Signature = b.Signature + }) +} + +func (e VoteExtensions) copySigns( + protoMap tmproto.VoteExtensions, + modifier func(a *tmproto.VoteExtension, b *tmproto.VoteExtension), +) error { + for t, exts := range e { + if len(exts) != len(protoMap[t]) { + return errUnableCopySigns + } + for i := range exts { + modifier(protoMap[t][i], &exts[i]) + } + } + return nil +} diff --git a/types/vote_test.go b/types/vote_test.go index 0c05e9d502..9b2703bd99 100644 --- a/types/vote_test.go +++ b/types/vote_test.go @@ -40,7 +40,7 @@ func examplePrecommit(t testing.TB) *Vote { t.Helper() vote := exampleVote(t, byte(tmproto.PrecommitType)) vote.VoteExtensions = VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []VoteExtension{{Signature: []byte("signature")}}, + tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Signature: []byte("signature")}}, } return vote } @@ -182,7 +182,7 @@ func TestVoteSignBytesTestVectors(t *testing.T) { Height: 1, Round: 1, VoteExtensions: VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []VoteExtension{{Extension: []byte("extension")}}, + tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("extension")}}, }, }, []byte{ @@ -333,7 +333,7 @@ func TestVoteExtension(t *testing.T) { { name: "all fields present", extensions: VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []VoteExtension{{Extension: []byte("extension")}}, + tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{Extension: []byte("extension")}}, }, includeSignature: true, expectError: false, @@ -341,7 +341,7 @@ func TestVoteExtension(t *testing.T) { { name: "no extension signature", extensions: VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []VoteExtension{{Extension: []byte("extension")}}, + tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{Extension: []byte("extension")}}, }, includeSignature: false, expectError: true, @@ -579,13 +579,13 @@ func TestInvalidPrevotes(t *testing.T) { { "vote extension present", func(v *Vote) { - v.VoteExtensions = VoteExtensions{tmproto.VoteExtensionType_DEFAULT: []VoteExtension{{Extension: []byte("extension")}}} + v.VoteExtensions = VoteExtensions{tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("extension")}}} }, }, { "vote extension signature present", func(v *Vote) { - v.VoteExtensions = VoteExtensions{tmproto.VoteExtensionType_DEFAULT: []VoteExtension{{Signature: []byte("signature")}}} + v.VoteExtensions = VoteExtensions{tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Signature: []byte("signature")}}} }, }, } @@ -621,7 +621,7 @@ func TestInvalidPrecommitExtensions(t *testing.T) { "oversized vote extension signature", func(v *Vote) { v.VoteExtensions = VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []VoteExtension{{Signature: make([]byte, SignatureSize+1)}}, + tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{Signature: make([]byte, SignatureSize+1)}}, } }, }, @@ -653,6 +653,24 @@ func TestVoteExtensionsSignBytes(t *testing.T) { assert.EqualValues(t, expect, actual) } +// TestVoteExtensionsSignBytesRaw checks vote extension sign bytes for a raw vote extension type. +// +// Given some vote extension, SignBytes or THRESHOLD_RECOVER_RAW returns that extension. +func TestVoteExtensionsSignBytesRaw(t *testing.T) { + expect := []byte{1, 2, 3, 4, 5, 6, 7, 8} + ve := tmproto.VoteExtension{ + Extension: expect, + Signature: []byte{}, + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, + XSignRequestId: &tmproto.VoteExtension_SignRequestId{ + SignRequestId: []byte("dpevote-someSignRequestID"), + }, + } + actual := VoteExtensionSignBytes("some-chain", 1, 2, &ve) + t.Logf("sign bytes: %x", actual) + assert.EqualValues(t, expect, actual) +} + func TestVoteProtobuf(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() From 37340ab7b60fae3dafff29237ecac58e2f31e80e Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 12 Dec 2023 16:18:31 +0100 Subject: [PATCH 08/55] chore: remove printf --- types/quorum_sign_data_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index 6d8891a205..ec554c9d2a 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -155,9 +155,8 @@ func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { expected = append(expected, tmbytes.Reverse(crypto.Checksum(requestID))...) expected = append(expected, tmbytes.Reverse(crypto.Checksum(extension))...) - fmt.Printf("Expected: %v \n", expected) - expected = crypto.Checksum(crypto.Checksum(expected)) + t.Logf("sign bytes: %x", actual) assert.EqualValues(t, expected, actual) } From 459d279ec7cb8e6fa63eadacb2bebacfecc5319f Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 12 Dec 2023 16:37:21 +0100 Subject: [PATCH 09/55] doc: proto THRESHOLD_RECOVER_RAW docs --- abci/types/types.pb.go | 4 ++-- proto/tendermint/abci/types.proto | 10 ++++++---- proto/tendermint/types/dash.pb.go | 9 +++++++++ proto/tendermint/types/dash.proto | 7 ++++++- spec/abci++/api.md | 6 ++++-- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 12e14b93e8..7ed1b1a00e 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -3069,8 +3069,8 @@ func (m *ResponseProcessProposal) GetValidatorSetUpdate() *ValidatorSetUpdate { // Provides a vote extension for signing. `type` and `extension` fields are mandatory for filling type ExtendVoteExtension struct { - // Vote extension type can be either DEFAULT or THRESHOLD_RECOVER. - // The Tenderdash supports only THRESHOLD_RECOVER at this moment. + // Vote extension type can be either DEFAULT, THRESHOLD_RECOVER or THRESHOLD_RECOVER_RAW. + // The Tenderdash supports only THRESHOLD_RECOVER and THRESHOLD_RECOVER_RAW at this moment. Type types1.VoteExtensionType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.types.VoteExtensionType" json:"type,omitempty"` // Deterministic or (Non-Deterministic) extension provided by the sending validator's Application. Extension []byte `protobuf:"bytes,2,opt,name=extension,proto3" json:"extension,omitempty"` diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 392eee3d40..18a9f7f835 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -662,14 +662,16 @@ message ResponseProcessProposal { // Provides a vote extension for signing. `type` and `extension` fields are mandatory for filling message ExtendVoteExtension { - // Vote extension type can be either DEFAULT or THRESHOLD_RECOVER. - // The Tenderdash supports only THRESHOLD_RECOVER at this moment. + // Vote extension type can be either DEFAULT, THRESHOLD_RECOVER or THRESHOLD_RECOVER_RAW. + // The Tenderdash supports only THRESHOLD_RECOVER and THRESHOLD_RECOVER_RAW at this moment. tendermint.types.VoteExtensionType type = 1; // Deterministic or (Non-Deterministic) extension provided by the sending validator's Application. bytes extension = 2; // Sign request ID that will be used to sign the vote extensions. - // Tenderdash will use checksum of `sign_request_id` when generating quorum signatures of - // THRESHOLD_RECOVER vote extensions. + // Only applicable for THRESHOLD_RECOVER_RAW vote extension type. + // + // Tenderdash will use SHA256 checksum of `sign_request_id` when generating quorum signatures of + // THRESHOLD_RECOVER_RAW vote extensions. It MUST NOT be set for any other vote extension types. // If not set, Tenderdash will generate it based on height and round. // diff --git a/proto/tendermint/types/dash.pb.go b/proto/tendermint/types/dash.pb.go index 58f85b9cd0..ad693ce5ab 100644 --- a/proto/tendermint/types/dash.pb.go +++ b/proto/tendermint/types/dash.pb.go @@ -33,8 +33,17 @@ const ( // // Deterministic vote extension - each validator in a quorum must provide the same vote extension data. VoteExtensionType_THRESHOLD_RECOVER VoteExtensionType = 1 + // Sign raw form of vote extension and threshold-recover signatures. + // + // Deterministic vote extension - each validator in a quorum must provide the same vote extension data. // Use with caution - it can have severe security consequences, like replay attacks. // + // THRESHOLD_RECOVER_RAW alows overriding sign request ID with `sign_request_id` field + // of ExtendVoteExtension.sign_request_id. If sign_request_id is provided, SHA256(sign_request_id) will be used as + // a sign request ID. + // + // It also changes how threshold-recover signatures are generated. Instead of signing canonical form of + // threshold-recover signatures, it signs SHA256 of raw form of the vote extension (`ExtendVoteExtension.extension`). VoteExtensionType_THRESHOLD_RECOVER_RAW VoteExtensionType = 2 ) diff --git a/proto/tendermint/types/dash.proto b/proto/tendermint/types/dash.proto index d93cec5954..41206a5ac2 100644 --- a/proto/tendermint/types/dash.proto +++ b/proto/tendermint/types/dash.proto @@ -23,9 +23,14 @@ enum VoteExtensionType { // Sign raw form of vote extension and threshold-recover signatures. // // Deterministic vote extension - each validator in a quorum must provide the same vote extension data. - // Use with caution - it can have severe security consequences, like replay attacks. // + // THRESHOLD_RECOVER_RAW alows overriding sign request ID with `sign_request_id` field + // of ExtendVoteExtension.sign_request_id. If sign_request_id is provided, SHA256(sign_request_id) will be used as + // a sign request ID. + // + // It also changes how threshold-recover signatures are generated. Instead of signing canonical form of + // threshold-recover signatures, it signs SHA256 of raw form of the vote extension (`ExtendVoteExtension.extension`). THRESHOLD_RECOVER_RAW = 2; } diff --git a/spec/abci++/api.md b/spec/abci++/api.md index 7c187b1861..2b2f95739b 100644 --- a/spec/abci++/api.md +++ b/spec/abci++/api.md @@ -160,10 +160,12 @@ Provides a vote extension for signing. `type` and `extension` fields are mandato | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| type | [tendermint.types.VoteExtensionType](#tendermint-types-VoteExtensionType) | | Vote extension type can be either DEFAULT or THRESHOLD_RECOVER. The Tenderdash supports only THRESHOLD_RECOVER at this moment. | +| type | [tendermint.types.VoteExtensionType](#tendermint-types-VoteExtensionType) | | Vote extension type can be either DEFAULT, THRESHOLD_RECOVER or THRESHOLD_RECOVER_RAW. The Tenderdash supports only THRESHOLD_RECOVER and THRESHOLD_RECOVER_RAW at this moment. | | extension | [bytes](#bytes) | | Deterministic or (Non-Deterministic) extension provided by the sending validator's Application. -Sign request ID that will be used to sign the vote extensions. Tenderdash will use checksum of `sign_request_id` when generating quorum signatures of THRESHOLD_RECOVER vote extensions. | +Sign request ID that will be used to sign the vote extensions. Only applicable for THRESHOLD_RECOVER_RAW vote extension type. + +Tenderdash will use SHA256 checksum of `sign_request_id` when generating quorum signatures of THRESHOLD_RECOVER_RAW vote extensions. It MUST NOT be set for any other vote extension types. | | sign_request_id | [bytes](#bytes) | optional | If not set, Tenderdash will generate it based on height and round. If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` string. From 6978fc6b079d2c203e0f4a37b97dd40e5baa3b60 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:47:46 +0100 Subject: [PATCH 10/55] chore: vote extension fixes --- proto/tendermint/types/dash.go | 19 +++++++++++--- types/canonical.go | 2 +- types/quorum_sign_data.go | 20 +++++++++++---- types/quorum_sign_data_test.go | 44 +++++++++++++++++++++++++-------- types/vote.go | 9 ++++--- types/vote_extension.go | 7 ++---- types/vote_test.go | 45 ++++++++++++++++++++-------------- 7 files changed, 101 insertions(+), 45 deletions(-) diff --git a/proto/tendermint/types/dash.go b/proto/tendermint/types/dash.go index fa0914f0a5..68739e62ba 100644 --- a/proto/tendermint/types/dash.go +++ b/proto/tendermint/types/dash.go @@ -12,6 +12,7 @@ import ( type VoteExtensions map[VoteExtensionType][]*VoteExtension var ( + errExtensionNil = errors.New("vote extension is nil") errExtensionSignEmpty = errors.New("vote extension signature is missing") errExtensionSignTooBig = fmt.Errorf("vote extension signature is too big (max: %d)", bls12381.SignatureSize) errExtensionSignRequestIdNotSupported = errors.New("vote extension sign request id is not supported") @@ -19,10 +20,17 @@ var ( ) // Clone returns a copy of current vote-extension +// +// Clone of nil will panic + func (v *VoteExtension) Clone() VoteExtension { - var xSignRequestID *VoteExtension_SignRequestId + if v == nil { + panic("cannot clone nil vote-extension") + } + + var xSignRequestID isVoteExtension_XSignRequestId - if v.XSignRequestId != nil { + if v.XSignRequestId != nil && v.XSignRequestId.Size() > 0 { src := v.GetSignRequestId() dst := make([]byte, len(src)) copy(dst, src) @@ -32,6 +40,7 @@ func (v *VoteExtension) Clone() VoteExtension { } return VoteExtension{ + Type: v.Type, Extension: v.Extension, Signature: v.Signature, XSignRequestId: xSignRequestID, @@ -40,6 +49,10 @@ func (v *VoteExtension) Clone() VoteExtension { // Validate checks the validity of the vote-extension func (v *VoteExtension) Validate() error { + if v == nil { + return errExtensionNil + } + if len(v.Extension) > 0 && len(v.Signature) == 0 { return errExtensionSignEmpty } @@ -47,7 +60,7 @@ func (v *VoteExtension) Validate() error { return errExtensionSignTooBig } - if v.XSignRequestId != nil { + if v.XSignRequestId != nil && v.XSignRequestId.Size() > 0 { if v.Type != VoteExtensionType_THRESHOLD_RECOVER_RAW { return errExtensionSignRequestIdNotSupported } diff --git a/types/canonical.go b/types/canonical.go index d931b5e419..53385d9039 100644 --- a/types/canonical.go +++ b/types/canonical.go @@ -35,7 +35,7 @@ func CanonicalizeProposal(chainID string, proposal *tmproto.Proposal) tmproto.Ca // bytes is what is signed in order to produce the vote extension's signature. func CanonicalizeVoteExtension(chainID string, ext *tmproto.VoteExtension, height int64, round int32) ([]byte, error) { switch ext.Type { - case tmproto.VoteExtensionType_THRESHOLD_RECOVER: + case tmproto.VoteExtensionType_DEFAULT, tmproto.VoteExtensionType_THRESHOLD_RECOVER: { canonical := tmproto.CanonicalVoteExtension{ Extension: ext.Extension, diff --git a/types/quorum_sign_data.go b/types/quorum_sign_data.go index e15ff0c2c9..2f81576dc4 100644 --- a/types/quorum_sign_data.go +++ b/types/quorum_sign_data.go @@ -114,14 +114,24 @@ func MakeVoteExtensionSignItems( if items[t] == nil && len(exts) > 0 { items[t] = make([]SignItem, len(exts)) } - if t == types.VoteExtensionType_DEFAULT { - // DEFAULT vote extensions don't support signing - continue - } + for i, ext := range exts { reqID := VoteExtensionRequestID(ext, protoVote.Height, protoVote.Round) raw := VoteExtensionSignBytes(chainID, protoVote.Height, protoVote.Round, ext) - items[t][i] = NewSignItem(quorumType, quorumHash, reqID, raw) + // TODO: this is to avoid sha256 of raw data, to be removed once we get into agreement on the format + if ext.Type == types.VoteExtensionType_THRESHOLD_RECOVER_RAW { + // ensure we have exactly 32 bytes, cut or fill with 0s if it's not + msgHash := make([]byte, 32) + copy(msgHash, raw) + items[t][i] = SignItem{ + ReqID: reqID, + ID: MakeSignID(raw, reqID, quorumType, quorumHash), + Raw: raw, + Hash: msgHash, + } + } else { + items[t][i] = NewSignItem(quorumType, quorumHash, reqID, raw) + } } } return items, nil diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index ec554c9d2a..df44786199 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -2,6 +2,7 @@ package types import ( "bytes" + "encoding/hex" "fmt" "testing" @@ -122,11 +123,34 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { // // Given some vote extension, llmq type, quorum hash and sign request id, sign data should match predefined test vector. func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { - extension := []byte{1, 2, 3, 4, 5, 6, 7, 8} - quorumHash := bytes.Repeat([]byte{4, 3, 2, 1}, 8) + llmq := btcjson.LLMQType_TEST_PLATFORM - requestID := []byte("dpevote-someSignRequestID") - llmq := btcjson.LLMQType_100_67 + quorumHash, err := hex.DecodeString("dddabfe1c883dd8a2c71c4281a4212c3715a61f87d62a99aaed0f65a0506c053") + assert.NoError(t, err) + assert.Len(t, quorumHash, 32) + + requestID, err := hex.DecodeString("922a8fc39b6e265ca761eaaf863387a5e2019f4795a42260805f5562699fd9fa") + assert.NoError(t, err) + assert.Len(t, requestID, 32) + + extension, err := hex.DecodeString("7dfb2432d37f004c4eb2b9aebf601ba4ad59889b81d2e8c7029dce3e0bf8381c") + assert.NoError(t, err) + assert.Len(t, extension, 32) + + expected, err := hex.DecodeString("6d98f773cef8484432c4946c6b96e04aab39fd119c77de2f21d668dd17d5d2f6") + assert.NoError(t, err) + assert.Len(t, expected, 32) + + // quorumHash = tmbytes.Reverse(quorumHash) + // requestID = tmbytes.Reverse(requestID) + // extension = tmbytes.Reverse(extension) + expected = tmbytes.Reverse(expected) + + // extension := []byte{1, 2, 3, 4, 5, 6, 7, 8} + // quorumHash := bytes.Repeat([]byte{4, 3, 2, 1}, 8) + + // requestID := []byte("dpevote-someSignRequestID") + // llmq := btcjson.LLMQType_100_67 chainID := "some-chain" ve := tmproto.VoteExtension{ @@ -146,16 +170,16 @@ func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { item := signItems[tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW][0] actual := item.ID - + // actual = crypto.Checksum(actual) // SHA256(llmqType, quorumHash, ABCI_sign_requestId, ABCI_extension) // blsSignHash := bls.BuildSignHash(uint8(llmqType), blsQuorumHash, blsRequestID, blsMessageHash) - expected := []byte{uint8(llmq)} - expected = append(expected, tmbytes.Reverse(quorumHash)...) - expected = append(expected, tmbytes.Reverse(crypto.Checksum(requestID))...) - expected = append(expected, tmbytes.Reverse(crypto.Checksum(extension))...) + // expected := []byte{uint8(llmq)} + // expected = append(expected, tmbytes.Reverse(quorumHash)...) + // expected = append(expected, tmbytes.Reverse(crypto.Checksum(requestID))...) + // expected = append(expected, tmbytes.Reverse(crypto.Checksum(extension))...) - expected = crypto.Checksum(crypto.Checksum(expected)) + // expected = crypto.Checksum(crypto.Checksum(expected)) t.Logf("sign bytes: %x", actual) assert.EqualValues(t, expected, actual) diff --git a/types/vote.go b/types/vote.go index db73752131..777319861a 100644 --- a/types/vote.go +++ b/types/vote.go @@ -127,11 +127,14 @@ func VoteExtensionSignBytes(chainID string, height int64, round int32, ext *tmpr // VoteExtensionRequestID returns vote extension request ID func VoteExtensionRequestID(ext *tmproto.VoteExtension, height int64, round int32) []byte { - signRequestID := ext.GetSignRequestId() - if signRequestID != nil { + if ext.XSignRequestId != nil && ext.XSignRequestId.Size() > 0 { if ext.Type == tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW { - return crypto.Checksum(signRequestID) + // TODO to avoid blind signing, we should have crypto.Checksum(signRequestID) here + buf := make([]byte, 32) + // this will ensure sign request ID has exactly 32 bytes + copy(buf, ext.GetSignRequestId()) + return buf } panic(fmt.Sprintf("unexpected sign request id for vote extension type %s", ext.Type.String())) diff --git a/types/vote_extension.go b/types/vote_extension.go index 8fe5af4989..3cd98826dd 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -59,11 +59,8 @@ func (e VoteExtensions) ToProto() []*tmproto.VoteExtension { extensions := make([]*tmproto.VoteExtension, 0, e.totalCount()) for _, t := range VoteExtensionTypes { for _, ext := range e[t] { - extensions = append(extensions, &tmproto.VoteExtension{ - Type: t, - Extension: ext.Extension, - Signature: ext.Signature, - }) + cloned := ext.Clone() + extensions = append(extensions, &cloned) } } return extensions diff --git a/types/vote_test.go b/types/vote_test.go index 9b2703bd99..b885acf675 100644 --- a/types/vote_test.go +++ b/types/vote_test.go @@ -40,7 +40,10 @@ func examplePrecommit(t testing.TB) *Vote { t.Helper() vote := exampleVote(t, byte(tmproto.PrecommitType)) vote.VoteExtensions = VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Signature: []byte("signature")}}, + tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{ + Type: tmproto.VoteExtensionType_DEFAULT, + Signature: []byte("signature"), + }}, } return vote } @@ -331,9 +334,11 @@ func TestVoteExtension(t *testing.T) { expectError bool }{ { - name: "all fields present", + name: "valid THRESHOLD_RECOVER", extensions: VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{Extension: []byte("extension")}}, + tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("extension")}}, }, includeSignature: true, expectError: false, @@ -341,7 +346,9 @@ func TestVoteExtension(t *testing.T) { { name: "no extension signature", extensions: VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{Extension: []byte("extension")}}, + tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("extension")}}, }, includeSignature: false, expectError: true, @@ -693,22 +700,24 @@ func TestVoteProtobuf(t *testing.T) { {"fail vote validate basic", &Vote{}, true, false}, } for _, tc := range testCases { - protoProposal := tc.vote.ToProto() + t.Run(tc.msg, func(t *testing.T) { + protoProposal := tc.vote.ToProto() - v, err := VoteFromProto(protoProposal) - if tc.convertsOk { - require.NoError(t, err) - } else { - require.Error(t, err) - } + v, err := VoteFromProto(protoProposal) + if tc.convertsOk { + require.NoError(t, err) + } else { + require.Error(t, err) + } - err = v.ValidateBasic() - if tc.passesValidateBasic { - require.NoError(t, err) - require.Equal(t, tc.vote, v, tc.msg) - } else { - require.Error(t, err) - } + err = v.ValidateBasic() + if tc.passesValidateBasic { + require.NoError(t, err) + require.Equal(t, tc.vote, v, tc.msg) + } else { + require.Error(t, err) + } + }) } } From 7ede91c350b17194395be9d7eb6ae6c93d96b256 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 13 Dec 2023 16:06:19 +0100 Subject: [PATCH 11/55] chore: self review --- abci/example/kvstore/verify.go | 4 --- abci/types/types.go | 4 +-- internal/consensus/common_test.go | 4 ++- internal/consensus/state_test.go | 10 +++++-- internal/consensus/vote_signer.go | 8 ++++-- internal/consensus/vote_signer_test.go | 5 +++- internal/test/factory/commit.go | 7 ++++- internal/test/factory/vote.go | 5 ++++ privval/file_test.go | 10 +++++-- privval/msgs_test.go | 4 ++- types/quorum_sign_data_test.go | 39 ++++++++++++++++++++++++-- types/test_util.go | 8 ++++-- types/vote_test.go | 4 ++- 13 files changed, 89 insertions(+), 23 deletions(-) diff --git a/abci/example/kvstore/verify.go b/abci/example/kvstore/verify.go index 4780375019..166fee948d 100644 --- a/abci/example/kvstore/verify.go +++ b/abci/example/kvstore/verify.go @@ -71,10 +71,6 @@ func makeVoteExtensionSignItems( items := make(map[types1.VoteExtensionType][]types.SignItem) protoExtensionsMap := types1.VoteExtensionsToMap(req.Commit.ThresholdVoteExtensions) for t, exts := range protoExtensionsMap { - if t == types1.VoteExtensionType_DEFAULT { - // DEFAULT vote extensions don't support signing - continue - } if items[t] == nil && len(exts) > 0 { items[t] = make([]types.SignItem, len(exts)) } diff --git a/abci/types/types.go b/abci/types/types.go index 07adde1ac8..5458b53f4d 100644 --- a/abci/types/types.go +++ b/abci/types/types.go @@ -377,11 +377,9 @@ func (m *ExtendVoteExtension) ToVoteExtension() types.VoteExtension { var requestID *types.VoteExtension_SignRequestId if m.XSignRequestId != nil { src := m.GetSignRequestId() - dst := make([]byte, len(src)) - copy(dst, src) requestID = &types.VoteExtension_SignRequestId{ - SignRequestId: dst, + SignRequestId: bytes.Clone(src), } } return types.VoteExtension{ diff --git a/internal/consensus/common_test.go b/internal/consensus/common_test.go index 5b725acd0c..ab0abea525 100644 --- a/internal/consensus/common_test.go +++ b/internal/consensus/common_test.go @@ -159,7 +159,9 @@ func signVote( quorumHash crypto.QuorumHash) *types.Vote { exts := make(types.VoteExtensions) if voteType == tmproto.PrecommitType && !blockID.IsNil() { - exts.Add(tmproto.VoteExtensionType_DEFAULT, tmproto.VoteExtension{Extension: []byte("extension")}) + exts.Add(tmproto.VoteExtensionType_DEFAULT, tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_DEFAULT, + Extension: []byte("extension")}) } v, err := vs.signVote(ctx, voteType, chainID, blockID, quorumType, quorumHash, exts) require.NoError(t, err, "failed to sign vote") diff --git a/internal/consensus/state_test.go b/internal/consensus/state_test.go index ff71f68ccb..54fb69b852 100644 --- a/internal/consensus/state_test.go +++ b/internal/consensus/state_test.go @@ -2455,10 +2455,16 @@ func TestPrepareProposalReceivesVoteExtensions(t *testing.T) { for _, vs := range vss[1:] { voteExtensions := types.VoteExtensions{ tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{ - {Extension: []byte("extension")}, + { + Type: tmproto.VoteExtensionType_DEFAULT, + Extension: []byte("extension"), + }, }, tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{ - {Extension: []byte("deterministic")}, + { + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("deterministic"), + }, }, } signAddPrecommitWithExtension(ctx, t, cs1, config.ChainID(), blockID, voteExtensions, vs) diff --git a/internal/consensus/vote_signer.go b/internal/consensus/vote_signer.go index 3f1e145a04..ed50018955 100644 --- a/internal/consensus/vote_signer.go +++ b/internal/consensus/vote_signer.go @@ -103,8 +103,12 @@ func (s *voteSigner) signVote( if err != nil { return nil, err } - // Deep copy vote extensions - vote.VoteExtensions = types.VoteExtensionsFromProto(protoVote.VoteExtensions) + + err = vote.PopulateSignsFromProto(protoVote) + if err != nil { + return nil, err + } + return vote, nil } diff --git a/internal/consensus/vote_signer_test.go b/internal/consensus/vote_signer_test.go index 829ab52125..c8779698e5 100644 --- a/internal/consensus/vote_signer_test.go +++ b/internal/consensus/vote_signer_test.go @@ -41,7 +41,10 @@ func TestVoteSigner_signAddVote(t *testing.T) { } voteExtensions := types.VoteExtensions{ tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{ - {Extension: tmbytes.MustHexDecode("524F1D03D1D81E94A099042736D40BD9681B867321443FF58A4568E274DBD83B")}, + { + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: tmbytes.MustHexDecode("524F1D03D1D81E94A099042736D40BD9681B867321443FF58A4568E274DBD83B"), + }, }, } conf := configSetup(t) diff --git a/internal/test/factory/commit.go b/internal/test/factory/commit.go index f1fb42b140..2b277d4a05 100644 --- a/internal/test/factory/commit.go +++ b/internal/test/factory/commit.go @@ -38,7 +38,12 @@ func MakeCommit( return nil, err } vote.BlockSignature = v.BlockSignature - vote.VoteExtensions = types.VoteExtensionsFromProto(v.VoteExtensions) + + err = vote.VoteExtensions.CopySignsFromProto(v.VoteExtensionsToMap()) + if err != nil { + return nil, err + } + if _, err := voteSet.AddVote(vote); err != nil { return nil, err } diff --git a/internal/test/factory/vote.go b/internal/test/factory/vote.go index 1cbd15e3dd..c8bcdeb88d 100644 --- a/internal/test/factory/vote.go +++ b/internal/test/factory/vote.go @@ -39,7 +39,12 @@ func MakeVote( } v.BlockSignature = vpb.BlockSignature + + err = v.VoteExtensions.CopySignsFromProto(vpb.VoteExtensionsToMap()) v.VoteExtensions = types.VoteExtensionsFromProto(vpb.VoteExtensions) + if err != nil { + return nil, err + } return v, nil } diff --git a/privval/file_test.go b/privval/file_test.go index 132d109cf3..1426abfb25 100644 --- a/privval/file_test.go +++ b/privval/file_test.go @@ -360,8 +360,12 @@ func TestVoteExtensionsAreAlwaysSigned(t *testing.T) { voteType := tmproto.PrecommitType exts := types.VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("extension")}}, + tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{ + Type: tmproto.VoteExtensionType_DEFAULT, + Extension: []byte("extension"), + }}, } + // We initially sign this vote without an extension vote1 := newVote(proTxHash, 0, height, round, voteType, blockID, exts) vpb1 := vote1.ToProto() @@ -378,7 +382,9 @@ func TestVoteExtensionsAreAlwaysSigned(t *testing.T) { // its extension vote2 := vote1.Copy() vote2.VoteExtensions = types.VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("new extension")}}, + tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{ + Type: tmproto.VoteExtensionType_DEFAULT, + Extension: []byte("new extension")}}, } vpb2 := vote2.ToProto() diff --git a/privval/msgs_test.go b/privval/msgs_test.go index 833d042b20..1072a6cf07 100644 --- a/privval/msgs_test.go +++ b/privval/msgs_test.go @@ -45,7 +45,9 @@ func exampleVote() *types.Vote { ValidatorProTxHash: crypto.ProTxHashFromSeedBytes([]byte("validator_pro_tx_hash")), ValidatorIndex: 56789, VoteExtensions: types.VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("extension")}}, + tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{ + Type: tmproto.VoteExtensionType_DEFAULT, + Extension: []byte("extension")}}, }, } } diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index df44786199..2cfc5e967a 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -1,7 +1,6 @@ package types import ( - "bytes" "encoding/hex" "fmt" "testing" @@ -72,8 +71,12 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { Height: 1001, ValidatorProTxHash: tmbytes.MustHexDecode("9CC13F685BC3EA0FCA99B87F42ABCC934C6305AA47F62A32266A2B9D55306B7B"), VoteExtensions: VoteExtensions{ - types.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("default")}}, - types.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{Extension: []byte("threshold")}}, + types.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{ + Type: tmproto.VoteExtensionType_DEFAULT, + Extension: []byte("default")}}, + types.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("threshold")}}, }, }, quorumHash: tmbytes.MustHexDecode("6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD"), @@ -118,6 +121,36 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { }) } } +func TestA(t *testing.T) { + llmq := btcjson.LLMQType_TEST_PLATFORM + + quorumHash, err := hex.DecodeString("dddabfe1c883dd8a2c71c4281a4212c3715a61f87d62a99aaed0f65a0506c053") + assert.NoError(t, err) + assert.Len(t, quorumHash, 32) + + requestID, err := hex.DecodeString("922a8fc39b6e265ca761eaaf863387a5e2019f4795a42260805f5562699fd9fa") + assert.NoError(t, err) + assert.Len(t, requestID, 32) + + extension, err := hex.DecodeString("7dfb2432d37f004c4eb2b9aebf601ba4ad59889b81d2e8c7029dce3e0bf8381c") + assert.NoError(t, err) + assert.Len(t, extension, 32) + + expected, err := hex.DecodeString("6d98f773cef8484432c4946c6b96e04aab39fd119c77de2f21d668dd17d5d2f6") + assert.NoError(t, err) + assert.Len(t, expected, 32) + + manual := []byte{uint8(llmq)} + manual = append(manual, tmbytes.Reverse(quorumHash)...) + manual = append(manual, tmbytes.Reverse(requestID)...) + manual = append(manual, tmbytes.Reverse(extension)...) + + t.Logf("before checksum: %x", manual) + sigHash := crypto.Checksum(crypto.Checksum(manual)) + sigHash = tmbytes.Reverse(sigHash) + + assert.EqualValues(t, expected, sigHash) +} // TestVoteExtensionsRawSignData checks signed data for a VoteExtensionType_THRESHOLD_RECOVER_RAW vote extension type. // diff --git a/types/test_util.go b/types/test_util.go index 9dfe62d281..e571a0b18c 100644 --- a/types/test_util.go +++ b/types/test_util.go @@ -46,8 +46,12 @@ func makeCommit( Type: tmproto.PrecommitType, BlockID: blockID, VoteExtensions: VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("default")}}, - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{Extension: []byte("threshold")}}, + tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{ + Type: tmproto.VoteExtensionType_DEFAULT, + Extension: []byte("default")}}, + tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("threshold")}}, }, } diff --git a/types/vote_test.go b/types/vote_test.go index b885acf675..5e9d992906 100644 --- a/types/vote_test.go +++ b/types/vote_test.go @@ -628,7 +628,9 @@ func TestInvalidPrecommitExtensions(t *testing.T) { "oversized vote extension signature", func(v *Vote) { v.VoteExtensions = VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{Signature: make([]byte, SignatureSize+1)}}, + tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Signature: make([]byte, SignatureSize+1)}}, } }, }, From 92779a1bac43a73ea055b01ccd82750eb01bbb1a Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 13 Dec 2023 16:23:56 +0100 Subject: [PATCH 12/55] chore: fix tests --- types/test_util.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/types/test_util.go b/types/test_util.go index e571a0b18c..324231eac8 100644 --- a/types/test_util.go +++ b/types/test_util.go @@ -73,7 +73,10 @@ func signAddVote(ctx context.Context, privVal PrivValidator, vote *Vote, voteSet return false, err } - vote.VoteExtensions = VoteExtensionsFromProto(v.VoteExtensions) + err = vote.PopulateSignsFromProto(v) + if err != nil { + return false, err + } return voteSet.AddVote(vote) } From d03eea93f1ffebd58cddf8fba671ab5bc1756761 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 13 Dec 2023 17:08:06 +0100 Subject: [PATCH 13/55] fix: tests --- internal/consensus/block_executor_test.go | 12 ++++++------ types/signs_recoverer_test.go | 8 +++++--- types/vote_extension.go | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/internal/consensus/block_executor_test.go b/internal/consensus/block_executor_test.go index 86d5a98c9f..6a2dd76887 100644 --- a/internal/consensus/block_executor_test.go +++ b/internal/consensus/block_executor_test.go @@ -20,7 +20,7 @@ import ( "github.com/dashpay/tenderdash/types/mocks" ) -type BockExecutorTestSuite struct { +type BlockExecutorTestSuite struct { suite.Suite blockExec *blockExecutor @@ -28,11 +28,11 @@ type BockExecutorTestSuite struct { mockBlockExec *smmocks.Executor } -func TestBockExecutor(t *testing.T) { - suite.Run(t, new(BockExecutorTestSuite)) +func TestBlockExecutor(t *testing.T) { + suite.Run(t, new(BlockExecutorTestSuite)) } -func (suite *BockExecutorTestSuite) SetupTest() { +func (suite *BlockExecutorTestSuite) SetupTest() { logger := log.NewTestingLogger(suite.T()) suite.mockPrivVal = mocks.NewPrivValidator(suite.T()) suite.mockBlockExec = smmocks.NewExecutor(suite.T()) @@ -47,7 +47,7 @@ func (suite *BockExecutorTestSuite) SetupTest() { } } -func (suite *BockExecutorTestSuite) TestCreate() { +func (suite *BlockExecutorTestSuite) TestCreate() { ctx := context.Background() commitH99R0 := &types.Commit{ Height: 99, @@ -137,7 +137,7 @@ func (suite *BockExecutorTestSuite) TestCreate() { } } -func (suite *BockExecutorTestSuite) TestProcess() { +func (suite *BlockExecutorTestSuite) TestProcess() { ctx := context.Background() const round = int32(0) wantDefaultCRS := sm.CurrentRoundState{ diff --git a/types/signs_recoverer_test.go b/types/signs_recoverer_test.go index 50ed1b3067..1f7a132496 100644 --- a/types/signs_recoverer_test.go +++ b/types/signs_recoverer_test.go @@ -137,11 +137,13 @@ func mockVoteExtensions(t *testing.T, pairs ...interface{}) VoteExtensions { } ve := make(VoteExtensions) for i := 0; i < len(pairs); i += 2 { - et, ok := pairs[i].(tmproto.VoteExtensionType) + extensionType, ok := pairs[i].(tmproto.VoteExtensionType) if !ok { t.Fatalf("given unsupported type %T", pairs[i]) } - ext := tmproto.VoteExtension{} + ext := tmproto.VoteExtension{ + Type: extensionType, + } switch v := pairs[i+1].(type) { case string: ext.Extension = []byte(v) @@ -150,7 +152,7 @@ func mockVoteExtensions(t *testing.T, pairs ...interface{}) VoteExtensions { default: t.Fatalf("given unsupported type %T", pairs[i+1]) } - ve[et] = append(ve[et], ext) + ve[extensionType] = append(ve[extensionType], ext) } return ve } diff --git a/types/vote_extension.go b/types/vote_extension.go index 3cd98826dd..15f94fbc10 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -10,7 +10,7 @@ import ( ) var ( - errUnableCopySigns = errors.New("unable copy signatures the sizes of extensions are not equal") + errUnableCopySigns = errors.New("unable to copy signatures: the sizes of extensions are not equal") ) // VoteExtensions is a container where the key is vote-extension type and value is a list of VoteExtension From 449a8f36d0a2b4b41e2fdbbe97f99178c52ec3a6 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 13 Dec 2023 17:38:41 +0100 Subject: [PATCH 14/55] chore: code cleanup --- types/quorum_sign_data_test.go | 56 +++------------------------------- 1 file changed, 4 insertions(+), 52 deletions(-) diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index 2cfc5e967a..aa16e6379e 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -121,42 +121,13 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { }) } } -func TestA(t *testing.T) { - llmq := btcjson.LLMQType_TEST_PLATFORM - - quorumHash, err := hex.DecodeString("dddabfe1c883dd8a2c71c4281a4212c3715a61f87d62a99aaed0f65a0506c053") - assert.NoError(t, err) - assert.Len(t, quorumHash, 32) - - requestID, err := hex.DecodeString("922a8fc39b6e265ca761eaaf863387a5e2019f4795a42260805f5562699fd9fa") - assert.NoError(t, err) - assert.Len(t, requestID, 32) - - extension, err := hex.DecodeString("7dfb2432d37f004c4eb2b9aebf601ba4ad59889b81d2e8c7029dce3e0bf8381c") - assert.NoError(t, err) - assert.Len(t, extension, 32) - - expected, err := hex.DecodeString("6d98f773cef8484432c4946c6b96e04aab39fd119c77de2f21d668dd17d5d2f6") - assert.NoError(t, err) - assert.Len(t, expected, 32) - - manual := []byte{uint8(llmq)} - manual = append(manual, tmbytes.Reverse(quorumHash)...) - manual = append(manual, tmbytes.Reverse(requestID)...) - manual = append(manual, tmbytes.Reverse(extension)...) - - t.Logf("before checksum: %x", manual) - sigHash := crypto.Checksum(crypto.Checksum(manual)) - sigHash = tmbytes.Reverse(sigHash) - - assert.EqualValues(t, expected, sigHash) -} // TestVoteExtensionsRawSignData checks signed data for a VoteExtensionType_THRESHOLD_RECOVER_RAW vote extension type. // // Given some vote extension, llmq type, quorum hash and sign request id, sign data should match predefined test vector. func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { - llmq := btcjson.LLMQType_TEST_PLATFORM + const chainID = "some-chain" + const llmqType = btcjson.LLMQType_TEST_PLATFORM quorumHash, err := hex.DecodeString("dddabfe1c883dd8a2c71c4281a4212c3715a61f87d62a99aaed0f65a0506c053") assert.NoError(t, err) @@ -173,18 +144,9 @@ func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { expected, err := hex.DecodeString("6d98f773cef8484432c4946c6b96e04aab39fd119c77de2f21d668dd17d5d2f6") assert.NoError(t, err) assert.Len(t, expected, 32) - - // quorumHash = tmbytes.Reverse(quorumHash) - // requestID = tmbytes.Reverse(requestID) - // extension = tmbytes.Reverse(extension) expected = tmbytes.Reverse(expected) - // extension := []byte{1, 2, 3, 4, 5, 6, 7, 8} - // quorumHash := bytes.Repeat([]byte{4, 3, 2, 1}, 8) - - // requestID := []byte("dpevote-someSignRequestID") - // llmq := btcjson.LLMQType_100_67 - chainID := "some-chain" + // Note: MakeVoteExtensionSignItems() calls MakeSignID(), which will reverse bytes in quorumHash, requestID and extension. ve := tmproto.VoteExtension{ Extension: extension, @@ -198,21 +160,11 @@ func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { signItems, err := MakeVoteExtensionSignItems(chainID, &tmproto.Vote{ Type: tmproto.PrecommitType, VoteExtensions: []*tmproto.VoteExtension{&ve}, - }, llmq, quorumHash) + }, llmqType, quorumHash) assert.NoError(t, err) item := signItems[tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW][0] actual := item.ID - // actual = crypto.Checksum(actual) - // SHA256(llmqType, quorumHash, ABCI_sign_requestId, ABCI_extension) - // blsSignHash := bls.BuildSignHash(uint8(llmqType), blsQuorumHash, blsRequestID, blsMessageHash) - - // expected := []byte{uint8(llmq)} - // expected = append(expected, tmbytes.Reverse(quorumHash)...) - // expected = append(expected, tmbytes.Reverse(crypto.Checksum(requestID))...) - // expected = append(expected, tmbytes.Reverse(crypto.Checksum(extension))...) - - // expected = crypto.Checksum(crypto.Checksum(expected)) t.Logf("sign bytes: %x", actual) assert.EqualValues(t, expected, actual) From 903b2aecb86395fdb38d0931539cc664b1c1d7d0 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 14 Dec 2023 12:51:33 +0100 Subject: [PATCH 15/55] feat: allow pwldtx prefix in sign_request_id --- abci/example/kvstore/verify.go | 5 ++++- proto/tendermint/abci/types.proto | 2 +- proto/tendermint/types/dash.go | 26 +++++++++++++++------- proto/tendermint/types/dash.proto | 2 +- types/quorum_sign_data.go | 5 ++++- types/vote.go | 36 +++++++++++++++---------------- types/vote_test.go | 13 +++++++++++ 7 files changed, 59 insertions(+), 30 deletions(-) diff --git a/abci/example/kvstore/verify.go b/abci/example/kvstore/verify.go index 166fee948d..6cc4de96d6 100644 --- a/abci/example/kvstore/verify.go +++ b/abci/example/kvstore/verify.go @@ -77,7 +77,10 @@ func makeVoteExtensionSignItems( chainID := req.Block.Header.ChainID for i, ext := range exts { raw := types.VoteExtensionSignBytes(chainID, req.Height, req.Round, ext) - reqID := types.VoteExtensionRequestID(ext, req.Height, req.Round) + reqID, err := types.VoteExtensionRequestID(ext, req.Height, req.Round) + if err != nil { + panic(fmt.Errorf("vote extension sign items: %w", err)) + } items[t][i] = types.NewSignItem(quorumType, quorumHash, reqID, raw) } diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 18a9f7f835..229e6ecd7d 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -675,7 +675,7 @@ message ExtendVoteExtension { // If not set, Tenderdash will generate it based on height and round. // - // If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` string. + // If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` or `plwdtx` string. // // Use with caution - it can have severe security consequences. optional bytes sign_request_id = 3; diff --git a/proto/tendermint/types/dash.go b/proto/tendermint/types/dash.go index 68739e62ba..255f774ad8 100644 --- a/proto/tendermint/types/dash.go +++ b/proto/tendermint/types/dash.go @@ -1,9 +1,9 @@ package types import ( + "bytes" "errors" fmt "fmt" - "strings" "github.com/dashpay/tenderdash/crypto/bls12381" ) @@ -12,11 +12,11 @@ import ( type VoteExtensions map[VoteExtensionType][]*VoteExtension var ( - errExtensionNil = errors.New("vote extension is nil") - errExtensionSignEmpty = errors.New("vote extension signature is missing") - errExtensionSignTooBig = fmt.Errorf("vote extension signature is too big (max: %d)", bls12381.SignatureSize) - errExtensionSignRequestIdNotSupported = errors.New("vote extension sign request id is not supported") - errExtensionSignRequestIdMissingPrefix = errors.New("vote extension sign request id must have dpevote prefix") + errExtensionNil = errors.New("vote extension is nil") + errExtensionSignEmpty = errors.New("vote extension signature is missing") + errExtensionSignTooBig = fmt.Errorf("vote extension signature is too big (max: %d)", bls12381.SignatureSize) + errExtensionSignRequestIdNotSupported = errors.New("vote extension sign request id is not supported") + errExtensionSignRequestIdWrongPrefix = errors.New("vote extension sign request id must have dpevote or plwdtx prefix") ) // Clone returns a copy of current vote-extension @@ -64,9 +64,19 @@ func (v *VoteExtension) Validate() error { if v.Type != VoteExtensionType_THRESHOLD_RECOVER_RAW { return errExtensionSignRequestIdNotSupported } + var validPrefixes = []string{"plwdtx", "dpevote"} requestID := v.GetSignRequestId() - if !strings.HasPrefix(string(requestID), "dpevote") { - return errExtensionSignRequestIdMissingPrefix + + var validPrefix bool + for _, prefix := range validPrefixes { + if bytes.HasPrefix(requestID, []byte(prefix)) { + validPrefix = true + break + } + } + + if !validPrefix { + return errExtensionSignRequestIdWrongPrefix } } diff --git a/proto/tendermint/types/dash.proto b/proto/tendermint/types/dash.proto index 41206a5ac2..e6112d5637 100644 --- a/proto/tendermint/types/dash.proto +++ b/proto/tendermint/types/dash.proto @@ -44,7 +44,7 @@ message VoteExtension { // If not set, Tenderdash will generate it based on height and round. // - // If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` string. + // If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` or `plwdtx` string. // // Use with caution - it can have severe security consequences. optional bytes sign_request_id = 4; diff --git a/types/quorum_sign_data.go b/types/quorum_sign_data.go index 2f81576dc4..04f1090707 100644 --- a/types/quorum_sign_data.go +++ b/types/quorum_sign_data.go @@ -116,7 +116,10 @@ func MakeVoteExtensionSignItems( } for i, ext := range exts { - reqID := VoteExtensionRequestID(ext, protoVote.Height, protoVote.Round) + reqID, err := VoteExtensionRequestID(ext, protoVote.Height, protoVote.Round) + if err != nil { + return nil, err + } raw := VoteExtensionSignBytes(chainID, protoVote.Height, protoVote.Round, ext) // TODO: this is to avoid sha256 of raw data, to be removed once we get into agreement on the format if ext.Type == types.VoteExtensionType_THRESHOLD_RECOVER_RAW { diff --git a/types/vote.go b/types/vote.go index 777319861a..3c5a815e63 100644 --- a/types/vote.go +++ b/types/vote.go @@ -42,19 +42,20 @@ func MaxVoteBytesForKeyType(keyType crypto.KeyType) int64 { } var ( - ErrVoteUnexpectedStep = errors.New("unexpected step") - ErrVoteInvalidValidatorIndex = errors.New("invalid validator index") - ErrVoteInvalidValidatorAddress = errors.New("invalid validator address") - ErrVoteInvalidSignature = errors.New("invalid signature") - ErrVoteInvalidBlockHash = errors.New("invalid block hash") - ErrVoteNonDeterministicSignature = errors.New("non-deterministic signature") - ErrVoteNil = errors.New("nil vote") - ErrVoteInvalidExtension = errors.New("invalid vote extension") - ErrVoteInvalidValidatorProTxHash = errors.New("invalid validator pro_tx_hash") - ErrVoteInvalidValidatorPubKeySize = errors.New("invalid validator public key size") - ErrVoteInvalidBlockSignature = errors.New("invalid block signature") - ErrVoteInvalidStateSignature = errors.New("invalid state signature") - ErrVoteStateSignatureShouldBeNil = errors.New("state signature when voting for nil block") + ErrVoteUnexpectedStep = errors.New("unexpected step") + ErrVoteInvalidValidatorIndex = errors.New("invalid validator index") + ErrVoteInvalidValidatorAddress = errors.New("invalid validator address") + ErrVoteInvalidSignature = errors.New("invalid signature") + ErrVoteInvalidBlockHash = errors.New("invalid block hash") + ErrVoteNonDeterministicSignature = errors.New("non-deterministic signature") + ErrVoteNil = errors.New("nil vote") + ErrVoteInvalidExtension = errors.New("invalid vote extension") + ErrVoteExtensionTypeWrongForRequestID = errors.New("provided vote extension type does not support sign request ID") + ErrVoteInvalidValidatorProTxHash = errors.New("invalid validator pro_tx_hash") + ErrVoteInvalidValidatorPubKeySize = errors.New("invalid validator public key size") + ErrVoteInvalidBlockSignature = errors.New("invalid block signature") + ErrVoteInvalidStateSignature = errors.New("invalid state signature") + ErrVoteStateSignatureShouldBeNil = errors.New("state signature when voting for nil block") ) type ErrVoteConflictingVotes struct { @@ -126,7 +127,7 @@ func VoteExtensionSignBytes(chainID string, height int64, round int32, ext *tmpr } // VoteExtensionRequestID returns vote extension request ID -func VoteExtensionRequestID(ext *tmproto.VoteExtension, height int64, round int32) []byte { +func VoteExtensionRequestID(ext *tmproto.VoteExtension, height int64, round int32) ([]byte, error) { if ext.XSignRequestId != nil && ext.XSignRequestId.Size() > 0 { if ext.Type == tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW { @@ -134,13 +135,12 @@ func VoteExtensionRequestID(ext *tmproto.VoteExtension, height int64, round int3 buf := make([]byte, 32) // this will ensure sign request ID has exactly 32 bytes copy(buf, ext.GetSignRequestId()) - return buf + return buf, nil } - - panic(fmt.Sprintf("unexpected sign request id for vote extension type %s", ext.Type.String())) + return nil, ErrVoteExtensionTypeWrongForRequestID } - return heightRoundRequestID("dpevote", height, round) + return heightRoundRequestID("dpevote", height, round), nil } // VoteBlockSignID returns signID that should be signed for the block diff --git a/types/vote_test.go b/types/vote_test.go index 5e9d992906..6b44fc4c2e 100644 --- a/types/vote_test.go +++ b/types/vote_test.go @@ -343,6 +343,19 @@ func TestVoteExtension(t *testing.T) { includeSignature: true, expectError: false, }, + { + name: "valid THRESHOLD_RECOVER_RAW", + extensions: VoteExtensions{ + tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW: []tmproto.VoteExtension{{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, + XSignRequestId: &tmproto.VoteExtension_SignRequestId{ + SignRequestId: []byte("plwdtx"), + }, + Extension: []byte("extension")}}, + }, + includeSignature: true, + expectError: false, + }, { name: "no extension signature", extensions: VoteExtensions{ From 58f0db173a3afe9b2bcaf0507d1cda5763229d14 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 14 Dec 2023 13:11:24 +0100 Subject: [PATCH 16/55] fix: return checksum of SignRequestId --- types/vote.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/types/vote.go b/types/vote.go index 3c5a815e63..aece55cea8 100644 --- a/types/vote.go +++ b/types/vote.go @@ -131,11 +131,7 @@ func VoteExtensionRequestID(ext *tmproto.VoteExtension, height int64, round int3 if ext.XSignRequestId != nil && ext.XSignRequestId.Size() > 0 { if ext.Type == tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW { - // TODO to avoid blind signing, we should have crypto.Checksum(signRequestID) here - buf := make([]byte, 32) - // this will ensure sign request ID has exactly 32 bytes - copy(buf, ext.GetSignRequestId()) - return buf, nil + return crypto.Checksum(ext.GetSignRequestId()), nil } return nil, ErrVoteExtensionTypeWrongForRequestID } From 9e1b291234a5382f330db6c3c5122ff85636a27b Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 14 Dec 2023 13:16:31 +0100 Subject: [PATCH 17/55] doc: update api spec --- spec/abci++/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/abci++/api.md b/spec/abci++/api.md index 2b2f95739b..ad67727b2e 100644 --- a/spec/abci++/api.md +++ b/spec/abci++/api.md @@ -168,7 +168,7 @@ Sign request ID that will be used to sign the vote extensions. Only applicable f Tenderdash will use SHA256 checksum of `sign_request_id` when generating quorum signatures of THRESHOLD_RECOVER_RAW vote extensions. It MUST NOT be set for any other vote extension types. | | sign_request_id | [bytes](#bytes) | optional | If not set, Tenderdash will generate it based on height and round. -If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` string. +If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` or `plwdtx` string. Use with caution - it can have severe security consequences. | From ed330eb1a894827650e71eab8e04ea83ca19592e Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 14 Dec 2023 14:17:28 +0100 Subject: [PATCH 18/55] chore: change prefix --- proto/tendermint/abci/types.proto | 2 +- proto/tendermint/types/dash.go | 4 +- proto/tendermint/types/dash.proto | 2 +- spec/abci++/api.md | 181 ++++++++++++++++++------------ types/vote_test.go | 17 ++- 5 files changed, 129 insertions(+), 77 deletions(-) diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 229e6ecd7d..2e1494b2a1 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -675,7 +675,7 @@ message ExtendVoteExtension { // If not set, Tenderdash will generate it based on height and round. // - // If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` or `plwdtx` string. + // If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` or `\x06plwdtx` prefix. // // Use with caution - it can have severe security consequences. optional bytes sign_request_id = 3; diff --git a/proto/tendermint/types/dash.go b/proto/tendermint/types/dash.go index 255f774ad8..312f391ee9 100644 --- a/proto/tendermint/types/dash.go +++ b/proto/tendermint/types/dash.go @@ -16,7 +16,7 @@ var ( errExtensionSignEmpty = errors.New("vote extension signature is missing") errExtensionSignTooBig = fmt.Errorf("vote extension signature is too big (max: %d)", bls12381.SignatureSize) errExtensionSignRequestIdNotSupported = errors.New("vote extension sign request id is not supported") - errExtensionSignRequestIdWrongPrefix = errors.New("vote extension sign request id must have dpevote or plwdtx prefix") + errExtensionSignRequestIdWrongPrefix = errors.New("vote extension sign request id must have dpevote or \\x06plwdtx prefix") ) // Clone returns a copy of current vote-extension @@ -64,7 +64,7 @@ func (v *VoteExtension) Validate() error { if v.Type != VoteExtensionType_THRESHOLD_RECOVER_RAW { return errExtensionSignRequestIdNotSupported } - var validPrefixes = []string{"plwdtx", "dpevote"} + var validPrefixes = []string{"\x06plwdtx", "dpevote"} requestID := v.GetSignRequestId() var validPrefix bool diff --git a/proto/tendermint/types/dash.proto b/proto/tendermint/types/dash.proto index e6112d5637..2e42a12fbb 100644 --- a/proto/tendermint/types/dash.proto +++ b/proto/tendermint/types/dash.proto @@ -44,7 +44,7 @@ message VoteExtension { // If not set, Tenderdash will generate it based on height and round. // - // If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` or `plwdtx` string. + // If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` or `\x06plwdtx` string. // // Use with caution - it can have severe security consequences. optional bytes sign_request_id = 4; diff --git a/spec/abci++/api.md b/spec/abci++/api.md index ad67727b2e..6c8579af66 100644 --- a/spec/abci++/api.md +++ b/spec/abci++/api.md @@ -1,70 +1,78 @@ # Protocol Documentation + ## Table of Contents -- [tendermint/abci/types.proto](#tendermint_abci_types-proto) - - [CommitInfo](#tendermint-abci-CommitInfo) - - [Event](#tendermint-abci-Event) - - [EventAttribute](#tendermint-abci-EventAttribute) - - [ExecTxResult](#tendermint-abci-ExecTxResult) - - [ExtendVoteExtension](#tendermint-abci-ExtendVoteExtension) - - [ExtendedVoteInfo](#tendermint-abci-ExtendedVoteInfo) - - [Misbehavior](#tendermint-abci-Misbehavior) - - [QuorumHashUpdate](#tendermint-abci-QuorumHashUpdate) - - [Request](#tendermint-abci-Request) - - [RequestApplySnapshotChunk](#tendermint-abci-RequestApplySnapshotChunk) - - [RequestCheckTx](#tendermint-abci-RequestCheckTx) - - [RequestEcho](#tendermint-abci-RequestEcho) - - [RequestExtendVote](#tendermint-abci-RequestExtendVote) - - [RequestFinalizeBlock](#tendermint-abci-RequestFinalizeBlock) - - [RequestFlush](#tendermint-abci-RequestFlush) - - [RequestInfo](#tendermint-abci-RequestInfo) - - [RequestInitChain](#tendermint-abci-RequestInitChain) - - [RequestListSnapshots](#tendermint-abci-RequestListSnapshots) - - [RequestLoadSnapshotChunk](#tendermint-abci-RequestLoadSnapshotChunk) - - [RequestOfferSnapshot](#tendermint-abci-RequestOfferSnapshot) - - [RequestPrepareProposal](#tendermint-abci-RequestPrepareProposal) - - [RequestProcessProposal](#tendermint-abci-RequestProcessProposal) - - [RequestQuery](#tendermint-abci-RequestQuery) - - [RequestVerifyVoteExtension](#tendermint-abci-RequestVerifyVoteExtension) - - [Response](#tendermint-abci-Response) - - [ResponseApplySnapshotChunk](#tendermint-abci-ResponseApplySnapshotChunk) - - [ResponseCheckTx](#tendermint-abci-ResponseCheckTx) - - [ResponseEcho](#tendermint-abci-ResponseEcho) - - [ResponseException](#tendermint-abci-ResponseException) - - [ResponseExtendVote](#tendermint-abci-ResponseExtendVote) - - [ResponseFinalizeBlock](#tendermint-abci-ResponseFinalizeBlock) - - [ResponseFlush](#tendermint-abci-ResponseFlush) - - [ResponseInfo](#tendermint-abci-ResponseInfo) - - [ResponseInitChain](#tendermint-abci-ResponseInitChain) - - [ResponseListSnapshots](#tendermint-abci-ResponseListSnapshots) - - [ResponseLoadSnapshotChunk](#tendermint-abci-ResponseLoadSnapshotChunk) - - [ResponseOfferSnapshot](#tendermint-abci-ResponseOfferSnapshot) - - [ResponsePrepareProposal](#tendermint-abci-ResponsePrepareProposal) - - [ResponseProcessProposal](#tendermint-abci-ResponseProcessProposal) - - [ResponseQuery](#tendermint-abci-ResponseQuery) - - [ResponseVerifyVoteExtension](#tendermint-abci-ResponseVerifyVoteExtension) - - [Snapshot](#tendermint-abci-Snapshot) - - [ThresholdPublicKeyUpdate](#tendermint-abci-ThresholdPublicKeyUpdate) - - [TxRecord](#tendermint-abci-TxRecord) - - [TxResult](#tendermint-abci-TxResult) - - [Validator](#tendermint-abci-Validator) - - [ValidatorSetUpdate](#tendermint-abci-ValidatorSetUpdate) - - [ValidatorUpdate](#tendermint-abci-ValidatorUpdate) - - [VoteInfo](#tendermint-abci-VoteInfo) - - - [CheckTxType](#tendermint-abci-CheckTxType) - - [MisbehaviorType](#tendermint-abci-MisbehaviorType) - - [ResponseApplySnapshotChunk.Result](#tendermint-abci-ResponseApplySnapshotChunk-Result) - - [ResponseOfferSnapshot.Result](#tendermint-abci-ResponseOfferSnapshot-Result) - - [ResponseProcessProposal.ProposalStatus](#tendermint-abci-ResponseProcessProposal-ProposalStatus) - - [ResponseVerifyVoteExtension.VerifyStatus](#tendermint-abci-ResponseVerifyVoteExtension-VerifyStatus) - - [TxRecord.TxAction](#tendermint-abci-TxRecord-TxAction) - - - [ABCIApplication](#tendermint-abci-ABCIApplication) - -- [Scalar Value Types](#scalar-value-types) +1. [Table of Contents](#table-of-contents) +2. [tendermint/abci/types.proto](#tendermintabcitypesproto) + 1. [CommitInfo](#commitinfo) + 2. [Event](#event) + 3. [EventAttribute](#eventattribute) + 4. [ExecTxResult](#exectxresult) + 5. [ExtendVoteExtension](#extendvoteextension) + 6. [ExtendedVoteInfo](#extendedvoteinfo) + 7. [Misbehavior](#misbehavior) + 8. [QuorumHashUpdate](#quorumhashupdate) + 9. [Request](#request) + 10. [RequestApplySnapshotChunk](#requestapplysnapshotchunk) + 11. [RequestCheckTx](#requestchecktx) + 12. [RequestEcho](#requestecho) + 13. [RequestExtendVote](#requestextendvote) + 1. [Usage](#usage) + 2. [When does Tenderdash call it?](#when-does-tenderdash-call-it) + 14. [RequestFinalizeBlock](#requestfinalizeblock) + 1. [Usage](#usage-1) + 15. [RequestFlush](#requestflush) + 16. [RequestInfo](#requestinfo) + 17. [RequestInitChain](#requestinitchain) + 18. [RequestListSnapshots](#requestlistsnapshots) + 19. [RequestLoadSnapshotChunk](#requestloadsnapshotchunk) + 20. [RequestOfferSnapshot](#requestoffersnapshot) + 21. [RequestPrepareProposal](#requestprepareproposal) + 1. [Usage](#usage-2) + 2. [When does Tenderdash call it?](#when-does-tenderdash-call-it-1) + 22. [RequestProcessProposal](#requestprocessproposal) + 1. [Usage](#usage-3) + 2. [When does Tenderdash call it?](#when-does-tenderdash-call-it-2) + 23. [RequestQuery](#requestquery) + 24. [RequestVerifyVoteExtension](#requestverifyvoteextension) + 1. [Usage](#usage-4) + 2. [When does Tenderdash call it?](#when-does-tenderdash-call-it-3) + 25. [Response](#response) + 26. [ResponseApplySnapshotChunk](#responseapplysnapshotchunk) + 27. [ResponseCheckTx](#responsechecktx) + 28. [ResponseEcho](#responseecho) + 29. [ResponseException](#responseexception) + 30. [ResponseExtendVote](#responseextendvote) + 31. [ResponseFinalizeBlock](#responsefinalizeblock) + 32. [ResponseFlush](#responseflush) + 33. [ResponseInfo](#responseinfo) + 34. [ResponseInitChain](#responseinitchain) + 35. [ResponseListSnapshots](#responselistsnapshots) + 36. [ResponseLoadSnapshotChunk](#responseloadsnapshotchunk) + 37. [ResponseOfferSnapshot](#responseoffersnapshot) + 38. [ResponsePrepareProposal](#responseprepareproposal) + 39. [ResponseProcessProposal](#responseprocessproposal) + 40. [ResponseQuery](#responsequery) + 41. [ResponseVerifyVoteExtension](#responseverifyvoteextension) + 42. [Snapshot](#snapshot) + 43. [ThresholdPublicKeyUpdate](#thresholdpublickeyupdate) + 44. [TxRecord](#txrecord) + 45. [TxResult](#txresult) + 46. [Validator](#validator) + 47. [ValidatorSetUpdate](#validatorsetupdate) + 48. [ValidatorUpdate](#validatorupdate) + 49. [VoteInfo](#voteinfo) + 50. [CheckTxType](#checktxtype) + 51. [MisbehaviorType](#misbehaviortype) + 52. [ResponseApplySnapshotChunk.Result](#responseapplysnapshotchunkresult) + 53. [ResponseOfferSnapshot.Result](#responseoffersnapshotresult) + 54. [ResponseProcessProposal.ProposalStatus](#responseprocessproposalproposalstatus) + 55. [ResponseVerifyVoteExtension.VerifyStatus](#responseverifyvoteextensionverifystatus) + 56. [TxRecord.TxAction](#txrecordtxaction) + 57. [ABCIApplication](#abciapplication) +3. [Scalar Value Types](#scalar-value-types) @@ -96,6 +104,7 @@ ### Event + Event allows application developers to attach additional information to ResponseCheckTx, ResponsePrepareProposal, ResponseProcessProposal and ResponseFinalizeBlock. @@ -116,6 +125,7 @@ Later, transactions may be queried using these events. ### EventAttribute + EventAttribute is a single key-value pair, associated with an event. @@ -133,6 +143,7 @@ EventAttribute is a single key-value pair, associated with an event. ### ExecTxResult + ExecTxResult contains results of executing one individual transaction. @@ -155,6 +166,7 @@ ExecTxResult contains results of executing one individual transaction. ### ExtendVoteExtension + Provides a vote extension for signing. `type` and `extension` fields are mandatory for filling @@ -168,7 +180,7 @@ Sign request ID that will be used to sign the vote extensions. Only applicable f Tenderdash will use SHA256 checksum of `sign_request_id` when generating quorum signatures of THRESHOLD_RECOVER_RAW vote extensions. It MUST NOT be set for any other vote extension types. | | sign_request_id | [bytes](#bytes) | optional | If not set, Tenderdash will generate it based on height and round. -If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` or `plwdtx` string. +If set, it SHOULD be unique per voting round, and it MUST start with `\x06dpevote` or `plwdtx` string. Use with caution - it can have severe security consequences. | @@ -180,6 +192,7 @@ Use with caution - it can have severe security consequences. | ### ExtendedVoteInfo + ExtendedVoteInfo @@ -206,7 +219,7 @@ ExtendedVoteInfo | validator | [Validator](#tendermint-abci-Validator) | | The offending validator | | height | [int64](#int64) | | The height when the offense occurred | | time | [google.protobuf.Timestamp](#google-protobuf-Timestamp) | | The corresponding time where the offense occurred | -| total_voting_power | [int64](#int64) | | Total voting power of the validator set in case the ABCI application does not store historical validators. https://github.com/tendermint/tendermint/issues/4581 | +| total_voting_power | [int64](#int64) | | Total voting power of the validator set in case the ABCI application does not store historical validators. | @@ -231,6 +244,7 @@ ExtendedVoteInfo ### Request + Request types @@ -260,6 +274,7 @@ Request types ### RequestApplySnapshotChunk + Applies a snapshot chunk. - The application can choose to refetch chunks and/or ban P2P peers as appropriate. @@ -288,6 +303,7 @@ Applies a snapshot chunk. ### RequestCheckTx + Check if transaction is valid. - Technically optional - not involved in processing blocks. @@ -313,6 +329,7 @@ Check if transaction is valid. ### RequestEcho + Echo a string to test an abci client/server implementation @@ -328,6 +345,7 @@ Echo a string to test an abci client/server implementation ### RequestExtendVote + Extends a vote with application-side injection #### Usage @@ -379,6 +397,7 @@ a [CanonicalVoteExtension](#canonicalvoteextension) field in the `precommit nil` ### RequestFinalizeBlock + Finalize newly decided block. #### Usage @@ -425,6 +444,7 @@ Finalize newly decided block. ### RequestFlush + Signals that messages queued on the client should be flushed to the server. It is called periodically by the client implementation to ensure asynchronous requests are actually sent, and is called immediately to make a synchronous request, @@ -438,6 +458,7 @@ which returns when the Flush response comes back. ### RequestInfo + Return information about the application state. Used to sync Tenderdash with the application during a handshake that happens on startup. @@ -461,6 +482,7 @@ ensuring that Commit is never called twice for the same block height. ### RequestInitChain + Called once upon genesis. - If ResponseInitChain.Validators is empty, the initial validator set will be the RequestInitChain.Validators @@ -489,6 +511,7 @@ Called once upon genesis. ### RequestListSnapshots + Lists available snapshots - Used during state sync to discover available snapshots on peers. @@ -502,6 +525,7 @@ Lists available snapshots ### RequestLoadSnapshotChunk + Used during state sync to retrieve snapshot chunks from peers. @@ -519,6 +543,7 @@ Used during state sync to retrieve snapshot chunks from peers. ### RequestOfferSnapshot + Offers a snapshot to the application. - OfferSnapshot is called when bootstrapping a node using state sync. The application may accept or reject snapshots @@ -544,6 +569,7 @@ Offers a snapshot to the application. ### RequestPrepareProposal + Prepare new block proposal, potentially altering list of transactions. #### Usage @@ -652,6 +678,7 @@ Note that, if _p_ has a non-`nil` _validValue_, Tenderdash will use it as propos ### RequestProcessProposal + Process prepared proposal. #### Usage @@ -722,6 +749,7 @@ When a validator _p_ enters Tenderdash consensus round _r_, height _h_, in which ### RequestQuery + Query for data from the application at current or past height. - Optionally return Merkle proof. @@ -743,6 +771,7 @@ Query for data from the application at current or past height. ### RequestVerifyVoteExtension + Verify the vote extension #### Usage @@ -766,14 +795,17 @@ When a validator _p_ is in Tenderdash consensus round _r_, height _h_, state _pr from this condition, but not sure), and _p_ receives a Precommit message for round _r_, height _h_ from _q_: 1. If the Precommit message does not contain a vote extensions with a valid signature, Tenderdash discards the message as invalid. - - a 0-length vote extensions is valid as long as its accompanying signature is also valid. + +- a 0-length vote extensions is valid as long as its accompanying signature is also valid. + 2. Else, _p_'s Tenderdash calls `RequestVerifyVoteExtension`. 3. The Application returns _accept_ or _reject_ via `ResponseVerifyVoteExtension.status`. 4. If the Application returns - - _accept_, _p_'s Tenderdash will keep the received vote, together with its corresponding + +- _accept_, _p_'s Tenderdash will keep the received vote, together with its corresponding vote extension in its internal data structures. It will be used to populate the [ExtendedCommitInfo](#extendedcommitinfo) structure in calls to `RequestPrepareProposal`, in rounds of height _h + 1_ where _p_ is the proposer. - - _reject_, _p_'s Tenderdash will deem the Precommit message invalid and discard it. +- _reject_, _p_'s Tenderdash will deem the Precommit message invalid and discard it. | Field | Type | Label | Description | @@ -876,6 +908,7 @@ from this condition, but not sure), and _p_ receives a Precommit message for rou ### ResponseException + nondeterministic @@ -1141,6 +1174,7 @@ nondeterministic ### TxResult + TxResult contains results of executing the transaction. One usage is indexing transaction results. @@ -1161,6 +1195,7 @@ One usage is indexing transaction results. ### Validator + Validator @@ -1194,6 +1229,7 @@ Validator ### ValidatorUpdate + ValidatorUpdate @@ -1212,6 +1248,7 @@ ValidatorUpdate ### VoteInfo + VoteInfo @@ -1224,12 +1261,13 @@ VoteInfo - + ### CheckTxType + Type of transaction check | Name | Number | Description | @@ -1314,6 +1352,7 @@ Type of transaction check ### TxRecord.TxAction + TxAction contains App-provided information on what to do with a transaction that is part of a raw proposal | Name | Number | Description | @@ -1325,9 +1364,9 @@ TxAction contains App-provided information on what to do with a transaction that | DELAYED | 4 | The Application wants this transaction removed from the proposal but not the mempool. | - - + + @@ -1353,7 +1392,7 @@ TxAction contains App-provided information on what to do with a transaction that | VerifyVoteExtension | [RequestVerifyVoteExtension](#tendermint-abci-RequestVerifyVoteExtension) | [ResponseVerifyVoteExtension](#tendermint-abci-ResponseVerifyVoteExtension) | | | FinalizeBlock | [RequestFinalizeBlock](#tendermint-abci-RequestFinalizeBlock) | [ResponseFinalizeBlock](#tendermint-abci-ResponseFinalizeBlock) | | - + diff --git a/types/vote_test.go b/types/vote_test.go index 6b44fc4c2e..e0cbd8a6ae 100644 --- a/types/vote_test.go +++ b/types/vote_test.go @@ -344,12 +344,25 @@ func TestVoteExtension(t *testing.T) { expectError: false, }, { - name: "valid THRESHOLD_RECOVER_RAW", + name: "valid THRESHOLD_RECOVER_RAW plwdtx", extensions: VoteExtensions{ tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW: []tmproto.VoteExtension{{ Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, XSignRequestId: &tmproto.VoteExtension_SignRequestId{ - SignRequestId: []byte("plwdtx"), + SignRequestId: []byte("\x06plwdtx"), + }, + Extension: []byte("extension")}}, + }, + includeSignature: true, + expectError: false, + }, + { + name: "valid THRESHOLD_RECOVER_RAW dpevote", + extensions: VoteExtensions{ + tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW: []tmproto.VoteExtension{{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, + XSignRequestId: &tmproto.VoteExtension_SignRequestId{ + SignRequestId: []byte("dpevote"), }, Extension: []byte("extension")}}, }, From ca7be853012e2ba0935c1c620634564c7730a3c2 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 15 Dec 2023 16:22:56 +0100 Subject: [PATCH 19/55] refactor: sign item refactoring and removal of reversals in sign id --- privval/dash_core_signer_client.go | 7 +- types/quorum_sign_data.go | 100 +++++++++++++++++++++-------- types/quorum_sign_data_test.go | 7 +- types/vote.go | 5 +- 4 files changed, 85 insertions(+), 34 deletions(-) diff --git a/privval/dash_core_signer_client.go b/privval/dash_core_signer_client.go index 56185952b4..775ede08eb 100644 --- a/privval/dash_core_signer_client.go +++ b/privval/dash_core_signer_client.go @@ -314,11 +314,8 @@ func (sc *DashCoreSignerClient) QuorumSign( quorumType btcjson.LLMQType, quorumHash crypto.QuorumHash, ) ([]byte, []byte, error) { - signItem := types.SignItem{ - ReqID: requestIDHash, - ID: types.MakeSignID(msgHash, requestIDHash, quorumType, quorumHash), - Hash: msgHash, - } + signItem := types.NewSignItemFromHash(quorumType, quorumHash, requestIDHash, msgHash) + qs, err := sc.quorumSignAndVerify(ctx, quorumType, quorumHash, signItem) if err != nil { return nil, nil, err diff --git a/types/quorum_sign_data.go b/types/quorum_sign_data.go index 04f1090707..2d2ee9afd9 100644 --- a/types/quorum_sign_data.go +++ b/types/quorum_sign_data.go @@ -1,14 +1,15 @@ package types import ( + "bytes" "errors" "fmt" + "testing" "github.com/dashpay/dashd-go/btcjson" "github.com/rs/zerolog" "github.com/dashpay/tenderdash/crypto" - tmbytes "github.com/dashpay/tenderdash/libs/bytes" "github.com/dashpay/tenderdash/proto/tendermint/types" ) @@ -29,10 +30,12 @@ func (q QuorumSignData) Verify(pubKey crypto.PubKey, signs QuorumSigns) error { // SignItem represents quorum sign data, like a request id, message bytes, sha256 hash of message and signID type SignItem struct { - ReqID []byte // Request ID for quorum signing - ID []byte // Signature ID - Raw []byte // Raw data to be signed - Hash []byte // Checksum of Raw + ReqID []byte // Request ID for quorum signing + ID []byte // Signature ID + Raw []byte // Raw data to be signed + Hash []byte // Checksum of Raw + QuorumType btcjson.LLMQType // Quorum type for which this sign item is created + QuorumHash []byte // Quorum hash for which this sign item is created } // Validate validates prepared data for signing @@ -40,6 +43,17 @@ func (i *SignItem) Validate() error { if len(i.ReqID) != crypto.DefaultHashSize { return fmt.Errorf("invalid request ID size: %X", i.ReqID) } + if len(i.Hash) != crypto.DefaultHashSize { + return fmt.Errorf("invalid hash size: %X", i.ReqID) + } + if len(i.QuorumHash) != crypto.DefaultHashSize { + return fmt.Errorf("invalid quorum hash size: %X", i.ReqID) + } + if len(i.Raw) > 0 { + if !bytes.Equal(crypto.Checksum(i.Raw), i.Hash) { + return fmt.Errorf("invalid hash %X for raw data: %X", i.Hash, i.Raw) + } + } return nil } @@ -123,15 +137,10 @@ func MakeVoteExtensionSignItems( raw := VoteExtensionSignBytes(chainID, protoVote.Height, protoVote.Round, ext) // TODO: this is to avoid sha256 of raw data, to be removed once we get into agreement on the format if ext.Type == types.VoteExtensionType_THRESHOLD_RECOVER_RAW { - // ensure we have exactly 32 bytes, cut or fill with 0s if it's not - msgHash := make([]byte, 32) - copy(msgHash, raw) - items[t][i] = SignItem{ - ReqID: reqID, - ID: MakeSignID(raw, reqID, quorumType, quorumHash), - Raw: raw, - Hash: msgHash, - } + // for this vote extension type, we just sign raw data from extension + msgHash := bytes.Clone(raw) + items[t][i] = NewSignItemFromHash(quorumType, quorumHash, reqID, msgHash) + items[t][i].Raw = raw } else { items[t][i] = NewSignItem(quorumType, quorumHash, reqID, raw) } @@ -141,22 +150,61 @@ func MakeVoteExtensionSignItems( } // NewSignItem creates a new instance of SignItem with calculating a hash for a raw and creating signID +// +// Arguments: +// - quorumType: quorum type +// - quorumHash: quorum hash +// - reqID: sign request ID +// - raw: raw data to be signed; it will be hashed with crypto.Checksum() func NewSignItem(quorumType btcjson.LLMQType, quorumHash, reqID, raw []byte) SignItem { msgHash := crypto.Checksum(raw) - return SignItem{ - ReqID: reqID, - ID: MakeSignID(msgHash, reqID, quorumType, quorumHash), - Raw: raw, - Hash: msgHash, + item := NewSignItemFromHash(quorumType, quorumHash, reqID, msgHash) + item.Raw = raw + + return item +} + +// Create a new sign item without raw value, using provided hash. +func NewSignItemFromHash(quorumType btcjson.LLMQType, quorumHash, reqID, msgHash []byte) SignItem { + item := SignItem{ + ReqID: reqID, + Hash: msgHash, + QuorumType: quorumType, + QuorumHash: quorumHash, + Raw: nil, // Raw is empty, as we don't have it } + item.UpdateID() + + return item } -// MakeSignID creates singID -func MakeSignID(msgHash, reqID []byte, quorumType btcjson.LLMQType, quorumHash []byte) []byte { - return crypto.SignID( - quorumType, - tmbytes.Reverse(quorumHash), - tmbytes.Reverse(reqID), - tmbytes.Reverse(msgHash), +func (i *SignItem) UpdateID() { + if err := i.Validate(); err != nil { + panic("invalid sign item: " + err.Error()) + } + // FIXME: previously we had reversals, but this doesn't work with Core test vectors + // So + // quorumHash := tmbytes.Reverse(i.QuorumHash) + quorumHash := i.QuorumHash + // requestID := tmbytes.Reverse(i.ReqID) + requestID := i.ReqID + // messageHash := tmbytes.Reverse(i.Hash) + messageHash := i.Hash + + if testing.Testing() { + fmt.Printf("generating sign ID using bls.BuildSignHash for %d %X %X %X\n", i.QuorumType, quorumHash, requestID, messageHash) + out := append([]byte{byte(i.QuorumType)}, quorumHash...) + out = append(out, requestID...) + out = append(out, messageHash...) + + fmt.Printf("data before sha256: %X\n", out) + fmt.Printf("sha256(sha256(data)): %X\n", crypto.Checksum((crypto.Checksum(out)))) + + } + i.ID = crypto.SignID( + i.QuorumType, + quorumHash, + requestID, + messageHash, ) } diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index aa16e6379e..dc18c58ffc 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -9,7 +9,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/dashpay/tenderdash/crypto" tmbytes "github.com/dashpay/tenderdash/libs/bytes" "github.com/dashpay/tenderdash/libs/log" "github.com/dashpay/tenderdash/proto/tendermint/types" @@ -42,6 +41,8 @@ func TestMakeBlockSignID(t *testing.T) { "DA25B746781DDF47B5D736F30B1D9D0CC86981EEC67CBE255265C4361DEF8C2E", "02000000E9030000000000000000000000000000E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B"+ "7852B855E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855646173682D706C6174666F726D", + "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", + btcjson.LLMQType_5_60, ), wantHash: tmbytes.MustHexDecode("0CA3D5F42BDFED0C4FDE7E6DE0F046CC76CDA6CEE734D65E8B2EE0E375D4C57D"), }, @@ -86,6 +87,8 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { "FB95F2CA6530F02AC623589D7938643FF22AE79A75DD79AEA1C8871162DE675E", "533524404D3A905F5AC9A30FCEB5A922EAD96F30DA02F979EE41C4342F540467", "210A0764656661756C7411E903000000000000220D646173682D706C6174666F726D", + "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", + btcjson.LLMQType_5_60, ), }, types.VoteExtensionType_THRESHOLD_RECOVER: { @@ -93,6 +96,8 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { "fb95f2ca6530f02ac623589d7938643ff22ae79a75dd79aea1c8871162de675e", "d3b7d53a0f9ca8072d47d6c18e782ee3155ef8dcddb010087030b6cbc63978bc", "250a097468726573686f6c6411e903000000000000220d646173682d706c6174666f726d2801", + "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", + btcjson.LLMQType_5_60, ), }, }, diff --git a/types/vote.go b/types/vote.go index aece55cea8..2f7123f497 100644 --- a/types/vote.go +++ b/types/vote.go @@ -126,12 +126,13 @@ func VoteExtensionSignBytes(chainID string, height int64, round int32, ext *tmpr return bz } -// VoteExtensionRequestID returns vote extension request ID +// VoteExtensionRequestID returns vote extension sign request ID used to generate +// threshold signatures func VoteExtensionRequestID(ext *tmproto.VoteExtension, height int64, round int32) ([]byte, error) { if ext.XSignRequestId != nil && ext.XSignRequestId.Size() > 0 { if ext.Type == tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW { - return crypto.Checksum(ext.GetSignRequestId()), nil + return crypto.Checksum(crypto.Checksum(ext.GetSignRequestId())), nil } return nil, ErrVoteExtensionTypeWrongForRequestID } From 4da18ba8a751928d8263d3ad54d7369c9056e62d Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 15 Dec 2023 16:23:57 +0100 Subject: [PATCH 20/55] test: update test vectors in TestVoteExtensionsRawSignDataRawVector --- types/quorum_sign_data_test.go | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index dc18c58ffc..6628b33b26 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -146,10 +146,13 @@ func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { assert.NoError(t, err) assert.Len(t, extension, 32) - expected, err := hex.DecodeString("6d98f773cef8484432c4946c6b96e04aab39fd119c77de2f21d668dd17d5d2f6") + extension = []byte{192, 37, 45, 64, 121, 74, 111, 51, 205, 98, 131, 161, 46, 118, 67, 43, 230, 124, 152, 192, 116, 136, 97, 125, 135, 163, 168, 131, 139, 120, 59, 42} + requestID = []byte{6, 112, 108, 119, 100, 116, 120, 0, 0, 0, 0, 0, 0, 0, 0} + + expected, err := hex.DecodeString("B7561730665DBD53A1947265CA5B78A3556B27DA5AB9264630A8E03918915397") assert.NoError(t, err) assert.Len(t, expected, 32) - expected = tmbytes.Reverse(expected) + // expected = tmbytes.Reverse(expected) // Note: MakeVoteExtensionSignItems() calls MakeSignID(), which will reverse bytes in quorumHash, requestID and extension. @@ -171,16 +174,18 @@ func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { item := signItems[tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW][0] actual := item.ID - t.Logf("sign bytes: %x", actual) + t.Logf("LLMQ type: %s (%d)\n", llmqType.Name(), llmqType) + t.Logf("extension: %X\n", extension) + t.Logf("sign requestID: %X\n", requestID) + t.Logf("quorum hash: %X\n", quorumHash) + + t.Logf("RESULT: sign bytes: %X", actual) assert.EqualValues(t, expected, actual) + } -func newSignItem(reqID, ID, raw string) SignItem { - item := SignItem{ - ReqID: tmbytes.MustHexDecode(reqID), - ID: tmbytes.MustHexDecode(ID), - Raw: tmbytes.MustHexDecode(raw), - } - item.Hash = crypto.Checksum(item.Raw) +func newSignItem(reqID, ID, raw, quorumHash string, quorumType btcjson.LLMQType) SignItem { + item := NewSignItem(quorumType, tmbytes.MustHexDecode(quorumHash), tmbytes.MustHexDecode(reqID), tmbytes.MustHexDecode(raw)) + item.ID = tmbytes.MustHexDecode(ID) return item } From b9071af489f86639f7705ffe0314b70a68e7e131 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 15 Dec 2023 17:05:21 +0100 Subject: [PATCH 21/55] refactor: SIgnItem moved to crypto and replaces all crypto.SignID calls --- abci/example/kvstore/verify.go | 13 +-- crypto/quorum.go | 99 +++++++++++++++++- dash/core/mock.go | 16 +-- internal/consensus/vote_signer.go | 2 +- internal/consensus/vote_signer_test.go | 8 +- privval/dash_consensus_key.go | 9 +- privval/dash_core_signer_client.go | 8 +- test/e2e/pkg/mockcoreserver/core_server.go | 15 +-- types/proposal.go | 7 +- types/quorum_sign_data.go | 116 ++------------------- types/quorum_sign_data_test.go | 11 +- 11 files changed, 135 insertions(+), 169 deletions(-) diff --git a/abci/example/kvstore/verify.go b/abci/example/kvstore/verify.go index 6cc4de96d6..01826a4cee 100644 --- a/abci/example/kvstore/verify.go +++ b/abci/example/kvstore/verify.go @@ -7,6 +7,7 @@ import ( "github.com/dashpay/dashd-go/btcjson" abci "github.com/dashpay/tenderdash/abci/types" + "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/crypto/encoding" tmbytes "github.com/dashpay/tenderdash/libs/bytes" types1 "github.com/dashpay/tenderdash/proto/tendermint/types" @@ -50,7 +51,7 @@ func makeBlockSignItem( req *abci.RequestFinalizeBlock, quorumType btcjson.LLMQType, quorumHash []byte, -) types.SignItem { +) crypto.SignItem { reqID := types.BlockRequestID(req.Height, req.Round) cv, err := req.ToCanonicalVote() if err != nil { @@ -60,19 +61,19 @@ func makeBlockSignItem( if err != nil { panic(fmt.Errorf("block sign item: %w", err)) } - return types.NewSignItem(quorumType, quorumHash, reqID, raw) + return crypto.NewSignItem(quorumType, quorumHash, reqID, raw) } func makeVoteExtensionSignItems( req *abci.RequestFinalizeBlock, quorumType btcjson.LLMQType, quorumHash []byte, -) map[types1.VoteExtensionType][]types.SignItem { - items := make(map[types1.VoteExtensionType][]types.SignItem) +) map[types1.VoteExtensionType][]crypto.SignItem { + items := make(map[types1.VoteExtensionType][]crypto.SignItem) protoExtensionsMap := types1.VoteExtensionsToMap(req.Commit.ThresholdVoteExtensions) for t, exts := range protoExtensionsMap { if items[t] == nil && len(exts) > 0 { - items[t] = make([]types.SignItem, len(exts)) + items[t] = make([]crypto.SignItem, len(exts)) } chainID := req.Block.Header.ChainID for i, ext := range exts { @@ -82,7 +83,7 @@ func makeVoteExtensionSignItems( panic(fmt.Errorf("vote extension sign items: %w", err)) } - items[t][i] = types.NewSignItem(quorumType, quorumHash, reqID, raw) + items[t][i] = crypto.NewSignItem(quorumType, quorumHash, reqID, raw) } } return items diff --git a/crypto/quorum.go b/crypto/quorum.go index 70b0753611..c9dafd57fb 100644 --- a/crypto/quorum.go +++ b/crypto/quorum.go @@ -1,15 +1,106 @@ package crypto import ( + "bytes" + "fmt" + bls "github.com/dashpay/bls-signatures/go-bindings" "github.com/dashpay/dashd-go/btcjson" + "github.com/rs/zerolog" ) -// SignID returns signing session data that will be signed to get threshold signature share. +// SignItem represents signing session data (in field SignItem.ID) that will be signed to get threshold signature share. // See DIP-0007 -func SignID(llmqType btcjson.LLMQType, quorumHash QuorumHash, requestID []byte, messageHash []byte) []byte { +type SignItem struct { + ReqID []byte // Request ID for quorum signing + ID []byte // Signature ID + Raw []byte // Raw data to be signed + Hash []byte // Checksum of Raw + QuorumType btcjson.LLMQType // Quorum type for which this sign item is created + QuorumHash []byte // Quorum hash for which this sign item is created +} + +// Validate validates prepared data for signing +func (i *SignItem) Validate() error { + if len(i.ReqID) != DefaultHashSize { + return fmt.Errorf("invalid request ID size: %X", i.ReqID) + } + if len(i.Hash) != DefaultHashSize { + return fmt.Errorf("invalid hash size: %X", i.ReqID) + } + if len(i.QuorumHash) != DefaultHashSize { + return fmt.Errorf("invalid quorum hash size: %X", i.ReqID) + } + if len(i.Raw) > 0 { + if !bytes.Equal(Checksum(i.Raw), i.Hash) { + return fmt.Errorf("invalid hash %X for raw data: %X", i.Hash, i.Raw) + } + } + return nil +} + +func (i SignItem) MarshalZerologObject(e *zerolog.Event) { + e.Hex("signBytes", i.Raw) + e.Hex("signRequestID", i.ReqID) + e.Hex("signID", i.ID) + e.Hex("signHash", i.Hash) +} + +// NewSignItem creates a new instance of SignItem with calculating a hash for a raw and creating signID +// +// Arguments: +// - quorumType: quorum type +// - quorumHash: quorum hash +// - reqID: sign request ID +// - raw: raw data to be signed; it will be hashed with crypto.Checksum() +func NewSignItem(quorumType btcjson.LLMQType, quorumHash, reqID, raw []byte) SignItem { + msgHash := Checksum(raw) + item := NewSignItemFromHash(quorumType, quorumHash, reqID, msgHash) + item.Raw = raw + + return item +} + +// Create a new sign item without raw value, using provided hash. +func NewSignItemFromHash(quorumType btcjson.LLMQType, quorumHash, reqID, msgHash []byte) SignItem { + item := SignItem{ + ReqID: reqID, + Hash: msgHash, + QuorumType: quorumType, + QuorumHash: quorumHash, + Raw: nil, // Raw is empty, as we don't have it + } + item.UpdateID() + + return item +} + +func (i *SignItem) UpdateID() { + if err := i.Validate(); err != nil { + panic("invalid sign item: " + err.Error()) + } + // FIXME: previously we had reversals, but this doesn't work with Core test vectors + // So + // quorumHash := tmbytes.Reverse(i.QuorumHash) + quorumHash := i.QuorumHash + // requestID := tmbytes.Reverse(i.ReqID) + requestID := i.ReqID + // messageHash := tmbytes.Reverse(i.Hash) + messageHash := i.Hash + + llmqType := i.QuorumType + + // if testing.Testing() { + // fmt.Printf("generating sign ID using bls.BuildSignHash for %d %X %X %X\n", llmqType, quorumHash, requestID, messageHash) + // out := append([]byte{byte(llmqType)}, quorumHash...) + // out = append(out, requestID...) + // out = append(out, messageHash...) + + // fmt.Printf("data before sha256: %X\n", out) + // fmt.Printf("sha256(sha256(data)): %X\n", crypto.Checksum((crypto.Checksum(out)))) + // } var blsQuorumHash bls.Hash - copy(blsQuorumHash[:], quorumHash.Bytes()) + copy(blsQuorumHash[:], quorumHash) var blsRequestID bls.Hash copy(blsRequestID[:], requestID) @@ -22,5 +113,5 @@ func SignID(llmqType btcjson.LLMQType, quorumHash QuorumHash, requestID []byte, signHash := make([]byte, 32) copy(signHash, blsSignHash[:]) - return signHash + i.ID = signHash } diff --git a/dash/core/mock.go b/dash/core/mock.go index e396f646a7..4d9f07eb80 100644 --- a/dash/core/mock.go +++ b/dash/core/mock.go @@ -152,13 +152,8 @@ func (mc *MockClient) QuorumSign( if !mc.canSign { return nil, errors.New("dash core mock client not set up for signing") } + signID := crypto.NewSignItemFromHash(quorumType, quorumHash, requestID, messageHash).ID - signID := crypto.SignID( - quorumType, - tmbytes.Reverse(quorumHash), - tmbytes.Reverse(requestID), - tmbytes.Reverse(messageHash), - ) privateKey, err := mc.localPV.GetPrivateKey(context.Background(), quorumHash) if err != nil { panic(err) @@ -190,12 +185,9 @@ func (mc *MockClient) QuorumVerify( if err := quorumType.Validate(); err != nil { return false, err } - signID := crypto.SignID( - quorumType, - tmbytes.Reverse(quorumHash), - tmbytes.Reverse(requestID), - tmbytes.Reverse(messageHash), - ) + + signID := crypto.NewSignItemFromHash(quorumType, quorumHash, requestID, messageHash).ID + thresholdPublicKey, err := mc.localPV.GetThresholdPublicKey(context.Background(), quorumHash) if err != nil { panic(err) diff --git a/internal/consensus/vote_signer.go b/internal/consensus/vote_signer.go index ed50018955..a921b45615 100644 --- a/internal/consensus/vote_signer.go +++ b/internal/consensus/vote_signer.go @@ -108,7 +108,7 @@ func (s *voteSigner) signVote( if err != nil { return nil, err } - + s.logger.Debug("signed Vote", "vote", vote, "signature", vote.BlockSignature.String()) return vote, nil } diff --git a/internal/consensus/vote_signer_test.go b/internal/consensus/vote_signer_test.go index c8779698e5..0189e19f43 100644 --- a/internal/consensus/vote_signer_test.go +++ b/internal/consensus/vote_signer_test.go @@ -90,25 +90,25 @@ func TestVoteSigner_signAddVote(t *testing.T) { { msgType: tmproto.PrevoteType, blockID: blockID, - wantBlockSign: "8B52677D4D455125808EDEE715D2A999695A6701E477C1F44CEDCCE3FC62FB88698D0B6B3CA0429E17EDA9DBCEA932720C189E21F5A6FB31B2C244152F0CD7988598AD572E5D605164554C80880BDC130E23C9DBEF20CF315D05F8C13B6C92CC", + wantBlockSign: "80B628F02FE2047C7B98175CD8CF609775B95393C63D8EBC2F630D95121C28826C942F6511405D33484639C2906879110FDC293418C95862A60329FDDF0B210654559839B5ABFC11E50AFC4E498B0C9041118394DB04E52D0B28A92FC91DEABC", }, { msgType: tmproto.PrecommitType, - wantBlockSign: "97CCF337D8FCA05E600EAAF769D73BE9A0D1466CAE85374E9E0EF4C3DD1759131E1D2C8B9E8D8D28EBEF27074669D46C0820DF4DA337DFFA6B3EB5BEEA4B78CA8EA131ED584609D227025DB96990C732C2D04A693BC0402B8A19229ED32A51B8", + wantBlockSign: "8BEEE4EDA67394060C1A1D41797E998120B7BC217E7D36526DA76AE57616475FB1C4DCF08C522E76C75220104611F56800F1CF299ECD98FDB1C598471DC0D4048F8F5381B034270EB0B66E987D61B7DF555DFA92C6B5C9E6FAD608676130A726", }, { msgType: tmproto.PrecommitType, blockID: blockID, voteExtensions: nil, mockFn: mockFn, - wantBlockSign: "9755FA9803D98C344CB16A43B782D2A93ED9A7E7E1C8437482F42781D5EF802EC82442C14C44429737A7355B1F9D87CB139EB2CF193A1CF7C812E38B99221ADF4DAA60CE16550ED6509A9C467A3D4492D77038505235796968465337A1E14B3E", + wantBlockSign: "B2C484BB07094AAB8EFAB187982F6A8E8172FBEBAE5B6EB6304E527ABAAB7D059D9A43DDDBA82A6D296AF30E67C28D250449A586E9A69C2577057E01FA290BB03C186982D4D45E6016935AD4B9A84EB0911B62A83E457E25CE44DC28516D0E0A", }, { msgType: tmproto.PrecommitType, blockID: blockID, voteExtensions: voteExtensions, mockFn: mockFn, - wantBlockSign: "9755FA9803D98C344CB16A43B782D2A93ED9A7E7E1C8437482F42781D5EF802EC82442C14C44429737A7355B1F9D87CB139EB2CF193A1CF7C812E38B99221ADF4DAA60CE16550ED6509A9C467A3D4492D77038505235796968465337A1E14B3E", + wantBlockSign: "B2C484BB07094AAB8EFAB187982F6A8E8172FBEBAE5B6EB6304E527ABAAB7D059D9A43DDDBA82A6D296AF30E67C28D250449A586E9A69C2577057E01FA290BB03C186982D4D45E6016935AD4B9A84EB0911B62A83E457E25CE44DC28516D0E0A", }, } for i, tc := range testCases { diff --git a/privval/dash_consensus_key.go b/privval/dash_consensus_key.go index 5eb6a909d3..6fcf1be299 100644 --- a/privval/dash_consensus_key.go +++ b/privval/dash_consensus_key.go @@ -8,8 +8,8 @@ import ( "github.com/dashpay/dashd-go/btcjson" + "github.com/dashpay/tenderdash/crypto" tmcrypto "github.com/dashpay/tenderdash/crypto" - tmbytes "github.com/dashpay/tenderdash/libs/bytes" ) type dashConsensusPrivateKey struct { @@ -105,12 +105,7 @@ func (pub DashConsensusPublicKey) VerifySignature(msg []byte, sig []byte) bool { return pub.VerifySignatureDigest(hash, sig) } func (pub DashConsensusPublicKey) VerifySignatureDigest(hash []byte, sig []byte) bool { - signID := tmcrypto.SignID( - pub.quorumType, - tmbytes.Reverse(pub.quorumHash), - tmbytes.Reverse(hash[:]), - tmbytes.Reverse(hash[:]), - ) + signID := crypto.NewSignItemFromHash(pub.quorumType, pub.quorumHash, hash, hash).ID return pub.PubKey.VerifySignatureDigest(signID, sig) } diff --git a/privval/dash_core_signer_client.go b/privval/dash_core_signer_client.go index 775ede08eb..402a759b1d 100644 --- a/privval/dash_core_signer_client.go +++ b/privval/dash_core_signer_client.go @@ -292,7 +292,7 @@ func (sc *DashCoreSignerClient) SignVote( func (sc *DashCoreSignerClient) SignProposal( ctx context.Context, chainID string, quorumType btcjson.LLMQType, quorumHash crypto.QuorumHash, proposalProto *tmproto.Proposal, ) (tmbytes.HexBytes, error) { - signItem := types.NewSignItem( + signItem := crypto.NewSignItem( quorumType, quorumHash, types.ProposalRequestIDProto(proposalProto), @@ -314,7 +314,7 @@ func (sc *DashCoreSignerClient) QuorumSign( quorumType btcjson.LLMQType, quorumHash crypto.QuorumHash, ) ([]byte, []byte, error) { - signItem := types.NewSignItemFromHash(quorumType, quorumHash, requestIDHash, msgHash) + signItem := crypto.NewSignItemFromHash(quorumType, quorumHash, requestIDHash, msgHash) qs, err := sc.quorumSignAndVerify(ctx, quorumType, quorumHash, signItem) if err != nil { @@ -392,7 +392,7 @@ func (sc *DashCoreSignerClient) quorumSignAndVerify( ctx context.Context, quorumType btcjson.LLMQType, quorumHash crypto.QuorumHash, - signItem types.SignItem, + signItem crypto.SignItem, ) (*quorumSignResult, error) { qs, err := sc.quorumSign(quorumType, quorumHash, signItem) if err != nil { @@ -420,7 +420,7 @@ func (sc *DashCoreSignerClient) quorumSignAndVerify( func (sc *DashCoreSignerClient) quorumSign( quorumType btcjson.LLMQType, quorumHash crypto.QuorumHash, - signItem types.SignItem, + signItem crypto.SignItem, ) (*quorumSignResult, error) { resp, err := sc.dashCoreRPCClient.QuorumSign(quorumType, signItem.ReqID, signItem.Hash, quorumHash) if err != nil { diff --git a/test/e2e/pkg/mockcoreserver/core_server.go b/test/e2e/pkg/mockcoreserver/core_server.go index 9a3880f837..183929f228 100644 --- a/test/e2e/pkg/mockcoreserver/core_server.go +++ b/test/e2e/pkg/mockcoreserver/core_server.go @@ -9,7 +9,6 @@ import ( "github.com/dashpay/dashd-go/btcjson" "github.com/dashpay/tenderdash/crypto" - tmbytes "github.com/dashpay/tenderdash/libs/bytes" "github.com/dashpay/tenderdash/privval" ) @@ -93,13 +92,8 @@ func (c *MockCoreServer) QuorumSign(ctx context.Context, cmd btcjson.QuorumCmd) panic(err) } quorumHash := crypto.QuorumHash(quorumHashBytes) + signID := crypto.NewSignItemFromHash(*cmd.LLMQType, quorumHash, reqID, msgHash).ID - signID := crypto.SignID( - *cmd.LLMQType, - tmbytes.Reverse(quorumHash), - tmbytes.Reverse(reqID), - tmbytes.Reverse(msgHash), - ) privateKey, err := c.FilePV.GetPrivateKey(ctx, quorumHash) if err != nil { panic(err) @@ -142,13 +136,8 @@ func (c *MockCoreServer) QuorumVerify(ctx context.Context, cmd btcjson.QuorumCmd if err != nil { panic(err) } + signID := crypto.NewSignItemFromHash(*cmd.LLMQType, quorumHash, reqID, msgHash).ID - signID := crypto.SignID( - *cmd.LLMQType, - tmbytes.Reverse(quorumHash), - tmbytes.Reverse(reqID), - tmbytes.Reverse(msgHash), - ) thresholdPublicKey, err := c.FilePV.GetThresholdPublicKey(ctx, quorumHash) if err != nil { panic(err) diff --git a/types/proposal.go b/types/proposal.go index 9525556a0b..04c4fe26c7 100644 --- a/types/proposal.go +++ b/types/proposal.go @@ -182,12 +182,7 @@ func ProposalBlockSignID( proposalRequestID := ProposalRequestIDProto(p) - signID := crypto.SignID( - quorumType, - tmbytes.Reverse(quorumHash), - tmbytes.Reverse(proposalRequestID), - tmbytes.Reverse(proposalMessageHash[:]), - ) + signID := crypto.NewSignItemFromHash(quorumType, quorumHash, proposalRequestID, proposalMessageHash[:]).ID return signID } diff --git a/types/quorum_sign_data.go b/types/quorum_sign_data.go index 2d2ee9afd9..1f4617fe8b 100644 --- a/types/quorum_sign_data.go +++ b/types/quorum_sign_data.go @@ -4,10 +4,8 @@ import ( "bytes" "errors" "fmt" - "testing" "github.com/dashpay/dashd-go/btcjson" - "github.com/rs/zerolog" "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/proto/tendermint/types" @@ -19,8 +17,8 @@ var ( // QuorumSignData holds data which is necessary for signing and verification block, state, and each vote-extension in a list type QuorumSignData struct { - Block SignItem - Extensions map[types.VoteExtensionType][]SignItem + Block crypto.SignItem + Extensions map[types.VoteExtensionType][]crypto.SignItem } // Verify verifies a quorum signatures: block, state and vote-extensions @@ -28,42 +26,6 @@ func (q QuorumSignData) Verify(pubKey crypto.PubKey, signs QuorumSigns) error { return NewQuorumSignsVerifier(q).Verify(pubKey, signs) } -// SignItem represents quorum sign data, like a request id, message bytes, sha256 hash of message and signID -type SignItem struct { - ReqID []byte // Request ID for quorum signing - ID []byte // Signature ID - Raw []byte // Raw data to be signed - Hash []byte // Checksum of Raw - QuorumType btcjson.LLMQType // Quorum type for which this sign item is created - QuorumHash []byte // Quorum hash for which this sign item is created -} - -// Validate validates prepared data for signing -func (i *SignItem) Validate() error { - if len(i.ReqID) != crypto.DefaultHashSize { - return fmt.Errorf("invalid request ID size: %X", i.ReqID) - } - if len(i.Hash) != crypto.DefaultHashSize { - return fmt.Errorf("invalid hash size: %X", i.ReqID) - } - if len(i.QuorumHash) != crypto.DefaultHashSize { - return fmt.Errorf("invalid quorum hash size: %X", i.ReqID) - } - if len(i.Raw) > 0 { - if !bytes.Equal(crypto.Checksum(i.Raw), i.Hash) { - return fmt.Errorf("invalid hash %X for raw data: %X", i.Hash, i.Raw) - } - } - return nil -} - -func (i SignItem) MarshalZerologObject(e *zerolog.Event) { - e.Hex("signBytes", i.Raw) - e.Hex("signRequestID", i.ReqID) - e.Hex("signID", i.ID) - e.Hex("signHash", i.Hash) -} - // MakeQuorumSignsWithVoteSet creates and returns QuorumSignData struct built with a vote-set and an added vote func MakeQuorumSignsWithVoteSet(voteSet *VoteSet, vote *types.Vote) (QuorumSignData, error) { return MakeQuorumSigns( @@ -94,13 +56,13 @@ func MakeQuorumSigns( } // MakeBlockSignItem creates SignItem struct for a block -func MakeBlockSignItem(chainID string, vote *types.Vote, quorumType btcjson.LLMQType, quorumHash []byte) SignItem { +func MakeBlockSignItem(chainID string, vote *types.Vote, quorumType btcjson.LLMQType, quorumHash []byte) crypto.SignItem { reqID := BlockRequestID(vote.Height, vote.Round) raw, err := vote.SignBytes(chainID) if err != nil { panic(fmt.Errorf("block sign item: %w", err)) } - return NewSignItem(quorumType, quorumHash, reqID, raw) + return crypto.NewSignItem(quorumType, quorumHash, reqID, raw) } // BlockRequestID returns a block request ID @@ -114,7 +76,7 @@ func MakeVoteExtensionSignItems( protoVote *types.Vote, quorumType btcjson.LLMQType, quorumHash []byte, -) (map[types.VoteExtensionType][]SignItem, error) { +) (map[types.VoteExtensionType][]crypto.SignItem, error) { // We only sign vote extensions for precommits if protoVote.Type != types.PrecommitType { if len(protoVote.VoteExtensions) > 0 { @@ -122,11 +84,11 @@ func MakeVoteExtensionSignItems( } return nil, nil } - items := make(map[types.VoteExtensionType][]SignItem) + items := make(map[types.VoteExtensionType][]crypto.SignItem) protoExtensionsMap := protoVote.VoteExtensionsToMap() for t, exts := range protoExtensionsMap { if items[t] == nil && len(exts) > 0 { - items[t] = make([]SignItem, len(exts)) + items[t] = make([]crypto.SignItem, len(exts)) } for i, ext := range exts { @@ -139,72 +101,12 @@ func MakeVoteExtensionSignItems( if ext.Type == types.VoteExtensionType_THRESHOLD_RECOVER_RAW { // for this vote extension type, we just sign raw data from extension msgHash := bytes.Clone(raw) - items[t][i] = NewSignItemFromHash(quorumType, quorumHash, reqID, msgHash) + items[t][i] = crypto.NewSignItemFromHash(quorumType, quorumHash, reqID, msgHash) items[t][i].Raw = raw } else { - items[t][i] = NewSignItem(quorumType, quorumHash, reqID, raw) + items[t][i] = crypto.NewSignItem(quorumType, quorumHash, reqID, raw) } } } return items, nil } - -// NewSignItem creates a new instance of SignItem with calculating a hash for a raw and creating signID -// -// Arguments: -// - quorumType: quorum type -// - quorumHash: quorum hash -// - reqID: sign request ID -// - raw: raw data to be signed; it will be hashed with crypto.Checksum() -func NewSignItem(quorumType btcjson.LLMQType, quorumHash, reqID, raw []byte) SignItem { - msgHash := crypto.Checksum(raw) - item := NewSignItemFromHash(quorumType, quorumHash, reqID, msgHash) - item.Raw = raw - - return item -} - -// Create a new sign item without raw value, using provided hash. -func NewSignItemFromHash(quorumType btcjson.LLMQType, quorumHash, reqID, msgHash []byte) SignItem { - item := SignItem{ - ReqID: reqID, - Hash: msgHash, - QuorumType: quorumType, - QuorumHash: quorumHash, - Raw: nil, // Raw is empty, as we don't have it - } - item.UpdateID() - - return item -} - -func (i *SignItem) UpdateID() { - if err := i.Validate(); err != nil { - panic("invalid sign item: " + err.Error()) - } - // FIXME: previously we had reversals, but this doesn't work with Core test vectors - // So - // quorumHash := tmbytes.Reverse(i.QuorumHash) - quorumHash := i.QuorumHash - // requestID := tmbytes.Reverse(i.ReqID) - requestID := i.ReqID - // messageHash := tmbytes.Reverse(i.Hash) - messageHash := i.Hash - - if testing.Testing() { - fmt.Printf("generating sign ID using bls.BuildSignHash for %d %X %X %X\n", i.QuorumType, quorumHash, requestID, messageHash) - out := append([]byte{byte(i.QuorumType)}, quorumHash...) - out = append(out, requestID...) - out = append(out, messageHash...) - - fmt.Printf("data before sha256: %X\n", out) - fmt.Printf("sha256(sha256(data)): %X\n", crypto.Checksum((crypto.Checksum(out)))) - - } - i.ID = crypto.SignID( - i.QuorumType, - quorumHash, - requestID, - messageHash, - ) -} diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index 6628b33b26..68e6b97236 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/dashpay/tenderdash/crypto" tmbytes "github.com/dashpay/tenderdash/libs/bytes" "github.com/dashpay/tenderdash/libs/log" "github.com/dashpay/tenderdash/proto/tendermint/types" @@ -26,7 +27,7 @@ func TestMakeBlockSignID(t *testing.T) { testCases := []struct { vote Vote quorumHash []byte - want SignItem + want crypto.SignItem wantHash []byte }{ { @@ -63,7 +64,7 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { testCases := []struct { vote Vote quorumHash []byte - want map[types.VoteExtensionType][]SignItem + want map[types.VoteExtensionType][]crypto.SignItem wantHash map[types.VoteExtensionType][][]byte }{ { @@ -81,7 +82,7 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { }, }, quorumHash: tmbytes.MustHexDecode("6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD"), - want: map[types.VoteExtensionType][]SignItem{ + want: map[types.VoteExtensionType][]crypto.SignItem{ types.VoteExtensionType_DEFAULT: { newSignItem( "FB95F2CA6530F02AC623589D7938643FF22AE79A75DD79AEA1C8871162DE675E", @@ -184,8 +185,8 @@ func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { } -func newSignItem(reqID, ID, raw, quorumHash string, quorumType btcjson.LLMQType) SignItem { - item := NewSignItem(quorumType, tmbytes.MustHexDecode(quorumHash), tmbytes.MustHexDecode(reqID), tmbytes.MustHexDecode(raw)) +func newSignItem(reqID, ID, raw, quorumHash string, quorumType btcjson.LLMQType) crypto.SignItem { + item := crypto.NewSignItem(quorumType, tmbytes.MustHexDecode(quorumHash), tmbytes.MustHexDecode(reqID), tmbytes.MustHexDecode(raw)) item.ID = tmbytes.MustHexDecode(ID) return item } From 815a4a0092578bd964d16b8dd34bc1dd4c72534a Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 15 Dec 2023 17:22:34 +0100 Subject: [PATCH 22/55] test: fix tests --- crypto/quorum.go | 4 ++-- privval/file_test.go | 4 ++-- types/evidence_test.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crypto/quorum.go b/crypto/quorum.go index c9dafd57fb..1ad885e2af 100644 --- a/crypto/quorum.go +++ b/crypto/quorum.go @@ -26,10 +26,10 @@ func (i *SignItem) Validate() error { return fmt.Errorf("invalid request ID size: %X", i.ReqID) } if len(i.Hash) != DefaultHashSize { - return fmt.Errorf("invalid hash size: %X", i.ReqID) + return fmt.Errorf("invalid hash size %d: %X", len(i.Hash), i.Hash) } if len(i.QuorumHash) != DefaultHashSize { - return fmt.Errorf("invalid quorum hash size: %X", i.ReqID) + return fmt.Errorf("invalid quorum hash size %d: %X", len(i.QuorumHash), i.QuorumHash) } if len(i.Raw) > 0 { if !bytes.Equal(Checksum(i.Raw), i.Hash) { diff --git a/privval/file_test.go b/privval/file_test.go index 1426abfb25..09f530cc04 100644 --- a/privval/file_test.go +++ b/privval/file_test.go @@ -238,7 +238,7 @@ func TestSignVote(t *testing.T) { } for _, c := range cases { - assert.Error(t, privVal.SignVote(ctx, "mychainid", 0, crypto.QuorumHash{}, c.ToProto(), nil), + assert.Error(t, privVal.SignVote(ctx, "mychainid", 0, quorumHash, c.ToProto(), nil), "expected error on signing conflicting vote") } @@ -289,7 +289,7 @@ func TestSignProposal(t *testing.T) { } for _, c := range cases { - _, err = privVal.SignProposal(ctx, "mychainid", 0, crypto.QuorumHash{}, c.ToProto()) + _, err = privVal.SignProposal(ctx, "mychainid", 0, quorumHash, c.ToProto()) assert.Error(t, err, "expected error on signing conflicting proposal") } } diff --git a/types/evidence_test.go b/types/evidence_test.go index edee9d7248..9fb19a84e9 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -302,7 +302,7 @@ func TestEvidenceVectors(t *testing.T) { }{ {"duplicateVoteEvidence", EvidenceList{&DuplicateVoteEvidence{VoteA: v2, VoteB: v}}, - "87904f3525bfdb8474a18bc44fcadf76f63f0e7cabc3063f5eae8dcf0eb11d79", + "54b4c93161a227c5387bd5da81b533c399097877217d08d1f579038a9c527775", }, } From 34fd62c0536f012f088bd4be6f7b8245952359ea Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 20 Dec 2023 15:01:04 +0100 Subject: [PATCH 23/55] refactor(types): vote extensions support for multiple types --- abci/example/kvstore/kvstore.go | 4 +- abci/example/kvstore/verify.go | 45 +- go.mod | 187 ++--- go.sum | 701 ++++++++---------- internal/blocksync/reactor_test.go | 4 +- internal/consensus/common_test.go | 8 +- internal/consensus/gossiper_test.go | 2 +- internal/consensus/msgs_test.go | 7 +- internal/consensus/replay_test.go | 4 +- internal/consensus/state_test.go | 59 +- .../consensus/types/height_vote_set_test.go | 2 +- internal/consensus/vote_signer_test.go | 16 +- internal/state/execution.go | 2 +- internal/state/validation_test.go | 4 +- internal/store/store_test.go | 2 +- internal/test/factory/commit.go | 2 +- internal/test/factory/vote.go | 3 +- privval/dash_core_signer_client.go | 16 +- privval/file.go | 30 +- privval/file_test.go | 35 +- privval/msgs_test.go | 13 +- proto/tendermint/types/dash.go | 82 +- proto/tendermint/types/types.go | 16 - types/block.go | 8 +- types/block_test.go | 2 +- types/priv_validator.go | 21 +- types/quorum.go | 105 +-- types/quorum_sign_data.go | 58 +- types/quorum_sign_data_test.go | 99 ++- types/signs_recoverer.go | 74 +- types/signs_recoverer_test.go | 90 ++- types/test_util.go | 14 +- types/validation_test.go | 2 +- types/vote.go | 45 +- types/vote_dash.go | 16 +- types/vote_extension.go | 382 +++++++--- types/vote_set.go | 22 +- types/vote_test.go | 108 ++- 38 files changed, 1186 insertions(+), 1104 deletions(-) diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index 41e9c2e52d..04acec1898 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -411,8 +411,8 @@ func (app *Application) FinalizeBlock(_ context.Context, req *abci.RequestFinali if app.shouldCommitVerify { vsu := app.getActiveValidatorSetUpdates() qsd := types.QuorumSignData{ - Block: makeBlockSignItem(req, btcjson.LLMQType_5_60, vsu.QuorumHash), - Extensions: makeVoteExtensionSignItems(req, btcjson.LLMQType_5_60, vsu.QuorumHash), + Block: makeBlockSignItem(req, btcjson.LLMQType_5_60, vsu.QuorumHash), + ThresholdVoteExtensions: makeVoteExtensionSignItems(req, btcjson.LLMQType_5_60, vsu.QuorumHash), } err := app.verifyBlockCommit(qsd, req.Commit) if err != nil { diff --git a/abci/example/kvstore/verify.go b/abci/example/kvstore/verify.go index 01826a4cee..64ae3c94e3 100644 --- a/abci/example/kvstore/verify.go +++ b/abci/example/kvstore/verify.go @@ -10,7 +10,6 @@ import ( "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/crypto/encoding" tmbytes "github.com/dashpay/tenderdash/libs/bytes" - types1 "github.com/dashpay/tenderdash/proto/tendermint/types" "github.com/dashpay/tenderdash/types" ) @@ -25,28 +24,11 @@ func (app *Application) verifyBlockCommit(qsd types.QuorumSignData, commit abci. return err } return verifier.Verify(pubKey, types.QuorumSigns{ - BlockSign: commit.BlockSignature, - ExtensionSigns: makeThresholdVoteExtensions(commit.ThresholdVoteExtensions), + BlockSign: commit.BlockSignature, + ThresholdVoteExtensions: types.VoteExtensionsFromProto(commit.ThresholdVoteExtensions...), }) } -func makeThresholdVoteExtensions(pbVoteExtensions []*types1.VoteExtension) []types.ThresholdExtensionSign { - voteExtensions := types.VoteExtensionsFromProto(pbVoteExtensions) - var thresholdExtensionSigns []types.ThresholdExtensionSign - thresholdVoteExtensions, ok := voteExtensions[types1.VoteExtensionType_THRESHOLD_RECOVER] - if !ok { - return nil - } - thresholdExtensionSigns = make([]types.ThresholdExtensionSign, len(thresholdVoteExtensions)) - for i, voteExtension := range thresholdVoteExtensions { - thresholdExtensionSigns[i] = types.ThresholdExtensionSign{ - Extension: voteExtension.Extension, - ThresholdSignature: voteExtension.Signature, - } - } - return thresholdExtensionSigns -} - func makeBlockSignItem( req *abci.RequestFinalizeBlock, quorumType btcjson.LLMQType, @@ -68,23 +50,14 @@ func makeVoteExtensionSignItems( req *abci.RequestFinalizeBlock, quorumType btcjson.LLMQType, quorumHash []byte, -) map[types1.VoteExtensionType][]crypto.SignItem { - items := make(map[types1.VoteExtensionType][]crypto.SignItem) - protoExtensionsMap := types1.VoteExtensionsToMap(req.Commit.ThresholdVoteExtensions) - for t, exts := range protoExtensionsMap { - if items[t] == nil && len(exts) > 0 { - items[t] = make([]crypto.SignItem, len(exts)) - } - chainID := req.Block.Header.ChainID - for i, ext := range exts { - raw := types.VoteExtensionSignBytes(chainID, req.Height, req.Round, ext) - reqID, err := types.VoteExtensionRequestID(ext, req.Height, req.Round) - if err != nil { - panic(fmt.Errorf("vote extension sign items: %w", err)) - } +) []crypto.SignItem { + + extensions := types.VoteExtensionsFromProto(req.Commit.ThresholdVoteExtensions...) + chainID := req.Block.Header.ChainID - items[t][i] = crypto.NewSignItem(quorumType, quorumHash, reqID, raw) - } + items, err := extensions.SignItems(chainID, quorumType, quorumHash, req.Height, req.Round) + if err != nil { + panic(fmt.Errorf("vote extension sign items: %w", err)) } return items } diff --git a/go.mod b/go.mod index 881c98ec28..1c8c81a99f 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/dashpay/tenderdash go 1.21 require ( - github.com/BurntSushi/toml v1.2.0 + github.com/BurntSushi/toml v1.3.2 github.com/adlio/schema v1.3.3 github.com/btcsuite/btcd v0.22.1 github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce @@ -22,11 +22,11 @@ require ( github.com/google/btree v1.1.2 // indirect github.com/google/gopacket v1.1.19 github.com/google/orderedcode v0.0.1 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 github.com/gorilla/websocket v1.5.0 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 - github.com/lib/pq v1.10.6 + github.com/lib/pq v1.10.9 github.com/libp2p/go-buffer-pool v0.1.0 github.com/mroth/weightedrand v0.4.1 github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae @@ -35,13 +35,13 @@ require ( github.com/rs/cors v1.8.2 github.com/rs/zerolog v1.29.0 github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa - github.com/spf13/cobra v1.6.1 + github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.15.0 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.4 github.com/tendermint/tm-db v0.6.6 - golang.org/x/crypto v0.1.0 - golang.org/x/net v0.8.0 - golang.org/x/sync v0.1.0 + golang.org/x/crypto v0.14.0 + golang.org/x/net v0.17.0 + golang.org/x/sync v0.4.0 google.golang.org/grpc v1.52.0 pgregory.net/rapid v0.4.8 ) @@ -57,73 +57,95 @@ require ( ) require ( + 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect + github.com/4meepo/tagalign v1.3.3 // indirect + github.com/Abirdcfly/dupword v0.0.13 // indirect + github.com/Antonboom/testifylint v0.2.3 // indirect + github.com/GaijinEntertainment/go-exhaustruct/v3 v3.1.0 // indirect + github.com/OpenPeeDeeP/depguard/v2 v2.1.0 // indirect + github.com/alecthomas/go-check-sumtype v0.1.3 // indirect + github.com/alexkohler/nakedret/v2 v2.0.2 // indirect github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect github.com/bufbuild/connect-go v0.2.0 // indirect + github.com/butuzov/mirror v1.1.0 // indirect + github.com/catenacyber/perfsprint v0.2.0 // indirect + github.com/ccojocar/zxcvbn-go v1.0.1 // indirect github.com/chigopher/pathlib v0.15.0 // indirect github.com/containerd/containerd v1.6.6 // indirect github.com/containerd/typeurl v1.0.2 // indirect + github.com/curioswitch/go-reassign v0.2.0 // indirect github.com/dashpay/dashd-go/btcutil v1.2.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/didip/tollbooth/v6 v6.0.1 // indirect github.com/didip/tollbooth_chi v0.0.0-20200524181329-8b84cd7183d9 // indirect github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/docker v20.10.17+incompatible // indirect + github.com/ghostiam/protogetter v0.2.3 // indirect github.com/go-chi/chi/v5 v5.0.7 // indirect github.com/go-chi/render v1.0.1 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-pkgz/expirable-cache v0.0.3 // indirect github.com/go-pkgz/rest v1.5.0 // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect github.com/iancoleman/strcase v0.2.0 // indirect github.com/jinzhu/copier v0.3.5 // indirect + github.com/kkHAIKE/contextcheck v1.1.4 // indirect + github.com/macabu/inamedparam v0.1.2 // indirect + github.com/maratori/testableexamples v1.0.0 // indirect github.com/moby/buildkit v0.10.3 // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/nunnatsa/ginkgolinter v0.14.0 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect - github.com/sashamelentyev/usestdlibvars v1.8.0 // indirect + github.com/sashamelentyev/interfacebloat v1.1.0 // indirect + github.com/sashamelentyev/usestdlibvars v1.24.0 // indirect + github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/tendermint/tendermint v0.34.21 // indirect + github.com/timonwong/loggercheck v0.9.4 // indirect + github.com/xen0n/gosmopolitan v1.2.2 // indirect + github.com/ykadowak/zerologlint v0.1.3 // indirect + go-simpler.org/sloglint v0.1.2 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.33.0 // indirect go.opentelemetry.io/otel v1.8.0 // indirect go.opentelemetry.io/otel/trace v1.8.0 // indirect + go.tmz.dev/musttag v0.7.2 // indirect golang.org/x/time v0.1.0 // indirect google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef // indirect ) require ( - 4d63.com/gochecknoglobals v0.1.0 // indirect - github.com/Antonboom/errname v0.1.7 // indirect - github.com/Antonboom/nilnil v0.1.1 // indirect + 4d63.com/gochecknoglobals v0.2.1 // indirect + github.com/Antonboom/errname v0.1.12 // indirect + github.com/Antonboom/nilnil v0.1.7 // 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/GaijinEntertainment/go-exhaustruct/v2 v2.2.2 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Microsoft/go-winio v0.5.2 // 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/alingse/asasalint v0.0.11 // indirect - github.com/ashanbrown/forbidigo v1.3.0 // indirect + github.com/ashanbrown/forbidigo v1.6.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/bkielbasa/cyclop v1.2.1 // indirect github.com/blizzy78/varnamelen v0.8.0 // indirect - github.com/bombsimon/wsl/v3 v3.3.0 // indirect - github.com/breml/bidichk v0.2.3 // indirect - github.com/breml/errchkjson v0.3.0 // indirect - github.com/butuzov/ireturn v0.1.1 // indirect + github.com/bombsimon/wsl/v3 v3.4.0 // indirect + github.com/breml/bidichk v0.2.7 // indirect + github.com/breml/errchkjson v0.3.6 // indirect + github.com/butuzov/ireturn v0.2.1 // 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-20220316182200-5cad0b5181d4 // indirect + github.com/charithe/durationcheck v0.0.10 // indirect + github.com/chavacava/garif v0.1.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/daixiang0/gci v0.6.2 // indirect + github.com/daixiang0/gci v0.11.2 // 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 @@ -134,20 +156,20 @@ require ( 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/fatih/color v1.13.0 // indirect + github.com/fatih/color v1.15.0 // indirect github.com/fatih/structtag v1.2.0 // indirect github.com/firefart/nonamedreturns v1.0.4 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect - github.com/go-critic/go-critic v0.6.3 // 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/go-critic/go-critic v0.9.0 // indirect + github.com/go-toolsmith/astcast v1.1.0 // indirect + github.com/go-toolsmith/astcopy v1.1.0 // indirect + github.com/go-toolsmith/astequal v1.1.0 // indirect + github.com/go-toolsmith/astfmt v1.1.0 // indirect + github.com/go-toolsmith/astp v1.1.0 // indirect + github.com/go-toolsmith/strparse v1.1.0 // indirect + github.com/go-toolsmith/typep v1.1.0 // indirect + github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gofrs/uuid v4.2.0+incompatible // indirect @@ -155,13 +177,13 @@ require ( 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-20220329215616-d24fe342adfe // indirect - github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a // indirect + github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e // 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-20220804021717-745bb2f7c2e6 // indirect + github.com/golangci/misspell v0.4.1 // indirect + github.com/golangci/revgrep v0.5.0 // indirect github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect - github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 // indirect + github.com/gordonklaus/ineffassign v0.0.0-20230610083614-0e73809eb601 // 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 @@ -173,69 +195,67 @@ require ( github.com/hexops/gotextdiff v1.0.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a // indirect - github.com/jgautheron/goconst v1.5.1 // indirect + github.com/jgautheron/goconst v1.6.0 // indirect github.com/jhump/protocompile v0.0.0-20220216033700-d705409f108f // indirect github.com/jhump/protoreflect v1.12.1-0.20220721211354-060cc04fc18b // 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.2 // indirect + github.com/kisielk/errcheck v1.6.3 // indirect github.com/kisielk/gotool v1.0.0 // indirect github.com/klauspost/compress v1.15.10 // indirect github.com/klauspost/pgzip v1.2.5 // indirect github.com/kulti/thelper v0.6.3 // indirect - github.com/kunwardeep/paralleltest v1.0.6 // indirect - github.com/kyoh86/exportloopref v0.1.8 // indirect + github.com/kunwardeep/paralleltest v1.0.8 // indirect + github.com/kyoh86/exportloopref v0.1.11 // indirect github.com/ldez/gomoddirectives v0.2.3 // indirect - github.com/ldez/tagliatelle v0.3.1 // indirect - github.com/leonklingele/grouper v1.1.0 // indirect + github.com/ldez/tagliatelle v0.5.0 // indirect + github.com/leonklingele/grouper v1.1.1 // indirect github.com/lufeee/execinquery v1.2.1 // indirect github.com/magiconair/properties v1.8.7 // indirect - github.com/maratori/testpackage v1.1.0 // indirect - github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect + github.com/maratori/testpackage v1.1.1 // indirect + github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mbilski/exhaustivestruct v1.2.0 // indirect - github.com/mgechev/revive v1.2.1 // indirect + github.com/mgechev/revive v1.3.4 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moricho/tparallel v0.2.1 // indirect + github.com/moricho/tparallel v0.3.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.8.1 // indirect + github.com/nishanths/exhaustive v0.11.0 // indirect github.com/nishanths/predeclared v0.2.2 // 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.3-0.20211202183452-c5a74bcca799 // indirect github.com/opencontainers/runc v1.1.3 // indirect - github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pkg/profile v1.6.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/polyfloyd/go-errorlint v1.0.0 // indirect + github.com/polyfloyd/go-errorlint v1.4.5 // indirect github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.37.0 github.com/prometheus/procfs v0.8.0 // indirect - github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a // indirect - github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5 // indirect - github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect + github.com/quasilyte/go-ruleguard v0.4.0 // indirect + github.com/quasilyte/gogrep v0.5.0 // indirect + github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/ryancurrah/gomodguard v1.2.4 // indirect - github.com/ryanrolds/sqlclosecheck v0.3.0 // indirect - github.com/sanposhiho/wastedassign/v2 v2.0.6 // indirect - github.com/securego/gosec/v2 v2.12.0 // indirect + github.com/ryancurrah/gomodguard v1.3.0 // indirect + github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect + github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect + github.com/securego/gosec/v2 v2.18.1 // indirect github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect - github.com/sirupsen/logrus v1.9.0 // indirect - github.com/sivchari/containedctx v1.0.2 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sivchari/containedctx v1.0.3 // indirect github.com/sivchari/nosnakecase v1.7.0 // indirect - github.com/sivchari/tenv v1.7.0 // indirect - github.com/sonatard/noctx v0.0.1 // indirect - github.com/sourcegraph/go-diff v0.6.1 // indirect + github.com/sivchari/tenv v1.7.1 // indirect + github.com/sonatard/noctx v0.0.2 // indirect + github.com/sourcegraph/go-diff v0.7.0 // indirect github.com/spf13/afero v1.9.3 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -244,39 +264,38 @@ require ( github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect - github.com/sylvia7788/contextcheck v1.0.4 // indirect - github.com/tdakkota/asciicheck v0.1.1 // 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.6.2 // indirect - github.com/tommy-muehle/go-mnd/v2 v2.5.0 // indirect - github.com/ultraware/funlen v0.0.3 // indirect + github.com/tdakkota/asciicheck v0.2.0 // indirect + github.com/tetafro/godot v1.4.15 // indirect + github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect + github.com/tomarrell/wrapcheck/v2 v2.8.1 // indirect + github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect + github.com/ultraware/funlen v0.1.0 // indirect github.com/ultraware/whitespace v0.0.5 // indirect - github.com/uudashr/gocognit v1.0.6 // indirect + github.com/uudashr/gocognit v1.1.2 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/yagipy/maintidx v1.0.0 // indirect github.com/yeya24/promlinter v0.2.0 // indirect - gitlab.com/bosi/decorder v0.2.3 // indirect + gitlab.com/bosi/decorder v0.4.1 // indirect go.etcd.io/bbolt v1.3.6 // indirect go.opencensus.io v0.24.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect - go.uber.org/zap v1.23.0 // indirect - golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d // indirect - golang.org/x/mod v0.9.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/term v0.6.0 - golang.org/x/text v0.8.0 // indirect - golang.org/x/tools v0.7.0 // indirect + go.uber.org/zap v1.24.0 // indirect + golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833 // indirect + golang.org/x/mod v0.13.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 + golang.org/x/text v0.13.0 // indirect + golang.org/x/tools v0.14.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - honnef.co/go/tools v0.3.3 // indirect - mvdan.cc/gofumpt v0.3.1 // indirect + honnef.co/go/tools v0.4.6 // indirect + mvdan.cc/gofumpt v0.5.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-20220706161116-678bad134442 // indirect + mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d // indirect ) require ( @@ -287,5 +306,5 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca github.com/tendermint/go-amino v0.16.0 github.com/tyler-smith/go-bip39 v1.1.0 - golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb + golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea ) diff --git a/go.sum b/go.sum index 535782197a..655bf99e86 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,7 @@ -4d63.com/gochecknoglobals v0.1.0 h1:zeZSRqj5yCg28tCkIV/z/lWbwvNm5qnKVS15PI8nhD0= -4d63.com/gochecknoglobals v0.1.0/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo= -bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M= +4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA= +4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= +4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc= +4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -15,7 +16,6 @@ cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6 cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.60.0/go.mod h1:yw2G51M9IfRboUH61Us8GqCeF1PzPblB823Mn2q2eAU= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= @@ -29,99 +29,105 @@ cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUM cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/compute v1.14.0 h1:hfm2+FfxVmnRlh6LpB7cg1ZNU+5edAHmW679JePztk0= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.5.0/go.mod h1:ZEwJccE3z93Z2HWvstpri00jOg7oO4UZDtKhwDwqF0w= -cloud.google.com/go/spanner v1.7.0/go.mod h1:sd3K2gZ9Fd0vMPLXzeCrF6fq4i63Q7aTLW/lBIfBkIk= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Antonboom/errname v0.1.7 h1:mBBDKvEYwPl4WFFNwec1CZO096G6vzK9vvDQzAwkako= -github.com/Antonboom/errname v0.1.7/go.mod h1:g0ONh16msHIPgJSGsecu1G/dcF2hlYR/0SddnIAGavU= -github.com/Antonboom/nilnil v0.1.1 h1:PHhrh5ANKFWRBh7TdYmyyq2gyT2lotnvFvvFbylF81Q= -github.com/Antonboom/nilnil v0.1.1/go.mod h1:L1jBqoWM7AOeTD+tSquifKSesRHs4ZdaxvZR+xdJEaI= +github.com/4meepo/tagalign v1.3.3 h1:ZsOxcwGD/jP4U/aw7qeWu58i7dwYemfy5Y+IF1ACoNw= +github.com/4meepo/tagalign v1.3.3/go.mod h1:Q9c1rYMZJc9dPRkbQPpcBNCLEmY2njbAsXhQOZFE2dE= +github.com/Abirdcfly/dupword v0.0.13 h1:SMS17YXypwP000fA7Lr+kfyBQyW14tTT+nRv9ASwUUo= +github.com/Abirdcfly/dupword v0.0.13/go.mod h1:Ut6Ue2KgF/kCOawpW4LnExT+xZLQviJPE4klBPMK/5Y= +github.com/Antonboom/errname v0.1.12 h1:oh9ak2zUtsLp5oaEd/erjB4GPu9w19NyoIskZClDcQY= +github.com/Antonboom/errname v0.1.12/go.mod h1:bK7todrzvlaZoQagP1orKzWXv59X/x0W0Io2XT1Ssro= +github.com/Antonboom/nilnil v0.1.7 h1:ofgL+BA7vlA1K2wNQOsHzLJ2Pw5B5DpWRLdDAVvvTow= +github.com/Antonboom/nilnil v0.1.7/go.mod h1:TP+ScQWVEq0eSIxqU8CbdT5DFWoHp0MbP+KMUO1BKYQ= +github.com/Antonboom/testifylint v0.2.3 h1:MFq9zyL+rIVpsvLX4vDPLojgN7qODzWsrnftNX2Qh60= +github.com/Antonboom/testifylint v0.2.3/go.mod h1:IYaXaOX9NbfAyO+Y04nfjGI8wDemC1rUyM/cYolz018= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= -github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= -github.com/GaijinEntertainment/go-exhaustruct/v2 v2.2.2 h1:DGdS4FlsdM6OkluXOhgkvwx05ZjD3Idm9WqtYnOmSuY= -github.com/GaijinEntertainment/go-exhaustruct/v2 v2.2.2/go.mod h1:xj0D2jwLdp6tOKLheyZCsfL0nz8DaicmJxSwj3VcHtY= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/GaijinEntertainment/go-exhaustruct/v3 v3.1.0 h1:3ZBs7LAezy8gh0uECsA6CGU43FF3zsx5f4eah5FxTMA= +github.com/GaijinEntertainment/go-exhaustruct/v3 v3.1.0/go.mod h1:rZLTje5A9kFBe0pzhpe2TdhRniBF++PRHQuRpR8esVc= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OpenPeeDeeP/depguard v1.1.0 h1:pjK9nLPS1FwQYGGpPxoMYpe7qACHOhAWQMQzV71i49o= -github.com/OpenPeeDeeP/depguard v1.1.0/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= +github.com/OpenPeeDeeP/depguard/v2 v2.1.0 h1:aQl70G173h/GZYhWf36aE5H0KaujXfVMnn/f1kSDVYY= +github.com/OpenPeeDeeP/depguard/v2 v2.1.0/go.mod h1:PUBgk35fX4i7JDmwzlJwJ+GMe6NfO1723wmJMgPThNQ= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= +github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= +github.com/alecthomas/go-check-sumtype v0.1.3 h1:M+tqMxB68hcgccRXBMVCPI4UJ+QUfdSx0xdbypKCqA8= +github.com/alecthomas/go-check-sumtype v0.1.3/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ= +github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= +github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alexkohler/nakedret/v2 v2.0.2 h1:qnXuZNvv3/AxkAb22q/sEsEpcA99YxLFACDtEw9TPxE= +github.com/alexkohler/nakedret/v2 v2.0.2/go.mod h1:2b8Gkk0GsOrqQv/gPWjNLDSKwG8I5moSXG1K4VIBcTQ= github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= -github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/ashanbrown/forbidigo v1.3.0 h1:VkYIwb/xxdireGAdJNZoo24O4lmnEWkactplBlWTShc= -github.com/ashanbrown/forbidigo v1.3.0/go.mod h1:vVW7PEdqEFqapJe95xHkTfB1+XvZXBFg8t0sG2FIxmI= +github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY= +github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= -github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.36.30/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bkielbasa/cyclop v1.2.0 h1:7Jmnh0yL2DjKfw28p86YTd/B4lRGcNuu12sKE35sM7A= -github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI= +github.com/bkielbasa/cyclop v1.2.1 h1:AeF71HZDob1P2/pRm1so9cd1alZnrpyc4q2uP2l0gJY= +github.com/bkielbasa/cyclop v1.2.1/go.mod h1:K/dT/M0FPAiYjBgQGau7tz+3TMh4FWAEqlMhzFWCrgM= github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= -github.com/bombsimon/wsl/v3 v3.3.0 h1:Mka/+kRLoQJq7g2rggtgQsjuI/K5Efd87WX96EWFxjM= -github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= -github.com/breml/bidichk v0.2.3 h1:qe6ggxpTfA8E75hdjWPZ581sY3a2lnl0IRxLQFelECI= -github.com/breml/bidichk v0.2.3/go.mod h1:8u2C6DnAy0g2cEq+k/A2+tr9O1s+vHGxWn0LTc70T2A= -github.com/breml/errchkjson v0.3.0 h1:YdDqhfqMT+I1vIxPSas44P+9Z9HzJwCeAzjB8PxP1xw= -github.com/breml/errchkjson v0.3.0/go.mod h1:9Cogkyv9gcT8HREpzi3TiqBxCqDzo8awa92zSDFcofU= +github.com/bombsimon/wsl/v3 v3.4.0 h1:RkSxjT3tmlptwfgEgTgU+KYKLI35p/tviNXNXiL2aNU= +github.com/bombsimon/wsl/v3 v3.4.0/go.mod h1:KkIB+TXkqy6MvK9BDZVbZxKNYsE1/oLRJbIFtf14qqo= +github.com/breml/bidichk v0.2.7 h1:dAkKQPLl/Qrk7hnP6P+E0xOodrq8Us7+U0o4UBOAlQY= +github.com/breml/bidichk v0.2.7/go.mod h1:YodjipAGI9fGcYM7II6wFvGhdMYsC5pHDlGzqvEW3tQ= +github.com/breml/errchkjson v0.3.6 h1:VLhVkqSBH96AvXEyclMR37rZslRrY2kcyq+31HCsVrA= +github.com/breml/errchkjson v0.3.6/go.mod h1:jhSDoFheAF2RSDOlCfhHO9KqhZgAYLyvHe7bRCX8f/U= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= @@ -138,21 +144,28 @@ github.com/bufbuild/buf v1.7.0 h1:uWRjhIXcrWkzIkA5TqXGyJbF51VW54QJsQZ3nwaes5Q= github.com/bufbuild/buf v1.7.0/go.mod h1:Go40fMAF46PnPLC7jJgTQhAI95pmC0+VtxFKVC0qLq0= github.com/bufbuild/connect-go v0.2.0 h1:WuMI/jLiJIhysHWvLWlxRozV67mGjCOUuDSl/lkDVic= github.com/bufbuild/connect-go v0.2.0/go.mod h1:4efZ2eXFENwd4p7tuLaL9m0qtTsCOzuBvrohvRGevDM= -github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY= -github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= +github.com/butuzov/ireturn v0.2.1 h1:w5Ks4tnfeFDZskGJ2x1GAkx5gaQV+kdU3NKNr3NEBzY= +github.com/butuzov/ireturn v0.2.1/go.mod h1:RfGHUvvAuFFxoHKf4Z8Yxuh6OjlCw1KvR2zM1NFHeBk= +github.com/butuzov/mirror v1.1.0 h1:ZqX54gBVMXu78QLoiqdwpl2mgmoOJTk7s4p4o+0avZI= +github.com/butuzov/mirror v1.1.0/go.mod h1:8Q0BdQU6rC6WILDiBM60DBfvV78OLJmMmixe7GF45AE= +github.com/catenacyber/perfsprint v0.2.0 h1:azOocHLscPjqXVJ7Mf14Zjlkn4uNua0+Hcg1wTR6vUo= +github.com/catenacyber/perfsprint v0.2.0/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50= +github.com/ccojocar/zxcvbn-go v1.0.1 h1:+sxrANSCj6CdadkcMnvde/GWU1vZiiXRbqYSCalV4/4= +github.com/ccojocar/zxcvbn-go v1.0.1/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= 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.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/charithe/durationcheck v0.0.9 h1:mPP4ucLrf/rKZiIG/a9IPXHGlh8p4CzgpyTy6EEutYk= -github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg= -github.com/chavacava/garif v0.0.0-20220316182200-5cad0b5181d4 h1:tFXjAxje9thrTF4h57Ckik+scJjTWdwAtZqZPtOT48M= -github.com/chavacava/garif v0.0.0-20220316182200-5cad0b5181d4/go.mod h1:W8EnPSQ8Nv4fUjc/v1/8tHFqhuOJXnRub0dTfuAQktU= +github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4= +github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= +github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc= +github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/chigopher/pathlib v0.15.0 h1:1pg96WL3iC1/YyWV4UJSl3E0GBf4B+h5amBtsbAAieY= github.com/chigopher/pathlib v0.15.0/go.mod h1:3+YPPV21mU9vyw8Mjp+F33CyCfE6iOzinpiqBcccv7I= @@ -168,7 +181,6 @@ github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XP github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/containerd v1.6.6 h1:xJNPhbrmz8xAMDNoVjHy9YHtWwEQNS+CDkcIRh7t8Y0= github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0= @@ -179,16 +191,10 @@ github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcD github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creachadair/atomicfile v0.2.6 h1:FgYxYvGcqREApTY8Nxg8msM6P/KVKK3ob5h9FaRUTNg= @@ -197,13 +203,13 @@ github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6V github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk= github.com/creachadair/tomledit v0.0.23 h1:ohYJjMsxwzj4dDzKaBWFbWH5J+3LO/8CYnlVY+baBWA= github.com/creachadair/tomledit v0.0.23/go.mod h1:cIu/4x5L855oSRejIqr+WRFh+mv9g4fWLiUFaApYn/Y= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= +github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= -github.com/daixiang0/gci v0.6.2 h1:TXCP5RqjE/UupXO+p33MEhqdv7QxjKGw5MVkt9ATiMs= -github.com/daixiang0/gci v0.6.2/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c= +github.com/daixiang0/gci v0.11.2 h1:Oji+oPsp3bQ6bNNgX30NBAVT18P4uBH4sRZnlOlTj7Y= +github.com/daixiang0/gci v0.11.2/go.mod h1:xtHP9N7AHdNvtRNfcx9gwTDfw7FRJx4bZUsiEfiNNAI= github.com/dashpay/bls-signatures/go-bindings v0.0.0-20230207105415-06df92693ac8 h1:v4K3CiDoFY1gjcWL/scRcwzyjBwh8TVG3ek8cWolK1g= github.com/dashpay/bls-signatures/go-bindings v0.0.0-20230207105415-06df92693ac8/go.mod h1:auvGS60NBZ+a21aCCQh366PdsjDvHinsCvl28VrYPu4= github.com/dashpay/dashd-go v0.24.1 h1:w+F5pDt+fqud4QQM/O9sAJihbQ3oswO8DKOmDS/pcNw= @@ -212,23 +218,23 @@ github.com/dashpay/dashd-go/btcec/v2 v2.1.0 h1:fXwlLf5H+TtgHxjGMU74NesKzk6NisjKM github.com/dashpay/dashd-go/btcec/v2 v2.1.0/go.mod h1:1i8XtxdOmvK6mYEUCneVXTzFbrCUw3wq1u91j8gvsns= github.com/dashpay/dashd-go/btcutil v1.2.0 h1:YMq7L0V0au5bbphIhpsBBc+nfOZqU+gJ4pkgRZB7Eiw= github.com/dashpay/dashd-go/btcutil v1.2.0/go.mod h1:7UHoqUh3LY3OI4mEcogx0CnL3rtzDQyoqvsOCZZtvzE= -github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/denis-tingaikin/go-header v0.4.3 h1:tEaZKAlqql6SKCY++utLmkPLd6K8IBM20Ha7UVm+mtU= github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= github.com/denisenkom/go-mssqldb v0.12.0 h1:VtrkII767ttSPNRfFekePK3sctr+joXgO58stqQbtUA= +github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/didip/tollbooth/v6 v6.0.1 h1:QvLvRpB1G2bzKvkRze0muMUBlGN9H1z7tJ4DH4ypWOU= @@ -236,6 +242,7 @@ github.com/didip/tollbooth/v6 v6.0.1/go.mod h1:j2pKs+JQ5PvU/K4jFnrnwntrmfUbYLJE5 github.com/didip/tollbooth_chi v0.0.0-20200524181329-8b84cd7183d9 h1:gTh8fKuI/yLqQtZEPlDX3ZGsiTPZIe0ADHsxXSbwO1I= github.com/didip/tollbooth_chi v0.0.0-20200524181329-8b84cd7183d9/go.mod h1:YWyIfq3y4ArRfWZ9XksmuusP+7Mad+T0iFZ0kv0XG/M= github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M= +github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE= @@ -245,7 +252,6 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -255,19 +261,19 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStBA= github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw= github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y= @@ -276,16 +282,18 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghostiam/protogetter v0.2.3 h1:qdv2pzo3BpLqezwqfGDLZ+nHEYmc5bUpIdsMbBVwMjw= +github.com/ghostiam/protogetter v0.2.3/go.mod h1:KmNLOsy1v04hKbvZs8EfGI1fk39AgTdRDxWNYPfXVc4= github.com/go-chi/chi v4.1.1+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= @@ -293,8 +301,8 @@ github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8= github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns= -github.com/go-critic/go-critic v0.6.3 h1:abibh5XYBTASawfTQ0rA7dVtQT+6KzpGqb/J+DxRDaw= -github.com/go-critic/go-critic v0.6.3/go.mod h1:c6b3ZP1MQ7o6lPR7Rv3lEf7pYQUmAcx8ABHgdZCQt/k= +github.com/go-critic/go-critic v0.9.0 h1:Pmys9qvU3pSML/3GEQ2Xd9RZ/ip+aXHKILuxczKGV/U= +github.com/go-critic/go-critic v0.9.0/go.mod h1:5P8tdXL7m/6qnyG6oRAlYLORvoXH0WDypYgAEmagT40= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -309,8 +317,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-pkgz/expirable-cache v0.0.3 h1:rTh6qNPp78z0bQE6HDhXBHUwqnV9i09Vm6dksJLXQDc= @@ -319,31 +327,31 @@ github.com/go-pkgz/jrpc v0.2.0 h1:CLy/eZyekjraVrxZV18N2R1mYLMJ/nWrgdfyIOGPY/E= github.com/go-pkgz/jrpc v0.2.0/go.mod h1:wd8vtQ4CgtCnuqua6x2b1SKIgv0VSOh5Dn0uUITbiUE= github.com/go-pkgz/rest v1.5.0 h1:C8SxXcXza4GiUUAn/95iCkvoIrGbS30qpwK19iqlrWQ= github.com/go-pkgz/rest v1.5.0/go.mod h1:nQaM3RhSTUAmbBZWY4hfe4buyeC9VckvhoCktiQXJxI= -github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g= -github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= -github.com/go-toolsmith/astcopy v1.0.0 h1:OMgl1b1MEpjFQ1m5ztEO06rz5CUd3oBv9RF7+DyvdG8= -github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= -github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= -github.com/go-toolsmith/astequal v1.0.1 h1:JbSszi42Jiqu36Gnf363HWS9MTEAz67vTQLponh3Moc= -github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw= -github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k= -github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= -github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg= -github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= -github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5 h1:eD9POs68PHkwrx7hAB78z1cb6PfGq/jyWn3wJywsH1o= -github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5/go.mod h1:3NAwwmD4uY/yggRxoEjk/S00MIV3A+H7rrE3i87eYxM= -github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= +github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= +github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s= +github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= +github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= +github.com/go-toolsmith/astequal v1.1.0 h1:kHKm1AWqClYn15R0K1KKE4RG614D46n+nqUQ06E1dTw= +github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= +github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco= +github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= +github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA= +github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= +github.com/go-toolsmith/pkgload v1.2.2 h1:0CtmHq/02QhxcF7E9N5LIFcYFsMR5rdovfqTtRKkgIk= +github.com/go-toolsmith/pkgload v1.2.2/go.mod h1:R2hxLNRKuAsiXCo2i5J6ZQPhnPMOVtU+f0arbFPWCus= github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= -github.com/go-toolsmith/typep v1.0.2 h1:8xdsa1+FSIH/RhEkgnD1j2CJOy5mNllW1Q9tRiYwvlk= -github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= -github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4/FHQWkvVRmgijNXRfzkIDHh23ggEo= -github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw= +github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= +github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= +github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= +github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= +github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -353,16 +361,14 @@ github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14j github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 h1:+eHOFJl1BaXrQxKX+T06f78590z4qA2ZzBTqahsKSE4= +github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -375,7 +381,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -403,26 +408,24 @@ github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9 github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe h1:6RGUuS7EGotKx6J5HIP8ZtyMdiDscjMLfRBSPuzVVeo= github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= -github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a h1:iR3fYXUjHCR97qWS8ch1y9zPNsgXThGwjKPrYfqMPks= -github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= -github.com/golangci/golangci-lint v1.48.0 h1:hRiBNk9iRqdAKMa06ntfEiLyza1/3IE9rHLNJaek4a8= -github.com/golangci/golangci-lint v1.48.0/go.mod h1:5N+oxduCho+7yuccW69upg/O7cxjfR/d+IQeiNxGmKM= +github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e h1:ULcKCDV1LOZPFxGZaA6TlQbiM3J2GCPnkx/bGF6sX/g= +github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e/go.mod h1:Pm5KhLPA8gSnQwrQ6ukebRcapGb/BG9iUkdaiCcGHJM= +github.com/golangci/golangci-lint v1.55.0 h1:ePpc6YhM1ZV8kHU8dwmHDHAdeedZHdK8cmTXlkkRdi8= +github.com/golangci/golangci-lint v1.55.0/go.mod h1:Z/OawFQ4yqFo2/plDYlIjoZlJeVYkRcqS9dW55p0FXg= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= -github.com/golangci/misspell v0.3.5 h1:pLzmVdl3VxTOncgzHcvLOKirdvcx/TydsClUQXTehjo= -github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= -github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 h1:DIPQnGy2Gv2FSA4B/hh8Q7xx3B7AIDk3DAMeHclH1vQ= -github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6/go.mod h1:0AKcRCkMoKvUvlf89F6O7H2LYdhr1zBh736mBItOdRs= +github.com/golangci/misspell v0.4.1 h1:+y73iSicVy2PqyX7kmUefHusENlrP9YwuHZHPLGQj/g= +github.com/golangci/misspell v0.4.1/go.mod h1:9mAN1quEo3DlpbaIKKyEvRxK1pwqR9s/Sea1bJCtlNI= +github.com/golangci/revgrep v0.5.0 h1:GGBqHFtFOeHiSUQtFVZXPJtVZYOGB4iVlAjaoFRBQvY= +github.com/golangci/revgrep v0.5.0/go.mod h1:bjAMA+Sh/QUfTDcHzxfyHxr4xKvllVr/0sCv2e7jJHA= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= -github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -435,11 +438,13 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= 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/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -453,40 +458,27 @@ github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw= -github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gookit/color v1.5.1/go.mod h1:wZFzea4X8qN6vHOSP2apMb4/+w/orMznEzYsIHPaqKM= -github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= -github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 h1:PVRE9d4AQKmbelZ7emNig1+NT27DUmKZn5qXxfio54U= -github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= -github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gordonklaus/ineffassign v0.0.0-20230610083614-0e73809eb601 h1:mrEEilTAUmaAORhssPPkxj84TsHrPMLBGW2Z4SoTxm8= +github.com/gordonklaus/ineffassign v0.0.0-20230610083614-0e73809eb601/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= -github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= -github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw= github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= -github.com/gostaticanalysis/comment v1.3.0/go.mod h1:xMicKDx7XRXYdVwY9f9wQpDJVnqWxw9wCauCMKp+IBI= github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q= github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= @@ -496,16 +488,13 @@ github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3 github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= +github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -517,36 +506,30 @@ github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mO github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= -github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a h1:d4+I1YEKVmWZrgkt6jpXBnLgV2ZjO0YxEtLDdfIZfH4= github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a/go.mod h1:Zi/ZFkEqFHTm7qkjyNJjaWH4LQA9LQhGJyF0lTYGpxw= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+WcM= -github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jgautheron/goconst v1.6.0 h1:gbMLWKRMkzAc6kYsQL6/TxaoBUg3Jm9LSF/Ih1ADWGA= +github.com/jgautheron/goconst v1.6.0/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ= github.com/jhump/protocompile v0.0.0-20220216033700-d705409f108f h1:BNuUg9k2EiJmlMwjoef3e8vZLHplbVw6DrjGFjLL+Yo= github.com/jhump/protocompile v0.0.0-20220216033700-d705409f108f/go.mod h1:qr2b5kx4HbFS7/g4uYO5qv9ei8303JMsC7ESbYiqr2Q= -github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E= github.com/jhump/protoreflect v1.12.1-0.20220721211354-060cc04fc18b h1:izTof8BKh/nE1wrKOrloNA5q4odOarjf+Xpe+4qow98= github.com/jhump/protoreflect v1.12.1-0.20220721211354-060cc04fc18b/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI= @@ -556,128 +539,100 @@ github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= -github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg= github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/errcheck v1.6.2 h1:uGQ9xI8/pgc9iOoCe7kWQgRE6SBTrCGmTSf0LrEtY7c= -github.com/kisielk/errcheck v1.6.2/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= +github.com/kisielk/errcheck v1.6.3 h1:dEKh+GLHcWm2oN34nMvDzn1sqI0i0WxPvrgiJA5JuM8= +github.com/kisielk/errcheck v1.6.3/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkHAIKE/contextcheck v1.1.4 h1:B6zAaLhOEEcjvUgIYEqystmnFk1Oemn8bvJhbt0GMb8= +github.com/kkHAIKE/contextcheck v1.1.4/go.mod h1:1+i/gWqokIa+dm31mqGLZhZJ7Uh44DJGZVmr6QRBNJg= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo= github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= -github.com/kunwardeep/paralleltest v1.0.6 h1:FCKYMF1OF2+RveWlABsdnmsvJrei5aoyZoaGS+Ugg8g= -github.com/kunwardeep/paralleltest v1.0.6/go.mod h1:Y0Y0XISdZM5IKm3TREQMZ6iteqn1YuwCsJO/0kL9Zes= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/kyoh86/exportloopref v0.1.8 h1:5Ry/at+eFdkX9Vsdw3qU4YkvGtzuVfzT4X7S77LoN/M= -github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= +github.com/kunwardeep/paralleltest v1.0.8 h1:Ul2KsqtzFxTlSU7IP0JusWlLiNqQaloB9vguyjbE558= +github.com/kunwardeep/paralleltest v1.0.8/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= +github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ= +github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA= github.com/ldez/gomoddirectives v0.2.3 h1:y7MBaisZVDYmKvt9/l1mjNCiSA1BVn34U0ObUcJwlhA= github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= -github.com/ldez/tagliatelle v0.3.1 h1:3BqVVlReVUZwafJUwQ+oxbx2BEX2vUG4Yu/NOfMiKiM= -github.com/ldez/tagliatelle v0.3.1/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= -github.com/leonklingele/grouper v1.1.0 h1:tC2y/ygPbMFSBOs3DcyaEMKnnwH7eYKzohOtRrf0SAg= -github.com/leonklingele/grouper v1.1.0/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= -github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= -github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo= +github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= +github.com/leonklingele/grouper v1.1.1 h1:suWXRU57D4/Enn6pXR0QVqqWWrnJ9Osrz+5rjt8ivzU= +github.com/leonklingele/grouper v1.1.1/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= +github.com/macabu/inamedparam v0.1.2 h1:RR5cnayM6Q7cDhQol32DE2BGAPGMnffJ31LFE+UklaU= +github.com/macabu/inamedparam v0.1.2/go.mod h1:Xg25QvY7IBRl1KLPV9Rbml8JOMZtF/iAkNkmV7eQgjw= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/maratori/testpackage v1.1.0 h1:GJY4wlzQhuBusMF1oahQCBtUV/AQ/k69IZ68vxaac2Q= -github.com/maratori/testpackage v1.1.0/go.mod h1:PeAhzU8qkCwdGEMTEupsHJNlQu2gZopMC6RjbhmHeDc= -github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 h1:pWxk9e//NbPwfxat7RXkts09K+dEBJWakUWwICVqYbA= -github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= +github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= +github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04= +github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= +github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE= +github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA= +github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo= github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= -github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= -github.com/mgechev/revive v1.2.1 h1:GjFml7ZsoR0IrQ2E2YIvWFNS5GPDV7xNwvA5GM1HZC4= -github.com/mgechev/revive v1.2.1/go.mod h1:+Ro3wqY4vakcYNtkBWdZC7dBg1xSB6sp054wWwmeFm0= -github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mgechev/revive v1.3.4 h1:k/tO3XTaWY4DEHal9tWBkkUMJYO/dLDVyMmAQxmIMDc= +github.com/mgechev/revive v1.3.4/go.mod h1:W+pZCMu9qj8Uhfs1iJMQsEFLRozUfvwFwqVvRbSNLVw= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/buildkit v0.10.3 h1:/dGykD8FW+H4p++q5+KqKEo6gAkYKyBQHdawdjVwVAU= github.com/moby/buildkit v0.10.3/go.mod h1:jxeOuly98l9gWHai0Ojrbnczrk/rf+o9/JqNhY+UCSo= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= @@ -688,31 +643,25 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/moricho/tparallel v0.2.1 h1:95FytivzT6rYzdJLdtfn6m1bfFJylOJK41+lgv/EHf4= -github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= +github.com/moricho/tparallel v0.3.1 h1:fQKD4U1wRMAYNngDonW5XupoB/ZGJHdpzrWqgyg9krA= +github.com/moricho/tparallel v0.3.1/go.mod h1:leENX2cUv7Sv2qDgdi0D0fCftN8fRC67Bcn8pqzeYNI= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8= -github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= github.com/mroth/weightedrand v0.4.1 h1:rHcbUBopmi/3x4nnrvwGJBhX9d0vk+KgoLUZeDP6YyI= github.com/mroth/weightedrand v0.4.1/go.mod h1:3p2SIcC8al1YMzGhAIoXD+r9olo/g/cdJgAD905gyNE= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= -github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= -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.8.1 h1:0QKNascWv9qIHY7zRoZSxeRr6kuk5aAT3YXLTiDmjTo= -github.com/nishanths/exhaustive v0.8.1/go.mod h1:qj+zJJUgJ76tR92+25+03oYUhzF4R7/2Wk7fGTfCHmg= -github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ= +github.com/nishanths/exhaustive v0.11.0 h1:T3I8nUGhl/Cwu5Z2hfc92l0e04D2GEW6e0l8pzda2l0= +github.com/nishanths/exhaustive v0.11.0/go.mod h1:RqwDsZ1xY0dNdqHho2z6X+bgzizwbLYOWnZbbl2wLB4= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= +github.com/nunnatsa/ginkgolinter v0.14.0 h1:XQPNmw+kZz5cC/HbFK3mQutpjzAQv1dHregRA+4CGGg= +github.com/nunnatsa/ginkgolinter v0.14.0/go.mod h1:cm2xaqCUCRd7qcP4DqbVvpcyEMkuLM9CF0wY6VASohk= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -720,27 +669,21 @@ github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae h1:Fa github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= github.com/oasisprotocol/oasis-core/go v0.2202.5 h1:SwT3XIKz4W5gYZd9I2fe+4qGPYaVvqG0kF8jsancd4E= github.com/oasisprotocol/oasis-core/go v0.2202.5/go.mod h1:hKUgtuPPq371HokUQL5ashT5MZLZxK/VkWNKRLb9m+w= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= -github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA= +github.com/onsi/ginkgo/v2 v2.12.1/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= -github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.28.0 h1:i2rg/p9n/UqIDAMFUJ6qIUUMcsqOuUHgbpbu235Vr1c= +github.com/onsi/gomega v1.28.0/go.mod h1:A1H2JE76sI14WIP57LMKj7FVfCHx3g3BcZVjJG8bjX8= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= @@ -753,8 +696,10 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/ory/dockertest/v3 v3.9.1 h1:v4dkG+dlu76goxMiTT2j8zV7s4oPPEppKT8K8p2f1kY= -github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= +github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= +github.com/otiai10/copy v1.11.0 h1:OKBD80J/mLBrwnzXqGtFCzprFSGioo30JcmR4APsNwc= +github.com/otiai10/copy v1.11.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= @@ -762,11 +707,8 @@ github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= -github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d h1:CdDQnGF8Nq9ocOS/xlSptM1N3BbrA6/kmaep5ggwaIA= -github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -776,11 +718,10 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/profile v1.6.0 h1:hUDfIISABYI59DyeB3OTay/HxSRwTQ8rB/H83k6r5dM= github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polyfloyd/go-errorlint v1.0.0 h1:pDrQG0lrh68e602Wfp68BlUTRFoHn8PZYAjLgt2LFsM= -github.com/polyfloyd/go-errorlint v1.0.0/go.mod h1:KZy4xxPJyy88/gldCe5OdW6OQRtNO3EZE7hXzmnebgA= +github.com/polyfloyd/go-errorlint v1.4.5 h1:70YWmMy4FgRHehGNOUask3HtSFSOLKgmDn7ryNe7LqI= +github.com/polyfloyd/go-errorlint v1.4.5/go.mod h1:sIZEbFoDOCnTYYZoVkjc4hTnM459tuWA9H/EkdXwsKk= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -806,26 +747,18 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= -github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= -github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= -github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a h1:sWFavxtIctGrVs5SYZ5Ml1CvrDAs8Kf5kx2PI3C41dA= -github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a/go.mod h1:VMX+OnnSw4LicdiEGtRSD/1X8kW7GuEscjYNr4cOIT4= -github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= -github.com/quasilyte/go-ruleguard/dsl v0.3.16/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= -github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= -github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= -github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5 h1:PDWGei+Rf2bBiuZIbZmM20J2ftEy9IeUCHA8HbQqed8= -github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5/go.mod h1:wSEyW6O61xRV6zb6My3HxrQ5/8ke7NE2OayqCHa3xRM= -github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 h1:L8QM9bvf68pVdQ3bCFZMDmnt9yqcMBro1pC7F+IPYMY= -github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= +github.com/quasilyte/go-ruleguard v0.4.0 h1:DyM6r+TKL+xbKB4Nm7Afd1IQh9kEUKQs2pboWGKtvQo= +github.com/quasilyte/go-ruleguard v0.4.0/go.mod h1:Eu76Z/R8IXtViWUIHkE3p8gdH3/PKk1eh3YGfaEof10= +github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= +github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= +github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= +github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= -github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -835,20 +768,21 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryancurrah/gomodguard v1.2.4 h1:CpMSDKan0LtNGGhPrvupAoLeObRFjND8/tU1rEOtBp4= -github.com/ryancurrah/gomodguard v1.2.4/go.mod h1:+Kem4VjWwvFpUJRJSwa16s1tBJe+vbv02+naTow2f6M= -github.com/ryanrolds/sqlclosecheck v0.3.0 h1:AZx+Bixh8zdUBxUA1NxbxVAS78vTPq4rCb8OUZI9xFw= -github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA= -github.com/sanposhiho/wastedassign/v2 v2.0.6 h1:+6/hQIHKNJAUixEj6EmOngGIisyeI+T3335lYTyxRoA= -github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= +github.com/ryancurrah/gomodguard v1.3.0 h1:q15RT/pd6UggBXVBuLps8BXRvl5GPBcwVA7BJHMLuTw= +github.com/ryancurrah/gomodguard v1.3.0/go.mod h1:ggBxb3luypPEzqVtq33ee7YSN35V28XeGnid8dnni50= +github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= +github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= +github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc= +github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= -github.com/sashamelentyev/usestdlibvars v1.8.0 h1:QnWP9IOEuRyYKH+IG0LlQIjuJlc0rfdo4K3/Zh3WRMw= -github.com/sashamelentyev/usestdlibvars v1.8.0/go.mod h1:BFt7b5mSVHaaa26ZupiNRV2ODViQBxZZVhtAxAJRrjs= +github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= +github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= +github.com/sashamelentyev/usestdlibvars v1.24.0 h1:MKNzmXtGh5N0y74Z/CIaJh4GlB364l0K1RUT08WSWAc= +github.com/sashamelentyev/usestdlibvars v1.24.0/go.mod h1:9cYkq+gYJ+a5W2RPdhfaSCnTVUC1OQP/bSiiBhq3OZE= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= -github.com/securego/gosec/v2 v2.12.0 h1:CQWdW7ATFpvLSohMVsajscfyHJ5rsGmEXmsNcsDNmAg= -github.com/securego/gosec/v2 v2.12.0/go.mod h1:iTpT+eKTw59bSgklBHlSnH5O2tNygHMDxfvMubA4i7I= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/securego/gosec/v2 v2.18.1 h1:xnnehWg7dIW8qrRPGm8ykY21zp2MueKyC99Vlcuj96I= +github.com/securego/gosec/v2 v2.18.1/go.mod h1:ZUTcKD9gAFip1lLGHWCjkoBQJyaEzePTNzjwlL2HHoE= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= @@ -859,21 +793,20 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/sivchari/containedctx v1.0.2 h1:0hLQKpgC53OVF1VT7CeoFHk9YKstur1XOgfYIc1yrHI= -github.com/sivchari/containedctx v1.0.2/go.mod h1:PwZOeqm4/DLoJOqMSIJs3aKqXRX4YO+uXww087KZ7Bw= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= +github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= github.com/sivchari/nosnakecase v1.7.0 h1:7QkpWIRMe8x25gckkFd2A5Pi6Ymo0qgr4JrhGt95do8= github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY= -github.com/sivchari/tenv v1.7.0 h1:d4laZMBK6jpe5PWepxlV9S+LC0yXqvYHiq8E6ceoVVE= -github.com/sivchari/tenv v1.7.0/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= +github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak= +github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa h1:YJfZp12Z3AFhSBeXOlv4BO55RMwPn2NoQeDsrdWnBtY= github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sonatard/noctx v0.0.1 h1:VC1Qhl6Oxx9vvWo3UDgrGXYCeKCe3Wbw7qAWL6FrmTY= -github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= -github.com/sourcegraph/go-diff v0.6.1 h1:hmA1LzxW0n1c3Q4YbrFgg4P99GSnebYa3x8gr0HZqLQ= -github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= +github.com/sonatard/noctx v0.0.2 h1:L7Dz4De2zDQhW8S0t+KUjY0MAQJd6SgVwhzNIc4ok00= +github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo= +github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= +github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -883,14 +816,12 @@ github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcD github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -906,29 +837,25 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/sylvia7788/contextcheck v1.0.4 h1:MsiVqROAdr0efZc/fOCt0c235qm9XJqHtWwM+2h2B04= -github.com/sylvia7788/contextcheck v1.0.4/go.mod h1:vuPKJMQ7MQ91ZTqfdyreNKwZjyUg6KO+IebVyQDedZQ= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= -github.com/tdakkota/asciicheck v0.1.1 h1:PKzG7JUTUmVspQTDqtkX9eSiLGossXTybutHwTXuO0A= -github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= +github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c h1:+aPplBwWcHBo6q9xrfWdMrT9o4kltkmmvpemgIjep/8= +github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk= +github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM= +github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= @@ -941,63 +868,62 @@ github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= -github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw= -github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= -github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 h1:kl4KhGNsJIbDHS9/4U9yQo1UcPQM0kOMJHn29EoH/Ro= -github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tomarrell/wrapcheck/v2 v2.6.2 h1:3dI6YNcrJTQ/CJQ6M/DUkc0gnqYSIk6o0rChn9E/D0M= -github.com/tomarrell/wrapcheck/v2 v2.6.2/go.mod h1:ao7l5p0aOlUNJKI0qVwB4Yjlqutd0IvAB9Rdwyilxvg= -github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= -github.com/tommy-muehle/go-mnd/v2 v2.5.0 h1:iAj0a8e6+dXSL7Liq0aXPox36FiN1dBbjA6lt9fl65s= -github.com/tommy-muehle/go-mnd/v2 v2.5.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= +github.com/tetafro/godot v1.4.15 h1:QzdIs+XB8q+U1WmQEWKHQbKmCw06QuQM7gLx/dky2RM= +github.com/tetafro/godot v1.4.15/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= +github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M= +github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= +github.com/timonwong/loggercheck v0.9.4 h1:HKKhqrjcVj8sxL7K77beXh0adEm6DLjV/QOGeMXEVi4= +github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg= +github.com/tomarrell/wrapcheck/v2 v2.8.1 h1:HxSqDSN0sAt0yJYsrcYVoEeyM4aI9yAm3KQpIXDJRhQ= +github.com/tomarrell/wrapcheck/v2 v2.8.1/go.mod h1:/n2Q3NZ4XFT50ho6Hbxg+RV1uyo2Uow/Vdm9NQcl5SE= +github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= +github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ultraware/funlen v0.0.3 h1:5ylVWm8wsNwH5aWo9438pwvsK0QiqVuUrt9bn7S/iLA= -github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= +github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81vI= +github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4= github.com/ultraware/whitespace v0.0.5 h1:hh+/cpIcopyMYbZNVov9iSxvJU3OYQg78Sfaqzi/CzI= github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/uudashr/gocognit v1.0.6 h1:2Cgi6MweCsdB6kpcVQp7EW4U23iBFQWfTXiWlyp842Y= -github.com/uudashr/gocognit v1.0.6/go.mod h1:nAIUuVBnYU7pcninia3BHOvQkpQCeO76Uscky5BOwcY= +github.com/uudashr/gocognit v1.1.2 h1:l6BAEKJqQH2UpKAPKdMfZf5kE4W/2xk8pfU1OVLvniI= +github.com/uudashr/gocognit v1.1.2/go.mod h1:aAVdLURqcanke8h3vg35BC++eseDm66Z7KmchI5et4k= github.com/vektra/mockery/v2 v2.33.2 h1:znIUwQ3FxnA5jvPy8irYBoiIqMZhuOJhoPOJYNoTJqU= github.com/vektra/mockery/v2 v2.33.2/go.mod h1:9lREs4VEeQiUS3rizYQx1saxHu2JiIhThP0q9+fDegM= -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/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -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/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU= +github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= github.com/yeya24/promlinter v0.2.0 h1:xFKDQ82orCU5jQujdaD8stOHiv8UN68BSdn2a8u8Y3o= github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA= -github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/ykadowak/zerologlint v0.1.3 h1:TLy1dTW3Nuc+YE3bYRPToG1Q9Ej78b5UUN6bjbGdxPE= +github.com/ykadowak/zerologlint v0.1.3/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -gitlab.com/bosi/decorder v0.2.3 h1:gX4/RgK16ijY8V+BRQHAySfQAb354T7/xQpDB2n10P0= -gitlab.com/bosi/decorder v0.2.3/go.mod h1:9K1RB5+VPNQYtXtTDAzd2OEftsZb1oV0IrJrzChSdGE= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +gitlab.com/bosi/decorder v0.4.1 h1:VdsdfxhstabyhZovHafFw+9eJ6eU0d2CkFNJcZz/NU4= +gitlab.com/bosi/decorder v0.4.1/go.mod h1:jecSqWUew6Yle1pCr2eLWTensJMmsxHsBwt+PVbkAqA= +go-simpler.org/assert v0.6.0 h1:QxSrXa4oRuo/1eHMXSBFHKvJIpWABayzKldqZyugG7E= +go-simpler.org/assert v0.6.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= +go-simpler.org/sloglint v0.1.2 h1:IjdhF8NPxyn0Ckn2+fuIof7ntSnVUAqBFcQRrnG9AiM= +go-simpler.org/sloglint v0.1.2/go.mod h1:2LL+QImPfTslD5muNPydAEYmpXIj6o/WYcqnJjLi4o4= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= -go.etcd.io/etcd v0.0.0-20200513171258-e048e166ab9c/go.mod h1:xCI7ZzBfRuGgBXyXO6yfWfDmlWd35khcWpUa4L0xI/k= -go.mozilla.org/mozlog v0.0.0-20170222151521-4bb13139d403/go.mod h1:jHoPAGnDrCy6kaI2tAze5Prf0Nr0w/oNkROt2lw3n3o= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -1013,25 +939,21 @@ go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRM go.opentelemetry.io/otel/trace v1.8.0 h1:cSy0DF9eGI5WIfNwZ1q2iUyGj00tGzP24dE1lOlHrfY= go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.tmz.dev/musttag v0.7.2 h1:1J6S9ipDbalBSODNT5jCep8dhZyMr4ttnjQagmGYR5s= +go.tmz.dev/musttag v0.7.2/go.mod h1:m6q5NiiSKMnQYokefa2xGoyoXnrswCbJ0AWYzf4Zs28= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= -go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -1040,13 +962,12 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/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-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1057,11 +978,12 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb h1:PaBZQdo+iSDyHT053FjUCgZQ/9uqVwPOcl7KSWhKn6w= -golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d h1:+W8Qf4iJtMGKkyAygcKohjxTk4JPsL9DpzApJ22m5Ic= -golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea h1:vLCWI/yYrdEHyN2JzIzPO3aaQJHQdp89IZBA/+azVC4= +golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833 h1:jWGQJV4niP+CCmFW9ekjA9Zx8vYORzOUH2/Nl5WPuLQ= +golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1075,7 +997,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -1090,13 +1011,15 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1108,9 +1031,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1118,7 +1038,6 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -1135,14 +1054,17 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1155,11 +1077,11 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1167,16 +1089,16 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1187,12 +1109,9 @@ golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1200,7 +1119,6 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1208,7 +1126,6 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1224,7 +1141,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1245,19 +1161,26 @@ golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1266,28 +1189,24 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190307163923-6a08e3108db3/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1298,22 +1217,16 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1326,35 +1239,22 @@ golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -1363,12 +1263,16 @@ golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0t golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1377,7 +1281,6 @@ google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEt google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= @@ -1397,15 +1300,12 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1413,7 +1313,6 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= @@ -1434,8 +1333,6 @@ google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200707001353-8e8330bf89df/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1448,19 +1345,15 @@ google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY= google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= @@ -1494,27 +1387,19 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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/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= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.6/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -1527,6 +1412,7 @@ gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1534,19 +1420,18 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA= -honnef.co/go/tools v0.3.3/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= -mvdan.cc/gofumpt v0.3.1 h1:avhhrOmv0IuvQVK7fvwV91oFSGAk5/6Po8GXTzICeu8= -mvdan.cc/gofumpt v0.3.1/go.mod h1:w3ymliuxvzVx8DAutBnVyDqYb1Niy/yCJt/lk821YCE= +honnef.co/go/tools v0.4.6 h1:oFEHCKeID7to/3autwsWfnuv69j3NsfcXbvJKuIcep8= +honnef.co/go/tools v0.4.6/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0= +mvdan.cc/gofumpt v0.5.0 h1:0EQ+Z56k8tXjj/6TQD25BFNKQXpCvT0rnansIc7Ug5E= +mvdan.cc/gofumpt v0.5.0/go.mod h1:HBeVDtMKRZpXyxFciAirzdKklDlGu8aAy1wEbH5Y9js= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= -mvdan.cc/unparam v0.0.0-20220706161116-678bad134442 h1:seuXWbRB1qPrS3NQnHmFKLJLtskWyueeIzmLXghMGgk= -mvdan.cc/unparam v0.0.0-20220706161116-678bad134442/go.mod h1:F/Cxw/6mVrNKqrR2YjFf5CaW0Bw4RL8RfbEf4GRggJk= +mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d h1:3rvTIIM22r9pvXk+q3swxUQAQOxksVMGK7sml4nG57w= +mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d/go.mod h1:IeHQjmn6TOD+e4Z3RFiZMMsLVL+A96Nvptar8Fj71is= pgregory.net/rapid v0.4.8 h1:d+5SGZWUbJPbl3ss6tmPFqnNeQR6VDOFly+eTjwPiEw= pgregory.net/rapid v0.4.8/go.mod h1:Z5PbWqjvWR1I3UGjvboUuan4fe4ZYEYNLNQLExzCoUs= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/internal/blocksync/reactor_test.go b/internal/blocksync/reactor_test.go index a882b2e2a4..f9c7d7a7d4 100644 --- a/internal/blocksync/reactor_test.go +++ b/internal/blocksync/reactor_test.go @@ -239,8 +239,8 @@ func makeNextBlock(ctx context.Context, blockID, &types.CommitSigns{ QuorumSigns: types.QuorumSigns{ - BlockSign: vote.BlockSignature, - ExtensionSigns: types.MakeThresholdExtensionSigns(vote.VoteExtensions), + BlockSign: vote.BlockSignature, + ThresholdVoteExtensions: vote.VoteExtensions.Filter(func(ext types.VoteExtensionIf) bool { return ext.IsThresholdRecoverable() }), }, QuorumHash: state.Validators.QuorumHash, }, diff --git a/internal/consensus/common_test.go b/internal/consensus/common_test.go index ab0abea525..f1f3c5ed3d 100644 --- a/internal/consensus/common_test.go +++ b/internal/consensus/common_test.go @@ -157,10 +157,10 @@ func signVote( blockID types.BlockID, quorumType btcjson.LLMQType, quorumHash crypto.QuorumHash) *types.Vote { - exts := make(types.VoteExtensions) + exts := make(types.VoteExtensions, 0) if voteType == tmproto.PrecommitType && !blockID.IsNil() { - exts.Add(tmproto.VoteExtensionType_DEFAULT, tmproto.VoteExtension{ - Type: tmproto.VoteExtensionType_DEFAULT, + exts.Add(tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, Extension: []byte("extension")}) } v, err := vs.signVote(ctx, voteType, chainID, blockID, quorumType, quorumHash, exts) @@ -1111,7 +1111,7 @@ func signDataIsEqual(v1 *types.Vote, v2 *tmproto.Vote) bool { if v1 == nil || v2 == nil { return false } - if v1.VoteExtensions.IsSameWithProto(v2.VoteExtensionsToMap()) { + if v1.VoteExtensions.IsSameWithProto(v2.VoteExtensions) { return false } return v1.Type == v2.Type && diff --git a/internal/consensus/gossiper_test.go b/internal/consensus/gossiper_test.go index 09d0cd9347..7007b31b2c 100644 --- a/internal/consensus/gossiper_test.go +++ b/internal/consensus/gossiper_test.go @@ -603,6 +603,6 @@ func (suite *GossiperSuiteTest) signVote(vote *types.Vote) { err := privVal.SignVote(ctx, factory.DefaultTestChainID, suite.valSet.QuorumType, suite.valSet.QuorumHash, protoVote, nil) suite.Require().NoError(err) vote.BlockSignature = protoVote.BlockSignature - err = vote.VoteExtensions.CopySignsFromProto(protoVote.VoteExtensionsToMap()) + err = vote.VoteExtensions.CopySignsFromProto(protoVote.VoteExtensions) suite.Require().NoError(err) } diff --git a/internal/consensus/msgs_test.go b/internal/consensus/msgs_test.go index cf0078c944..85211b2af0 100644 --- a/internal/consensus/msgs_test.go +++ b/internal/consensus/msgs_test.go @@ -384,9 +384,10 @@ func TestConsMsgsVectors(t *testing.T) { Round: 0, Type: tmproto.PrecommitType, BlockID: bi, - VoteExtensions: types.VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("extension")}}, - }, + VoteExtensions: types.VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_DEFAULT, + Extension: []byte("extension"), + }), } vpb := v.ToProto() diff --git a/internal/consensus/replay_test.go b/internal/consensus/replay_test.go index a82fe66731..7fbc9d3139 100644 --- a/internal/consensus/replay_test.go +++ b/internal/consensus/replay_test.go @@ -1123,8 +1123,8 @@ func makeBlockchainFromWAL(t *testing.T, wal WAL) ([]*types.Block, []*types.Comm p.BlockID, &types.CommitSigns{ QuorumSigns: types.QuorumSigns{ - BlockSign: p.BlockSignature, - ExtensionSigns: types.MakeThresholdExtensionSigns(p.VoteExtensions), + BlockSign: p.BlockSignature, + ThresholdVoteExtensions: p.VoteExtensions, }, QuorumHash: crypto.RandQuorumHash(), }, diff --git a/internal/consensus/state_test.go b/internal/consensus/state_test.go index 54fb69b852..7473f7220b 100644 --- a/internal/consensus/state_test.go +++ b/internal/consensus/state_test.go @@ -2143,7 +2143,7 @@ func TestExtendVote(t *testing.T) { voteExtensions := []*abci.ExtendVoteExtension{ { - Type: tmproto.VoteExtensionType_DEFAULT, + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, Extension: []byte("extension"), }, } @@ -2159,7 +2159,7 @@ func TestExtendVote(t *testing.T) { m.On("ExtendVote", mock.Anything, mock.Anything).Return(&abci.ResponseExtendVote{ VoteExtensions: []*abci.ExtendVoteExtension{ { - Type: tmproto.VoteExtensionType_DEFAULT, + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, Extension: []byte("extension"), }, }, @@ -2304,7 +2304,7 @@ func TestVerifyVoteExtensionNotCalledOnAbsentPrecommit(t *testing.T) { defer cancel() voteExtensions := []*abci.ExtendVoteExtension{ { - Type: tmproto.VoteExtensionType_DEFAULT, + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, Extension: []byte("extension"), }, } @@ -2381,7 +2381,7 @@ func TestVerifyVoteExtensionNotCalledOnAbsentPrecommit(t *testing.T) { Round: round, VoteExtensions: []*abci.ExtendVoteExtension{ { - Type: tmproto.VoteExtensionType_DEFAULT, + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, Extension: []byte("extension"), }, }, @@ -2405,8 +2405,8 @@ func TestPrepareProposalReceivesVoteExtensions(t *testing.T) { m.On("ExtendVote", mock.Anything, mock.Anything).Return(&abci.ResponseExtendVote{ VoteExtensions: []*abci.ExtendVoteExtension{ { - Type: tmproto.VoteExtensionType_DEFAULT, - Extension: []byte("extension"), + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, + Extension: crypto.Checksum([]byte("extension-raw")), }, { Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, @@ -2430,7 +2430,24 @@ func TestPrepareProposalReceivesVoteExtensions(t *testing.T) { m.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{AppHash: make([]byte, crypto.DefaultAppHashSize)}, nil).Once() m.On("VerifyVoteExtension", mock.Anything, mock.Anything).Return(&abci.ResponseVerifyVoteExtension{Status: abci.ResponseVerifyVoteExtension_ACCEPT}, nil) - m.On("FinalizeBlock", mock.Anything, mock.Anything).Return(&abci.ResponseFinalizeBlock{}, nil) + + // no vote extensions are present + m.On("FinalizeBlock", mock.Anything, mock.MatchedBy(func(r *abci.RequestFinalizeBlock) bool { + return len(r.Commit.ThresholdVoteExtensions) == 0 + })).Return(&abci.ResponseFinalizeBlock{}, nil) + + // we expect 2 threshold-recovered vote extensions + m.On("FinalizeBlock", mock.Anything, mock.MatchedBy(func(r *abci.RequestFinalizeBlock) bool { + if len(r.Commit.ThresholdVoteExtensions) != 0 { + return false + } + t.Logf("FinalizeBlock with %d vote extensions", len(r.Commit.ThresholdVoteExtensions)) + + vexts := r.Commit.ThresholdVoteExtensions + + return bytes.Equal(vexts[0].Extension, []byte("deterministic")) && + bytes.Equal(vexts[1].Extension, crypto.Checksum([]byte("raw"))) + })).Return(&abci.ResponseFinalizeBlock{}, nil).Once() cs1, vss := makeState(ctx, t, makeStateArgs{config: config, application: m}) stateData := cs1.GetStateData() @@ -2453,21 +2470,22 @@ func TestPrepareProposalReceivesVoteExtensions(t *testing.T) { // create a precommit for each validator with the associated vote extension. for _, vs := range vss[1:] { - voteExtensions := types.VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{ - { - Type: tmproto.VoteExtensionType_DEFAULT, - Extension: []byte("extension"), - }, + voteExtensions := tmproto.VoteExtensions{ + { + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("extension"), }, - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{ - { - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Extension: []byte("deterministic"), - }, + { + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("deterministic"), + }, + { + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, + Extension: crypto.Checksum([]byte("raw")), }, } - signAddPrecommitWithExtension(ctx, t, cs1, config.ChainID(), blockID, voteExtensions, vs) + + signAddPrecommitWithExtension(ctx, t, cs1, config.ChainID(), blockID, types.VoteExtensionsFromProto(voteExtensions...), vs) } ensurePrevote(t, voteCh, height, round) @@ -2491,6 +2509,7 @@ func TestPrepareProposalReceivesVoteExtensions(t *testing.T) { // ensure that the proposer received the list of vote extensions from the // previous height. require.Len(t, rpp.LocalLastCommit.ThresholdVoteExtensions, 1) + m.AssertExpectations(t) } // 4 vals, 3 Nil Precommits at P0 @@ -3328,7 +3347,7 @@ func mockProposerApplicationCalls(t *testing.T, m *abcimocks.Application, round m.On("ExtendVote", mock.Anything, roundMatcher). Return(&abci.ResponseExtendVote{ VoteExtensions: []*abci.ExtendVoteExtension{{ - Type: tmproto.VoteExtensionType_DEFAULT, + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, Extension: []byte("extension"), }}, }, nil).Once() diff --git a/internal/consensus/types/height_vote_set_test.go b/internal/consensus/types/height_vote_set_test.go index 19223279b3..b65ab9ed6a 100644 --- a/internal/consensus/types/height_vote_set_test.go +++ b/internal/consensus/types/height_vote_set_test.go @@ -87,7 +87,7 @@ func makeVoteHR( require.NoError(t, err, "Error signing vote") vote.BlockSignature = v.BlockSignature - err = vote.VoteExtensions.CopySignsFromProto(v.VoteExtensionsToMap()) + err = vote.VoteExtensions.CopySignsFromProto(v.VoteExtensions) require.NoError(t, err) return vote diff --git a/internal/consensus/vote_signer_test.go b/internal/consensus/vote_signer_test.go index 0189e19f43..89b2244c3d 100644 --- a/internal/consensus/vote_signer_test.go +++ b/internal/consensus/vote_signer_test.go @@ -39,14 +39,11 @@ func TestVoteSigner_signAddVote(t *testing.T) { PrivValidator: priVals[0], ProTxHash: proTxHash, } - voteExtensions := types.VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{ - { - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Extension: tmbytes.MustHexDecode("524F1D03D1D81E94A099042736D40BD9681B867321443FF58A4568E274DBD83B"), - }, - }, - } + voteExtensions := tmproto.VoteExtensions{{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: tmbytes.MustHexDecode("524F1D03D1D81E94A099042736D40BD9681B867321443FF58A4568E274DBD83B"), + }} + conf := configSetup(t) stateData := StateData{ config: conf.Consensus, @@ -106,7 +103,7 @@ func TestVoteSigner_signAddVote(t *testing.T) { { msgType: tmproto.PrecommitType, blockID: blockID, - voteExtensions: voteExtensions, + voteExtensions: types.VoteExtensionsFromProto(voteExtensions...), mockFn: mockFn, wantBlockSign: "B2C484BB07094AAB8EFAB187982F6A8E8172FBEBAE5B6EB6304E527ABAAB7D059D9A43DDDBA82A6D296AF30E67C28D250449A586E9A69C2577057E01FA290BB03C186982D4D45E6016935AD4B9A84EB0911B62A83E457E25CE44DC28516D0E0A", }, @@ -145,7 +142,6 @@ func TestVoteSigner_signAddVote(t *testing.T) { assert.NoError(t, err) t.Logf("key: %x", key1.Serialize()) - t.Logf("%+v", vote.VoteExtensions[tmproto.VoteExtensionType_THRESHOLD_RECOVER]) }) } } diff --git a/internal/state/execution.go b/internal/state/execution.go index e1d7bd220c..98ba693c40 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -615,7 +615,7 @@ func buildLastCommitInfo(block *types.Block, initialHeight int64) abci.CommitInf Round: block.LastCommit.Round, QuorumHash: block.LastCommit.QuorumHash, BlockSignature: block.LastCommit.ThresholdBlockSignature, - ThresholdVoteExtensions: types.ThresholdExtensionSignToProto(block.LastCommit.ThresholdVoteExtensions), + ThresholdVoteExtensions: block.LastCommit.ThresholdVoteExtensions.ToProto(), } } diff --git a/internal/state/validation_test.go b/internal/state/validation_test.go index 281ac4eb7e..eb6632d2fe 100644 --- a/internal/state/validation_test.go +++ b/internal/state/validation_test.go @@ -328,8 +328,8 @@ func TestValidateBlockCommit(t *testing.T) { require.NoError(t, err, "height %d", height) goodVote.BlockSignature, badVote.BlockSignature = g.BlockSignature, b.BlockSignature - goodVote.VoteExtensions = types.VoteExtensionsFromProto(g.VoteExtensions) - badVote.VoteExtensions = types.VoteExtensionsFromProto(b.VoteExtensions) + goodVote.VoteExtensions = types.VoteExtensionsFromProto(g.VoteExtensions...) + badVote.VoteExtensions = types.VoteExtensionsFromProto(b.VoteExtensions...) thresholdSigns, err := types.NewSignsRecoverer([]*types.Vote{badVote}).Recover() require.NoError(t, err) diff --git a/internal/store/store_test.go b/internal/store/store_test.go index 1b03e7ef25..f72816b640 100644 --- a/internal/store/store_test.go +++ b/internal/store/store_test.go @@ -53,7 +53,7 @@ func makeTestCommit(state sm.State, height int64, timestamp time.Time) *types.Co _ = privVal.SignVote(context.Background(), "chainID", state.Validators.QuorumType, state.Validators.QuorumHash, g, nil) goodVote.BlockSignature = g.BlockSignature - goodVote.VoteExtensions = types.VoteExtensionsFromProto(g.VoteExtensions) + goodVote.VoteExtensions = types.VoteExtensionsFromProto(g.VoteExtensions...) thresholdSigns, _ := types.NewSignsRecoverer([]*types.Vote{goodVote}).Recover() return types.NewCommit(height, 0, diff --git a/internal/test/factory/commit.go b/internal/test/factory/commit.go index 2b277d4a05..6d245659fc 100644 --- a/internal/test/factory/commit.go +++ b/internal/test/factory/commit.go @@ -39,7 +39,7 @@ func MakeCommit( } vote.BlockSignature = v.BlockSignature - err = vote.VoteExtensions.CopySignsFromProto(v.VoteExtensionsToMap()) + err = vote.VoteExtensions.CopySignsFromProto(v.VoteExtensions) if err != nil { return nil, err } diff --git a/internal/test/factory/vote.go b/internal/test/factory/vote.go index c8bcdeb88d..7a5110858f 100644 --- a/internal/test/factory/vote.go +++ b/internal/test/factory/vote.go @@ -40,8 +40,7 @@ func MakeVote( v.BlockSignature = vpb.BlockSignature - err = v.VoteExtensions.CopySignsFromProto(vpb.VoteExtensionsToMap()) - v.VoteExtensions = types.VoteExtensionsFromProto(vpb.VoteExtensions) + err = v.VoteExtensions.CopySignsFromProto(vpb.VoteExtensions) if err != nil { return nil, err diff --git a/privval/dash_core_signer_client.go b/privval/dash_core_signer_client.go index 402a759b1d..14a3d2704a 100644 --- a/privval/dash_core_signer_client.go +++ b/privval/dash_core_signer_client.go @@ -375,15 +375,15 @@ func (sc *DashCoreSignerClient) signVoteExtensions( } return nil } - for et, extensions := range protoVote.VoteExtensionsToMap() { - for i, ext := range extensions { - signItem := quorumSignData.Extensions[et][i] - resp, err := sc.quorumSignAndVerify(ctx, quorumType, quorumHash, signItem) - if err != nil { - return err - } - ext.Signature = resp.sign + + for i, ext := range quorumSignData.ThresholdVoteExtensions { + signItem := ext + resp, err := sc.quorumSignAndVerify(ctx, quorumType, quorumHash, signItem) + if err != nil { + return err } + + protoVote.VoteExtensions[i].Signature = resp.sign } return nil } diff --git a/privval/file.go b/privval/file.go index 3f6492841f..8023d439d3 100644 --- a/privval/file.go +++ b/privval/file.go @@ -686,16 +686,14 @@ func (pv *FilePV) signVote( // application may have created a different extension. We therefore always // re-sign the vote extensions of precommits. For prevotes, the extension // signature will always be empty. - extSigns := make(map[tmproto.VoteExtensionType][]tmbytes.HexBytes) + extSigns := make([]tmbytes.HexBytes, 0, len(quorumSigns.ThresholdVoteExtensions)) if vote.Type == tmproto.PrecommitType { - for et, signItems := range quorumSigns.Extensions { - for _, signItem := range signItems { - extSig, err := privKey.SignDigest(signItem.ID) - if err != nil { - return err - } - extSigns[et] = append(extSigns[et], extSig) + for _, signItem := range quorumSigns.ThresholdVoteExtensions { + extSig, err := privKey.SignDigest(signItem.ID) + if err != nil { + return err } + extSigns = append(extSigns, extSig) } } else if len(vote.VoteExtensions) > 0 { return errors.New("unexpected vote extension - extensions are only allowed in precommits") @@ -712,7 +710,7 @@ func (pv *FilePV) signVote( } else { return errors.New("conflicting data") } - fillProtoVoteExtensionSigns(vote.VoteExtensionsToMap(), extSigns) + fillProtoVoteExtensionSigns(vote.VoteExtensions, extSigns) return nil } @@ -735,7 +733,7 @@ func (pv *FilePV) signVote( } vote.BlockSignature = sigBlock - fillProtoVoteExtensionSigns(vote.VoteExtensionsToMap(), extSigns) + fillProtoVoteExtensionSigns(vote.VoteExtensions, extSigns) return nil } @@ -815,12 +813,12 @@ func (pv *FilePV) saveSigned( } func fillProtoVoteExtensionSigns( - voteExtensions map[tmproto.VoteExtensionType][]*tmproto.VoteExtension, - signs map[tmproto.VoteExtensionType][]tmbytes.HexBytes, + extensions []*tmproto.VoteExtension, + signs []tmbytes.HexBytes, ) { - for et, extensions := range voteExtensions { - for i, ext := range extensions { - ext.Signature = signs[et][i] - } + + for i, ext := range extensions { + ext.Signature = signs[i] } + } diff --git a/privval/file_test.go b/privval/file_test.go index 09f530cc04..2155e012a9 100644 --- a/privval/file_test.go +++ b/privval/file_test.go @@ -359,12 +359,10 @@ func TestVoteExtensionsAreAlwaysSigned(t *testing.T) { } voteType := tmproto.PrecommitType - exts := types.VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{ - Type: tmproto.VoteExtensionType_DEFAULT, - Extension: []byte("extension"), - }}, - } + exts := types.VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("extension"), + }) // We initially sign this vote without an extension vote1 := newVote(proTxHash, 0, height, round, voteType, blockID, exts) @@ -374,18 +372,17 @@ func TestVoteExtensionsAreAlwaysSigned(t *testing.T) { assert.NoError(t, err, "expected no error signing vote") assert.NotNil(t, vpb1.VoteExtensions[0].Signature) - extSignItem1, err := types.MakeVoteExtensionSignItems(chainID, vpb1, quorumType, quorumHash) + extSignItem1, err := types.VoteExtensionsFromProto(vpb1.VoteExtensions...).SignItems(chainID, quorumType, quorumHash, vpb1.Height, vpb1.Round) require.NoError(t, err) - assert.True(t, pubKey.VerifySignatureDigest(extSignItem1[tmproto.VoteExtensionType_DEFAULT][0].ID, vpb1.VoteExtensions[0].Signature)) + assert.True(t, pubKey.VerifySignatureDigest(extSignItem1[0].ID, vpb1.VoteExtensions[0].Signature)) // We duplicate this vote precisely, including its timestamp, but change // its extension vote2 := vote1.Copy() - vote2.VoteExtensions = types.VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{ - Type: tmproto.VoteExtensionType_DEFAULT, - Extension: []byte("new extension")}}, - } + vote2.VoteExtensions = types.VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("new extension")}) + vpb2 := vote2.ToProto() err = privVal.SignVote(ctx, chainID, quorumType, quorumHash, vpb2, logger) @@ -395,10 +392,10 @@ func TestVoteExtensionsAreAlwaysSigned(t *testing.T) { // that validates against the vote extension sign bytes with the new // extension, and does not validate against the vote extension sign bytes // with the old extension. - extSignItem2, err := types.MakeVoteExtensionSignItems(chainID, vpb2, quorumType, quorumHash) + extSignItem2, err := types.VoteExtensionsFromProto(vpb2.VoteExtensions...).SignItems(chainID, quorumType, quorumHash, vpb2.Height, vpb2.Round) require.NoError(t, err) - assert.True(t, pubKey.VerifySignatureDigest(extSignItem2[tmproto.VoteExtensionType_DEFAULT][0].ID, vpb2.VoteExtensions[0].Signature)) - assert.False(t, pubKey.VerifySignatureDigest(extSignItem1[tmproto.VoteExtensionType_DEFAULT][0].ID, vpb2.VoteExtensions[0].Signature)) + assert.True(t, pubKey.VerifySignatureDigest(extSignItem2[0].ID, vpb2.VoteExtensions[0].Signature)) + assert.False(t, pubKey.VerifySignatureDigest(extSignItem1[0].ID, vpb2.VoteExtensions[0].Signature)) vpb2.BlockSignature = nil vpb2.VoteExtensions[0].Signature = nil @@ -406,10 +403,10 @@ func TestVoteExtensionsAreAlwaysSigned(t *testing.T) { err = privVal.SignVote(ctx, chainID, quorumType, quorumHash, vpb2, logger) assert.NoError(t, err, "expected no error signing same vote with manipulated timestamp and vote extension") - extSignItem3, err := types.MakeVoteExtensionSignItems(chainID, vpb2, quorumType, quorumHash) + extSignItem3, err := types.VoteExtensionsFromProto(vpb2.VoteExtensions...).SignItems(chainID, quorumType, quorumHash, vpb2.Height, vpb2.Round) require.NoError(t, err) - assert.True(t, pubKey.VerifySignatureDigest(extSignItem3[tmproto.VoteExtensionType_DEFAULT][0].ID, vpb2.VoteExtensions[0].Signature)) - assert.False(t, pubKey.VerifySignatureDigest(extSignItem1[tmproto.VoteExtensionType_DEFAULT][0].ID, vpb2.VoteExtensions[0].Signature)) + assert.True(t, pubKey.VerifySignatureDigest(extSignItem3[0].ID, vpb2.VoteExtensions[0].Signature)) + assert.False(t, pubKey.VerifySignatureDigest(extSignItem1[0].ID, vpb2.VoteExtensions[0].Signature)) } func newVote(proTxHash types.ProTxHash, idx int32, height int64, round int32, diff --git a/privval/msgs_test.go b/privval/msgs_test.go index 1072a6cf07..32ba1354e3 100644 --- a/privval/msgs_test.go +++ b/privval/msgs_test.go @@ -44,11 +44,10 @@ func exampleVote() *types.Vote { }, ValidatorProTxHash: crypto.ProTxHashFromSeedBytes([]byte("validator_pro_tx_hash")), ValidatorIndex: 56789, - VoteExtensions: types.VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{ - Type: tmproto.VoteExtensionType_DEFAULT, - Extension: []byte("extension")}}, - }, + VoteExtensions: types.VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("extension"), + }), } } @@ -97,8 +96,8 @@ func TestPrivvalVectors(t *testing.T) { {"pubKey request", &privproto.PubKeyRequest{}, "0a00"}, {"pubKey response", &privproto.PubKeyResponse{PubKey: ppk, Error: nil}, "12340a321a30991a1c4f159f8e4730bf897e97e27c11f27ba0c1337111a3c102e1081a19372832b596623b1a248a0e00b156d80690cf"}, {"pubKey response with error", &privproto.PubKeyResponse{PubKey: cryptoproto.PublicKey{}, Error: remoteError}, "12140a0012100801120c697427732061206572726f72"}, - {"Vote Request", &privproto.SignVoteRequest{Vote: votepb}, "1aaa010aa701080210031802226c0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a1a20b583d49b95a0a5526966b519d8b7bba2aefc800b370a7438c7063728904e58ee2a20959a8f5ef2be68d0ed3a07ed8cff85991ee7995c2ac17030f742c135f9729fbe30d5bb03420b1209657874656e73696f6e"}, - {"Vote Response", &privproto.SignedVoteResponse{Vote: *votepb, Error: nil}, "22aa010aa701080210031802226c0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a1a20b583d49b95a0a5526966b519d8b7bba2aefc800b370a7438c7063728904e58ee2a20959a8f5ef2be68d0ed3a07ed8cff85991ee7995c2ac17030f742c135f9729fbe30d5bb03420b1209657874656e73696f6e"}, + {"Vote Request", &privproto.SignVoteRequest{Vote: votepb}, "1aac010aa901080210031802226c0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a1a20b583d49b95a0a5526966b519d8b7bba2aefc800b370a7438c7063728904e58ee2a20959a8f5ef2be68d0ed3a07ed8cff85991ee7995c2ac17030f742c135f9729fbe30d5bb03420d08011209657874656e73696f6e"}, + {"Vote Response", &privproto.SignedVoteResponse{Vote: *votepb, Error: nil}, "22ac010aa901080210031802226c0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a1a20b583d49b95a0a5526966b519d8b7bba2aefc800b370a7438c7063728904e58ee2a20959a8f5ef2be68d0ed3a07ed8cff85991ee7995c2ac17030f742c135f9729fbe30d5bb03420d08011209657874656e73696f6e"}, {"Vote Response with error", &privproto.SignedVoteResponse{Vote: tmproto.Vote{}, Error: remoteError}, "22180a042202120012100801120c697427732061206572726f72"}, {"Proposal Request", &privproto.SignProposalRequest{Proposal: proposalpb}, "2a700a6e08011003180220022a4a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a320608f49a8ded053a10697427732061207369676e6174757265"}, {"Proposal Response", &privproto.SignedProposalResponse{Proposal: *proposalpb, Error: nil}, "32700a6e08011003180220022a4a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a320608f49a8ded053a10697427732061207369676e6174757265"}, diff --git a/proto/tendermint/types/dash.go b/proto/tendermint/types/dash.go index 312f391ee9..0c2a4f4b63 100644 --- a/proto/tendermint/types/dash.go +++ b/proto/tendermint/types/dash.go @@ -9,17 +9,17 @@ import ( ) // VoteExtensions is a container type for grouped vote extensions by type -type VoteExtensions map[VoteExtensionType][]*VoteExtension +type VoteExtensions []*VoteExtension var ( errExtensionNil = errors.New("vote extension is nil") errExtensionSignEmpty = errors.New("vote extension signature is missing") errExtensionSignTooBig = fmt.Errorf("vote extension signature is too big (max: %d)", bls12381.SignatureSize) - errExtensionSignRequestIdNotSupported = errors.New("vote extension sign request id is not supported") - errExtensionSignRequestIdWrongPrefix = errors.New("vote extension sign request id must have dpevote or \\x06plwdtx prefix") + errExtensionSignRequestIDNotSupported = errors.New("vote extension sign request id is not supported") + errExtensionSignRequestIDWrongPrefix = errors.New("vote extension sign request id must have dpevote or \\x06plwdtx prefix") ) -// Clone returns a copy of current vote-extension +// Clone returns a shallow copy of current vote-extension // // Clone of nil will panic @@ -31,11 +31,8 @@ func (v *VoteExtension) Clone() VoteExtension { var xSignRequestID isVoteExtension_XSignRequestId if v.XSignRequestId != nil && v.XSignRequestId.Size() > 0 { - src := v.GetSignRequestId() - dst := make([]byte, len(src)) - copy(dst, src) xSignRequestID = &VoteExtension_SignRequestId{ - SignRequestId: dst, + SignRequestId: v.GetSignRequestId(), } } @@ -47,12 +44,69 @@ func (v *VoteExtension) Clone() VoteExtension { } } +// Copy returns a deep copy of current vote-extension. +func (v *VoteExtension) Copy() VoteExtension { + if v == nil { + panic("cannot copy nil vote-extension") + } + + var xSignRequestID isVoteExtension_XSignRequestId + + if v.XSignRequestId != nil && v.XSignRequestId.Size() > 0 { + xSignRequestID = &VoteExtension_SignRequestId{ + SignRequestId: bytes.Clone(v.GetSignRequestId()), + } + } + + return VoteExtension{ + Type: v.Type, + Extension: bytes.Clone(v.Extension), + Signature: bytes.Clone(v.Signature), + XSignRequestId: xSignRequestID, + } +} + +func (v *VoteExtension) Equal(other *VoteExtension) bool { + if v == nil || other == nil { + return false + } + + if v.Type != other.Type { + return false + } + + if !bytes.Equal(v.Extension, other.Extension) { + return false + } + + if !bytes.Equal(v.Signature, other.Signature) { + return false + } + + // one of them is nil, but not both + if (v.XSignRequestId != nil) != (other.XSignRequestId != nil) { + return false + } + + if v.XSignRequestId != nil && other.XSignRequestId != nil { + if !bytes.Equal(v.GetSignRequestId(), other.GetSignRequestId()) { + return false + } + } + + return true +} + // Validate checks the validity of the vote-extension func (v *VoteExtension) Validate() error { if v == nil { return errExtensionNil } + if v.Type == VoteExtensionType_DEFAULT { + return fmt.Errorf("vote extension type %s is not supported", v.Type.String()) + } + if len(v.Extension) > 0 && len(v.Signature) == 0 { return errExtensionSignEmpty } @@ -62,7 +116,7 @@ func (v *VoteExtension) Validate() error { if v.XSignRequestId != nil && v.XSignRequestId.Size() > 0 { if v.Type != VoteExtensionType_THRESHOLD_RECOVER_RAW { - return errExtensionSignRequestIdNotSupported + return errExtensionSignRequestIDNotSupported } var validPrefixes = []string{"\x06plwdtx", "dpevote"} requestID := v.GetSignRequestId() @@ -76,9 +130,17 @@ func (v *VoteExtension) Validate() error { } if !validPrefix { - return errExtensionSignRequestIdWrongPrefix + return errExtensionSignRequestIDWrongPrefix } } return nil } +func (v VoteExtensions) Contains(other VoteExtension) bool { + for _, ext := range v { + if ext.Equal(&other) { + return true + } + } + return false +} diff --git a/proto/tendermint/types/types.go b/proto/tendermint/types/types.go index c32a9a1406..0a27c46b8a 100644 --- a/proto/tendermint/types/types.go +++ b/proto/tendermint/types/types.go @@ -39,14 +39,6 @@ func (m *PartSetHeader) IsZero() bool { return m == nil || len(m.Hash) == 0 } -// VoteExtensionsToMap creates a map where a key is vote-extension type and value is the extensions grouped by type -func (m *Vote) VoteExtensionsToMap() VoteExtensions { - if m == nil { - return nil - } - return VoteExtensionsToMap(m.VoteExtensions) -} - // SignBytes represent data to be signed for the given vote. // It's a 64-byte slice containing concatenation of: // * Checksum of CanonicalVote @@ -171,11 +163,3 @@ func (s StateID) ValidateBasic() error { return nil } - -func VoteExtensionsToMap(voteExtensions []*VoteExtension) VoteExtensions { - res := make(map[VoteExtensionType][]*VoteExtension) - for _, ext := range voteExtensions { - res[ext.Type] = append(res[ext.Type], ext) - } - return res -} diff --git a/types/block.go b/types/block.go index df65dc7be3..5bcec3d59e 100644 --- a/types/block.go +++ b/types/block.go @@ -737,7 +737,7 @@ type Commit struct { QuorumHash crypto.QuorumHash `json:"quorum_hash"` ThresholdBlockSignature []byte `json:"threshold_block_signature"` // ThresholdVoteExtensions keeps the list of recovered threshold signatures for vote-extensions - ThresholdVoteExtensions []ThresholdExtensionSign `json:"threshold_vote_extensions"` + ThresholdVoteExtensions VoteExtensions `json:"threshold_vote_extensions"` // Memoized in first call to corresponding method. // NOTE: can't memoize in constructor because constructor isn't used for @@ -764,7 +764,7 @@ func (commit *Commit) ToCommitInfo() types.CommitInfo { Round: commit.Round, QuorumHash: commit.QuorumHash, BlockSignature: commit.ThresholdBlockSignature, - ThresholdVoteExtensions: ThresholdExtensionSignToProto(commit.ThresholdVoteExtensions), + ThresholdVoteExtensions: commit.ThresholdVoteExtensions.ToProto(), } } @@ -943,7 +943,7 @@ func (commit *Commit) ToProto() *tmproto.Commit { c.BlockID = commit.BlockID.ToProto() c.ThresholdBlockSignature = commit.ThresholdBlockSignature - c.ThresholdVoteExtensions = ThresholdExtensionSignToProto(commit.ThresholdVoteExtensions) + c.ThresholdVoteExtensions = commit.ThresholdVoteExtensions.ToProto() c.QuorumHash = commit.QuorumHash return c @@ -967,7 +967,7 @@ func CommitFromProto(cp *tmproto.Commit) (*Commit, error) { commit.QuorumHash = cp.QuorumHash commit.ThresholdBlockSignature = cp.ThresholdBlockSignature - commit.ThresholdVoteExtensions = ThresholdExtensionSignFromProto(cp.ThresholdVoteExtensions) + commit.ThresholdVoteExtensions = VoteExtensionsFromProto(cp.ThresholdVoteExtensions...) commit.Height = cp.Height commit.Round = cp.Round diff --git a/types/block_test.go b/types/block_test.go index f9a4af6489..d770b32179 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -528,7 +528,7 @@ func TestBlockMaxDataBytes(t *testing.T) { require.NotNil(t, commit) // minBlockSize is minimum correct size of a block - const minBlockSize = 1231 + const minBlockSize = 1370 testCases := []struct { maxBytes int64 diff --git a/types/priv_validator.go b/types/priv_validator.go index 723d21af69..96695343d4 100644 --- a/types/priv_validator.go +++ b/types/priv_validator.go @@ -273,6 +273,7 @@ func (pv *MockPV) SignVote( } vote.BlockSignature = blockSignature + // We only sign vote extensions for precommits if vote.Type != tmproto.PrecommitType { if len(vote.VoteExtensions) > 0 { return errors.New("unexpected vote extension - vote extensions are only allowed in precommits") @@ -280,22 +281,20 @@ func (pv *MockPV) SignVote( return nil } - // We only sign vote extensions for precommits - extSigns, err := MakeVoteExtensionSignItems(useChainID, vote, quorumType, quorumHash) + extensions := VoteExtensionsFromProto(vote.VoteExtensions...) + signItems, err := extensions.SignItems(useChainID, quorumType, quorumHash, vote.Height, vote.Round) if err != nil { return err } - protoExtensionsMap := vote.VoteExtensionsToMap() - for et, signs := range extSigns { - extensions := protoExtensionsMap[et] - for i, sign := range signs { - sign, err := privKey.SignDigest(sign.ID) - if err != nil { - return err - } - extensions[i].Signature = sign + + for i, sign := range signItems { + sig, err := privKey.SignDigest(sign.ID) + if err != nil { + return err } + vote.VoteExtensions[i].Signature = sig } + return nil } diff --git a/types/quorum.go b/types/quorum.go index 86d05db8e6..d8ea5e66d0 100644 --- a/types/quorum.go +++ b/types/quorum.go @@ -5,7 +5,6 @@ import ( "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/libs/log" - tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" ) // CommitSigns is used to combine threshold signatures and quorum-hash that were used @@ -18,93 +17,26 @@ type CommitSigns struct { func (c *CommitSigns) CopyToCommit(commit *Commit) { commit.QuorumHash = c.QuorumHash commit.ThresholdBlockSignature = c.BlockSign - commit.ThresholdVoteExtensions = c.ExtensionSigns + commit.ThresholdVoteExtensions = c.ThresholdVoteExtensions } // QuorumSigns holds all created signatures, block, state and for each recovered vote-extensions type QuorumSigns struct { - BlockSign []byte - ExtensionSigns []ThresholdExtensionSign + BlockSign []byte + // Signed vote extensions + ThresholdVoteExtensions VoteExtensions } -// NewQuorumSignsFromCommit creates and returns QuorumSigns using threshold signatures from a commit +// NewQuorumSignsFromCommit creates and returns QuorumSigns using threshold signatures from a commit. +// +// Note it only uses threshold-revoverable vote extension signatures, as non-threshold signatures are not included in the commit func NewQuorumSignsFromCommit(commit *Commit) QuorumSigns { return QuorumSigns{ - BlockSign: commit.ThresholdBlockSignature, - ExtensionSigns: commit.ThresholdVoteExtensions, + BlockSign: commit.ThresholdBlockSignature, + ThresholdVoteExtensions: commit.ThresholdVoteExtensions, } } -// ThresholdExtensionSign is used for keeping extension and recovered threshold signature -type ThresholdExtensionSign struct { - Extension []byte - ThresholdSignature []byte -} - -// MakeThresholdExtensionSigns creates and returns the list of ThresholdExtensionSign for given VoteExtensions container -func MakeThresholdExtensionSigns(voteExtensions VoteExtensions) []ThresholdExtensionSign { - if voteExtensions == nil { - return nil - } - extensions := voteExtensions[tmproto.VoteExtensionType_THRESHOLD_RECOVER] - if len(extensions) == 0 { - return nil - } - thresholdSigns := make([]ThresholdExtensionSign, len(extensions)) - for i, ext := range extensions { - thresholdSigns[i] = ThresholdExtensionSign{ - Extension: ext.Extension, - ThresholdSignature: ext.Signature, - } - } - return thresholdSigns -} - -// ThresholdExtensionSignFromProto transforms a list of protobuf ThresholdVoteExtension -// into the list of domain ThresholdExtensionSign -func ThresholdExtensionSignFromProto(protoExtensions []*tmproto.VoteExtension) []ThresholdExtensionSign { - if len(protoExtensions) == 0 { - return nil - } - extensions := make([]ThresholdExtensionSign, len(protoExtensions)) - for i, ext := range protoExtensions { - extensions[i] = ThresholdExtensionSign{ - Extension: ext.Extension, - ThresholdSignature: ext.Signature, - } - } - return extensions -} - -// ThresholdExtensionSignToProto transforms a list of domain ThresholdExtensionSign -// into the list of protobuf VoteExtension -func ThresholdExtensionSignToProto(extensions []ThresholdExtensionSign) []*tmproto.VoteExtension { - if len(extensions) == 0 { - return nil - } - protoExtensions := make([]*tmproto.VoteExtension, len(extensions)) - for i, ext := range extensions { - protoExtensions[i] = &tmproto.VoteExtension{ - Extension: ext.Extension, - Signature: ext.ThresholdSignature, - } - } - return protoExtensions -} - -// MakeThresholdVoteExtensions creates a list of ThresholdExtensionSign from the list of VoteExtension -// and recovered threshold signatures. The lengths of vote-extensions and threshold signatures must be the same -func MakeThresholdVoteExtensions(extensions []tmproto.VoteExtension, thresholdSigs [][]byte) []ThresholdExtensionSign { - thresholdExtensions := make([]ThresholdExtensionSign, len(extensions)) - for i, ext := range extensions { - thresholdExtensions[i] = ThresholdExtensionSign{ - Extension: ext.Extension, - ThresholdSignature: thresholdSigs[i], - } - } - return thresholdExtensions -} - // QuorumSingsVerifier ... type QuorumSingsVerifier struct { QuorumSignData @@ -181,6 +113,7 @@ func (q *QuorumSingsVerifier) verifyBlock(pubKey crypto.PubKey, signs QuorumSign return nil } +// verify threshold-recoverable vote extensions signatures func (q *QuorumSingsVerifier) verifyVoteExtensions( pubKey crypto.PubKey, signs QuorumSigns, @@ -188,20 +121,22 @@ func (q *QuorumSingsVerifier) verifyVoteExtensions( if !q.shouldVerifyVoteExtensions { return nil } - sings := signs.ExtensionSigns - signItems := q.Extensions[tmproto.VoteExtensionType_THRESHOLD_RECOVER] + + thresholdSigs := signs.ThresholdVoteExtensions.GetSignatures() + signItems := q.ThresholdVoteExtensions if len(signItems) == 0 { return nil } - if len(signItems) != len(sings) { + if len(signItems) != len(thresholdSigs) { return fmt.Errorf("count of threshold vote extension signatures (%d) doesn't match with recoverable vote extensions (%d)", - len(sings), len(signItems), + len(thresholdSigs), len(signItems), ) } - for i, ext := range sings { - if !pubKey.VerifySignatureDigest(signItems[i].ID, ext.ThresholdSignature) { - return fmt.Errorf("threshold vote-extension signature is invalid (%d) %X", - i, signItems[i].Raw) + + for i, sig := range thresholdSigs { + if !pubKey.VerifySignatureDigest(signItems[i].ID, sig) { + return fmt.Errorf("vote-extension %d signature is invalid: %X", i, + signItems[i].Raw) } } return nil diff --git a/types/quorum_sign_data.go b/types/quorum_sign_data.go index 1f4617fe8b..737aa65b4b 100644 --- a/types/quorum_sign_data.go +++ b/types/quorum_sign_data.go @@ -1,8 +1,6 @@ package types import ( - "bytes" - "errors" "fmt" "github.com/dashpay/dashd-go/btcjson" @@ -11,14 +9,10 @@ import ( "github.com/dashpay/tenderdash/proto/tendermint/types" ) -var ( - errUnexpectedVoteType = errors.New("unexpected vote extension - vote extensions are only allowed in precommits") -) - // QuorumSignData holds data which is necessary for signing and verification block, state, and each vote-extension in a list type QuorumSignData struct { - Block crypto.SignItem - Extensions map[types.VoteExtensionType][]crypto.SignItem + Block crypto.SignItem + ThresholdVoteExtensions []crypto.SignItem } // Verify verifies a quorum signatures: block, state and vote-extensions @@ -48,7 +42,12 @@ func MakeQuorumSigns( Block: MakeBlockSignItem(chainID, protoVote, quorumType, quorumHash), } var err error - quorumSign.Extensions, err = MakeVoteExtensionSignItems(chainID, protoVote, quorumType, quorumHash) + quorumSign.ThresholdVoteExtensions, err = + VoteExtensionsFromProto(protoVote.VoteExtensions...). + Filter(func(ext VoteExtensionIf) bool { + return ext.IsThresholdRecoverable() + }). + SignItems(chainID, quorumType, quorumHash, protoVote.Height, protoVote.Round) if err != nil { return QuorumSignData{}, err } @@ -69,44 +68,3 @@ func MakeBlockSignItem(chainID string, vote *types.Vote, quorumType btcjson.LLMQ func BlockRequestID(height int64, round int32) []byte { return heightRoundRequestID("dpbvote", height, round) } - -// MakeVoteExtensionSignItems creates a list SignItem structs for a vote extensions -func MakeVoteExtensionSignItems( - chainID string, - protoVote *types.Vote, - quorumType btcjson.LLMQType, - quorumHash []byte, -) (map[types.VoteExtensionType][]crypto.SignItem, error) { - // We only sign vote extensions for precommits - if protoVote.Type != types.PrecommitType { - if len(protoVote.VoteExtensions) > 0 { - return nil, errUnexpectedVoteType - } - return nil, nil - } - items := make(map[types.VoteExtensionType][]crypto.SignItem) - protoExtensionsMap := protoVote.VoteExtensionsToMap() - for t, exts := range protoExtensionsMap { - if items[t] == nil && len(exts) > 0 { - items[t] = make([]crypto.SignItem, len(exts)) - } - - for i, ext := range exts { - reqID, err := VoteExtensionRequestID(ext, protoVote.Height, protoVote.Round) - if err != nil { - return nil, err - } - raw := VoteExtensionSignBytes(chainID, protoVote.Height, protoVote.Round, ext) - // TODO: this is to avoid sha256 of raw data, to be removed once we get into agreement on the format - if ext.Type == types.VoteExtensionType_THRESHOLD_RECOVER_RAW { - // for this vote extension type, we just sign raw data from extension - msgHash := bytes.Clone(raw) - items[t][i] = crypto.NewSignItemFromHash(quorumType, quorumHash, reqID, msgHash) - items[t][i].Raw = raw - } else { - items[t][i] = crypto.NewSignItem(quorumType, quorumHash, reqID, raw) - } - } - } - return items, nil -} diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index 68e6b97236..1609e58138 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -24,6 +24,8 @@ func TestBlockRequestID(t *testing.T) { func TestMakeBlockSignID(t *testing.T) { const chainID = "dash-platform" + const quorumType = btcjson.LLMQType_5_60 + testCases := []struct { vote Vote quorumHash []byte @@ -39,20 +41,20 @@ func TestMakeBlockSignID(t *testing.T) { quorumHash: tmbytes.MustHexDecode("6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD"), want: newSignItem( "C8F2E1FE35DE03AC94F76191F59CAD1BA1F7A3C63742B7125990D996315001CC", - "DA25B746781DDF47B5D736F30B1D9D0CC86981EEC67CBE255265C4361DEF8C2E", + "C2CB4650EFA1179482AF85591E0C065563BD9EBBAF588ACD3BD3F5EBDD997DD6", "02000000E9030000000000000000000000000000E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B"+ "7852B855E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855646173682D706C6174666F726D", "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", - btcjson.LLMQType_5_60, + quorumType, ), wantHash: tmbytes.MustHexDecode("0CA3D5F42BDFED0C4FDE7E6DE0F046CC76CDA6CEE734D65E8B2EE0E375D4C57D"), }, } for i, tc := range testCases { t.Run(fmt.Sprintf("test-case %d", i), func(t *testing.T) { - signItem := MakeBlockSignItem(chainID, tc.vote.ToProto(), btcjson.LLMQType_5_60, tc.quorumHash) + signItem := MakeBlockSignItem(chainID, tc.vote.ToProto(), quorumType, tc.quorumHash) t.Logf("hash %X id %X raw %X reqID %X", signItem.Hash, signItem.ID, signItem.Raw, signItem.ReqID) - require.Equal(t, tc.want, signItem) + require.Equal(t, tc.want, signItem, "Got ID: %X", signItem.ID) require.Equal(t, tc.wantHash, signItem.Hash) }) } @@ -60,68 +62,62 @@ func TestMakeBlockSignID(t *testing.T) { func TestMakeVoteExtensionSignsData(t *testing.T) { const chainID = "dash-platform" + const quorumType = btcjson.LLMQType_5_60 + logger := log.NewTestingLogger(t) testCases := []struct { vote Vote quorumHash []byte - want map[types.VoteExtensionType][]crypto.SignItem - wantHash map[types.VoteExtensionType][][]byte + want []crypto.SignItem + wantHash [][]byte }{ { vote: Vote{ Type: types.PrecommitType, Height: 1001, ValidatorProTxHash: tmbytes.MustHexDecode("9CC13F685BC3EA0FCA99B87F42ABCC934C6305AA47F62A32266A2B9D55306B7B"), - VoteExtensions: VoteExtensions{ - types.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{ - Type: tmproto.VoteExtensionType_DEFAULT, - Extension: []byte("default")}}, - types.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{ + VoteExtensions: VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_DEFAULT, + Extension: []byte("default")}, + &tmproto.VoteExtension{ Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Extension: []byte("threshold")}}, - }, + Extension: []byte("threshold")}, + ), }, quorumHash: tmbytes.MustHexDecode("6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD"), - want: map[types.VoteExtensionType][]crypto.SignItem{ - types.VoteExtensionType_DEFAULT: { - newSignItem( - "FB95F2CA6530F02AC623589D7938643FF22AE79A75DD79AEA1C8871162DE675E", - "533524404D3A905F5AC9A30FCEB5A922EAD96F30DA02F979EE41C4342F540467", - "210A0764656661756C7411E903000000000000220D646173682D706C6174666F726D", - "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", - btcjson.LLMQType_5_60, - ), - }, - types.VoteExtensionType_THRESHOLD_RECOVER: { - newSignItem( - "fb95f2ca6530f02ac623589d7938643ff22ae79a75dd79aea1c8871162de675e", - "d3b7d53a0f9ca8072d47d6c18e782ee3155ef8dcddb010087030b6cbc63978bc", - "250a097468726573686f6c6411e903000000000000220d646173682d706c6174666f726d2801", - "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", - btcjson.LLMQType_5_60, - ), - }, + want: []crypto.SignItem{ + + newSignItem( + "FB95F2CA6530F02AC623589D7938643FF22AE79A75DD79AEA1C8871162DE675E", + "920740B3DA954CDB33F05F542E46502C10BACF8C085E8F8738B6BA99083FD1DF", + "210A0764656661756C7411E903000000000000220D646173682D706C6174666F726D", + "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", + quorumType, + ), + newSignItem( + "fb95f2ca6530f02ac623589d7938643ff22ae79a75dd79aea1c8871162de675e", + "A3B22D7D0D3D7DEB91AE414E8911AAB7BA476455113CA0E847628910C2FF312E", + "250a097468726573686f6c6411e903000000000000220d646173682d706c6174666f726d2801", + "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", + quorumType, + ), }, - wantHash: map[types.VoteExtensionType][][]byte{ - types.VoteExtensionType_DEFAULT: { - tmbytes.MustHexDecode("61519D79DE4C4D5AC5DD210C1BCE81AA24F76DD5581A24970E60112890C68FB7"), - }, - types.VoteExtensionType_THRESHOLD_RECOVER: { - tmbytes.MustHexDecode("46C72C423B74034E1AF574A99091B017C0698FEAA55C8B188BFD512FCADD3143"), - }, + wantHash: [][]byte{ + tmbytes.MustHexDecode("61519D79DE4C4D5AC5DD210C1BCE81AA24F76DD5581A24970E60112890C68FB7"), + tmbytes.MustHexDecode("46C72C423B74034E1AF574A99091B017C0698FEAA55C8B188BFD512FCADD3143"), }, }, } for i, tc := range testCases { t.Run(fmt.Sprintf("test-case #%d", i), func(t *testing.T) { - signItems, err := MakeVoteExtensionSignItems(chainID, tc.vote.ToProto(), btcjson.LLMQType_5_60, tc.quorumHash) + signItems, err := tc.vote.VoteExtensions.SignItems(chainID, quorumType, tc.quorumHash, tc.vote.Height, tc.vote.Round) + require.NoError(t, err) - for et, signs := range signItems { - for i, sign := range signs { - assert.Equal(t, tc.wantHash[et][i], sign.Hash, "want %X, actual %X", tc.wantHash[et][i], sign.Hash) - if !assert.Equal(t, tc.want[et][i], sign) { - logger.Error("invalid sign", "sign", sign, "type", et, "i", i) - } + + for i, sign := range signItems { + assert.Equal(t, tc.wantHash[i], sign.Hash, "want %X, actual %X", tc.wantHash[i], sign.Hash) + if !assert.Equal(t, tc.want[i], sign, "Got ID(%d): %X", i, sign.ID) { + logger.Error("invalid sign", "sign", sign, "i", i) } } }) @@ -157,22 +153,17 @@ func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { // Note: MakeVoteExtensionSignItems() calls MakeSignID(), which will reverse bytes in quorumHash, requestID and extension. - ve := tmproto.VoteExtension{ + ve := VoteExtensionFromProto(tmproto.VoteExtension{ Extension: extension, Signature: []byte{}, Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, XSignRequestId: &tmproto.VoteExtension_SignRequestId{ SignRequestId: requestID, }, - } + }) - signItems, err := MakeVoteExtensionSignItems(chainID, &tmproto.Vote{ - Type: tmproto.PrecommitType, - VoteExtensions: []*tmproto.VoteExtension{&ve}, - }, llmqType, quorumHash) + item, err := ve.SignItem(chainID, 1, 0, llmqType, quorumHash) assert.NoError(t, err) - - item := signItems[tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW][0] actual := item.ID t.Logf("LLMQ type: %s (%d)\n", llmqType.Name(), llmqType) diff --git a/types/signs_recoverer.go b/types/signs_recoverer.go index d9e7afdfa9..e97a437d92 100644 --- a/types/signs_recoverer.go +++ b/types/signs_recoverer.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/dashpay/tenderdash/crypto/bls12381" - tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" ) // SignsRecoverer is used to recover threshold block, state, and vote-extension signatures @@ -13,8 +12,10 @@ type SignsRecoverer struct { blockSigs [][]byte stateSigs [][]byte validatorProTxHashes [][]byte - voteExts [][]byte - voteExtSigs [][][]byte + // List of all threshold-recovered vote extensions, indexed by vote extension number + voteThresholdExts VoteExtensions + // voteThresholdExtensionSigs is a list of signatures for each threshold-recovered vote-extension, indexed by vote extension number + voteThresholdExtensionSigs [][][]byte quorumReached bool } @@ -59,7 +60,7 @@ func (v *SignsRecoverer) init(votes []*Vote) { v.blockSigs = nil v.stateSigs = nil v.validatorProTxHashes = nil - v.voteExtSigs = nil + v.voteThresholdExtensionSigs = nil for _, vote := range votes { v.addVoteSigs(vote) } @@ -71,18 +72,31 @@ func (v *SignsRecoverer) addVoteSigs(vote *Vote) { } v.blockSigs = append(v.blockSigs, vote.BlockSignature) v.validatorProTxHashes = append(v.validatorProTxHashes, vote.ValidatorProTxHash) - v.addVoteExtensions(vote.VoteExtensions) + v.addVoteExtensionSigs(vote.VoteExtensions) } -func (v *SignsRecoverer) addVoteExtensions(voteExtensions VoteExtensions) { - extensions := voteExtensions[tmproto.VoteExtensionType_THRESHOLD_RECOVER] - for i, ext := range extensions { - if len(extensions) > len(v.voteExtSigs) { - v.voteExts = append(v.voteExts, ext.Extension) - v.voteExtSigs = append(v.voteExtSigs, nil) - } - v.voteExtSigs[i] = append(v.voteExtSigs[i], ext.Signature) +// Add threshold-recovered vote extensions +func (v *SignsRecoverer) addVoteExtensionSigs(voteExtensions VoteExtensions) { + // Skip non-threshold vote-extensions + thresholdExtensions := voteExtensions.Filter(func(ext VoteExtensionIf) bool { + return ext.IsThresholdRecoverable() + }) + // initialize vote extensions if it's empty + if len(v.voteThresholdExts) == 0 && !thresholdExtensions.IsEmpty() { + v.voteThresholdExts = thresholdExtensions.Copy() + v.voteThresholdExtensionSigs = make([][][]byte, len(thresholdExtensions)) + } + + // sanity check; this should be detected on higher layers + if len(v.voteThresholdExts) != len(thresholdExtensions) { + panic(fmt.Sprintf("received vote extensions with different length: current %d, new %d", len(v.voteThresholdExts), len(thresholdExtensions))) } + + // append signatures from this vote to each extension + for i, ext := range thresholdExtensions { + v.voteThresholdExtensionSigs[i] = append(v.voteThresholdExtensionSigs[i], ext.GetSignature()) + } + } func (v *SignsRecoverer) recoverBlockSig(thresholdSigns *QuorumSigns) error { @@ -94,20 +108,36 @@ func (v *SignsRecoverer) recoverBlockSig(thresholdSigns *QuorumSigns) error { return nil } -func (v *SignsRecoverer) recoverVoteExtensionSigs(thresholdSigns *QuorumSigns) error { +// recoverVoteExtensionSigs recovers threshold signatures for vote-extensions +func (v *SignsRecoverer) recoverVoteExtensionSigs(quorumSigs *QuorumSigns) error { if !v.quorumReached { return nil } - var err error - thresholdSigns.ExtensionSigns = make([]ThresholdExtensionSign, len(v.voteExtSigs)) - for i, sigs := range v.voteExtSigs { - if len(sigs) > 0 { - thresholdSigns.ExtensionSigns[i].Extension = v.voteExts[i] - thresholdSigns.ExtensionSigns[i].ThresholdSignature, err = bls12381.RecoverThresholdSignatureFromShares(sigs, v.validatorProTxHashes) - if err != nil { - return fmt.Errorf("error recovering threshold vote-extension sig: %w", err) + + // initialize threshold vote extensions with empty signatures + quorumSigs.ThresholdVoteExtensions = v.voteThresholdExts.Filter(func(ext VoteExtensionIf) bool { return ext.IsThresholdRecoverable() }).Copy() + for i := range quorumSigs.ThresholdVoteExtensions { + quorumSigs.ThresholdVoteExtensions[i].SetSignature(nil) + } + + // for each vote extension, if it's threshold-recoverable, recover its signature + thresholdExtIndex := 0 + for extIndex, extension := range quorumSigs.ThresholdVoteExtensions { + if extension.IsThresholdRecoverable() { + extensionSignatures := v.voteThresholdExtensionSigs[thresholdExtIndex] + thresholdExtIndex++ + + if len(extensionSignatures) > 0 { + thresholdSignature, err := bls12381.RecoverThresholdSignatureFromShares(extensionSignatures, v.validatorProTxHashes) + if err != nil { + return fmt.Errorf("error recovering vote-extension %d threshold signature: %w", extIndex, err) + } + quorumSigs.ThresholdVoteExtensions[extIndex].SetSignature(thresholdSignature) + } else { + return fmt.Errorf("vote extension %d does not have any signatures for threshold-recovering", extIndex) } } } + return nil } diff --git a/types/signs_recoverer_test.go b/types/signs_recoverer_test.go index 1f7a132496..940197fe79 100644 --- a/types/signs_recoverer_test.go +++ b/types/signs_recoverer_test.go @@ -23,7 +23,8 @@ func TestSigsRecoverer(t *testing.T) { quorumType := crypto.SmallQuorumType() quorumHash := crypto.RandQuorumHash() testCases := []struct { - votes []*Vote + expectInvalidSig bool + votes []*Vote }{ { votes: []*Vote{ @@ -32,8 +33,8 @@ func TestSigsRecoverer(t *testing.T) { Type: tmproto.PrecommitType, BlockID: blockID, VoteExtensions: mockVoteExtensions(t, - tmproto.VoteExtensionType_DEFAULT, "default", tmproto.VoteExtensionType_THRESHOLD_RECOVER, "threshold", + tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, crypto.Checksum([]byte("threshold-raw")), ), }, { @@ -41,7 +42,75 @@ func TestSigsRecoverer(t *testing.T) { Type: tmproto.PrecommitType, BlockID: blockID, VoteExtensions: mockVoteExtensions(t, - tmproto.VoteExtensionType_DEFAULT, "default", + tmproto.VoteExtensionType_THRESHOLD_RECOVER, "threshold", + tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, crypto.Checksum([]byte("threshold-raw")), + ), + }, + }, + }, + { + votes: []*Vote{ + { + ValidatorProTxHash: crypto.RandProTxHash(), + Type: tmproto.PrecommitType, + BlockID: blockID, + VoteExtensions: mockVoteExtensions(t, + tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, crypto.Checksum([]byte("threshold-raw")), + tmproto.VoteExtensionType_THRESHOLD_RECOVER, "threshold", + ), + }, + { + ValidatorProTxHash: crypto.RandProTxHash(), + Type: tmproto.PrecommitType, + BlockID: blockID, + VoteExtensions: mockVoteExtensions(t, + tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, crypto.Checksum([]byte("threshold-raw")), + tmproto.VoteExtensionType_THRESHOLD_RECOVER, "threshold", + ), + }, + }, + }, + { + expectInvalidSig: true, + votes: []*Vote{ + { + ValidatorProTxHash: crypto.RandProTxHash(), + Type: tmproto.PrecommitType, + BlockID: blockID, + VoteExtensions: mockVoteExtensions(t, + tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, crypto.Checksum([]byte("threshold-raw")), + tmproto.VoteExtensionType_THRESHOLD_RECOVER, "threshold", + ), + }, + { + ValidatorProTxHash: crypto.RandProTxHash(), + Type: tmproto.PrecommitType, + BlockID: blockID, + VoteExtensions: mockVoteExtensions(t, + tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, crypto.Checksum([]byte("threshold-raw")), + tmproto.VoteExtensionType_THRESHOLD_RECOVER, "threshold1", + ), + }, + }, + }, + { + expectInvalidSig: true, + votes: []*Vote{ + { + ValidatorProTxHash: crypto.RandProTxHash(), + Type: tmproto.PrecommitType, + BlockID: blockID, + VoteExtensions: mockVoteExtensions(t, + tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, crypto.Checksum([]byte("threshold-raw1")), + tmproto.VoteExtensionType_THRESHOLD_RECOVER, "threshold", + ), + }, + { + ValidatorProTxHash: crypto.RandProTxHash(), + Type: tmproto.PrecommitType, + BlockID: blockID, + VoteExtensions: mockVoteExtensions(t, + tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, crypto.Checksum([]byte("threshold-raw")), tmproto.VoteExtensionType_THRESHOLD_RECOVER, "threshold", ), }, @@ -78,7 +147,11 @@ func TestSigsRecoverer(t *testing.T) { thresholdVoteSigns, err := sr.Recover() require.NoError(t, err) err = quorumSigns.Verify(thresholdPubKey, *thresholdVoteSigns) - require.NoError(t, err) + if tc.expectInvalidSig { + require.Error(t, err) + } else { + require.NoError(t, err) + } }) } } @@ -108,7 +181,7 @@ func TestSigsRecoverer_UsingVoteSet(t *testing.T) { Type: tmproto.PrecommitType, BlockID: blockID, VoteExtensions: mockVoteExtensions(t, - tmproto.VoteExtensionType_DEFAULT, "default", + tmproto.VoteExtensionType_THRESHOLD_RECOVER, "default", tmproto.VoteExtensionType_THRESHOLD_RECOVER, "threshold", ), } @@ -130,12 +203,12 @@ func TestSigsRecoverer_UsingVoteSet(t *testing.T) { // the format of pairs is // 1. the length of pairs must be even // 2. each pair consist of 2 elements: type and extension value -// example: types.VoteExtensionType_DEFAULT, "defailt", types.VoteExtensionType_THRESHOLD_RECOVER, "threshold" +// example: types.VoteExtensionType_THRESHOLD_RECOVER, "defailt", types.VoteExtensionType_THRESHOLD_RECOVER, "threshold" func mockVoteExtensions(t *testing.T, pairs ...interface{}) VoteExtensions { if len(pairs)%2 != 0 { t.Fatalf("the pairs length must be even") } - ve := make(VoteExtensions) + ve := make(VoteExtensions, 0) for i := 0; i < len(pairs); i += 2 { extensionType, ok := pairs[i].(tmproto.VoteExtensionType) if !ok { @@ -152,7 +225,8 @@ func mockVoteExtensions(t *testing.T, pairs ...interface{}) VoteExtensions { default: t.Fatalf("given unsupported type %T", pairs[i+1]) } - ve[extensionType] = append(ve[extensionType], ext) + ve.Add(ext) + } return ve } diff --git a/types/test_util.go b/types/test_util.go index 324231eac8..0418d1f082 100644 --- a/types/test_util.go +++ b/types/test_util.go @@ -45,14 +45,14 @@ func makeCommit( Round: round, Type: tmproto.PrecommitType, BlockID: blockID, - VoteExtensions: VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{ - Type: tmproto.VoteExtensionType_DEFAULT, - Extension: []byte("default")}}, - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{ + VoteExtensions: VoteExtensionsFromProto( + &tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, + Extension: crypto.Checksum([]byte("raw"))}, + &tmproto.VoteExtension{ Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Extension: []byte("threshold")}}, - }, + Extension: []byte("threshold")}, + ), } _, err = signAddVote(ctx, validators[i], vote, voteSet) diff --git a/types/validation_test.go b/types/validation_test.go index 8f5809cd44..57541b768a 100644 --- a/types/validation_test.go +++ b/types/validation_test.go @@ -140,7 +140,7 @@ func TestValidatorSet_VerifyCommit_CheckThresholdSignatures(t *testing.T) { thresholdSigns, err := recoverer.Recover() require.NoError(t, err) commit.ThresholdBlockSignature = thresholdSigns.BlockSign - commit.ThresholdVoteExtensions = thresholdSigns.ExtensionSigns + commit.ThresholdVoteExtensions = thresholdSigns.ThresholdVoteExtensions err = valSet.VerifyCommit(chainID, blockID, h, commit) require.NoError(t, err) } diff --git a/types/vote.go b/types/vote.go index 2f7123f497..ec708b80ea 100644 --- a/types/vote.go +++ b/types/vote.go @@ -24,13 +24,6 @@ const ( MaxVoteBytesEd25519 int64 = 209 ) -// VoteExtensionTypes is a list of all possible vote-extension types -var VoteExtensionTypes = []tmproto.VoteExtensionType{ - tmproto.VoteExtensionType_DEFAULT, - tmproto.VoteExtensionType_THRESHOLD_RECOVER, - tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, -} - func MaxVoteBytesForKeyType(keyType crypto.KeyType) int64 { switch keyType { case crypto.Ed25519: @@ -109,37 +102,10 @@ func VoteFromProto(pv *tmproto.Vote) (*Vote, error) { ValidatorProTxHash: pv.ValidatorProTxHash, ValidatorIndex: pv.ValidatorIndex, BlockSignature: pv.BlockSignature, - VoteExtensions: VoteExtensionsFromProto(pv.VoteExtensions), + VoteExtensions: VoteExtensionsFromProto(pv.VoteExtensions...), }, nil } -// VoteExtensionSignBytes returns the proto-encoding of the canonicalized vote -// extension for signing. Panics if the marshaling fails. -// -// Similar to VoteSignBytes, the encoded Protobuf message is varint -// length-prefixed for backwards-compatibility with the Amino encoding. -func VoteExtensionSignBytes(chainID string, height int64, round int32, ext *tmproto.VoteExtension) []byte { - bz, err := CanonicalizeVoteExtension(chainID, ext, height, round) - if err != nil { - panic(err) - } - return bz -} - -// VoteExtensionRequestID returns vote extension sign request ID used to generate -// threshold signatures -func VoteExtensionRequestID(ext *tmproto.VoteExtension, height int64, round int32) ([]byte, error) { - - if ext.XSignRequestId != nil && ext.XSignRequestId.Size() > 0 { - if ext.Type == tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW { - return crypto.Checksum(crypto.Checksum(ext.GetSignRequestId())), nil - } - return nil, ErrVoteExtensionTypeWrongForRequestID - } - - return heightRoundRequestID("dpevote", height, round), nil -} - // VoteBlockSignID returns signID that should be signed for the block func VoteBlockSignID(chainID string, vote *tmproto.Vote, quorumType btcjson.LLMQType, quorumHash []byte) []byte { signID := MakeBlockSignItem(chainID, vote, quorumType, quorumHash) @@ -291,8 +257,10 @@ func (vote *Vote) verifySign( func (vote *Vote) makeQuorumSigns() QuorumSigns { return QuorumSigns{ - BlockSign: vote.BlockSignature, - ExtensionSigns: MakeThresholdExtensionSigns(vote.VoteExtensions), + BlockSign: vote.BlockSignature, + ThresholdVoteExtensions: vote.VoteExtensions.Filter(func(ext VoteExtensionIf) bool { + return ext.IsThresholdRecoverable() + }).Copy(), } } @@ -350,8 +318,7 @@ func (vote *Vote) ValidateBasic() error { } if vote.Type == tmproto.PrecommitType && !vote.BlockID.IsNil() { - err := vote.VoteExtensions.Validate() - if err != nil { + if err := vote.VoteExtensions.Validate(); err != nil { return err } } diff --git a/types/vote_dash.go b/types/vote_dash.go index aae8f430b8..f2a5b8fb3d 100644 --- a/types/vote_dash.go +++ b/types/vote_dash.go @@ -5,23 +5,11 @@ import tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" // PopulateSignsFromProto updates the signatures of the current Vote with values are taken from the Vote's protobuf func (vote *Vote) PopulateSignsFromProto(pv *tmproto.Vote) error { vote.BlockSignature = pv.BlockSignature - return vote.VoteExtensions.CopySignsFromProto(pv.VoteExtensionsToMap()) + return vote.VoteExtensions.CopySignsFromProto(pv.VoteExtensions) } // PopulateSignsToProto updates the signatures of the given protobuf Vote entity with values are taken from the current Vote's func (vote *Vote) PopulateSignsToProto(pv *tmproto.Vote) error { pv.BlockSignature = vote.BlockSignature - return vote.VoteExtensions.CopySignsToProto(pv.VoteExtensionsToMap()) -} - -// GetVoteExtensionsSigns returns the list of signatures for given vote-extension type -func (vote *Vote) GetVoteExtensionsSigns(extType tmproto.VoteExtensionType) [][]byte { - if vote.VoteExtensions == nil { - return nil - } - sigs := make([][]byte, len(vote.VoteExtensions[extType])) - for i, ext := range vote.VoteExtensions[extType] { - sigs[i] = ext.Signature - } - return sigs + return vote.VoteExtensions.CopySignsToProto(pv.VoteExtensions) } diff --git a/types/vote_extension.go b/types/vote_extension.go index 15f94fbc10..8e9b641647 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -2,11 +2,17 @@ package types import ( "bytes" + "crypto/sha256" "errors" + "fmt" + "math/big" + "github.com/dashpay/dashd-go/btcjson" abci "github.com/dashpay/tenderdash/abci/types" + "github.com/dashpay/tenderdash/crypto" tmbytes "github.com/dashpay/tenderdash/libs/bytes" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" + "github.com/hashicorp/go-multierror" ) var ( @@ -14,161 +20,367 @@ var ( ) // VoteExtensions is a container where the key is vote-extension type and value is a list of VoteExtension -type VoteExtensions map[tmproto.VoteExtensionType][]tmproto.VoteExtension +type VoteExtensions []VoteExtensionIf // NewVoteExtensionsFromABCIExtended returns vote-extensions container for given ExtendVoteExtension func NewVoteExtensionsFromABCIExtended(exts []*abci.ExtendVoteExtension) VoteExtensions { - voteExtensions := make(VoteExtensions) + voteExtensions := make(VoteExtensions, 0, len(exts)) + for _, ext := range exts { ve := ext.ToVoteExtension() - voteExtensions.Add(ext.Type, ve) + voteExtensions.Add(ve) } return voteExtensions } -// Add creates and adds VoteExtension into a container by vote-extension type -func (e VoteExtensions) Add(t tmproto.VoteExtensionType, ext tmproto.VoteExtension) { - e[t] = append(e[t], ext) +// Add creates and adds protobuf VoteExtension into a container by vote-extension type +func (e *VoteExtensions) Add(ext tmproto.VoteExtension) { + *e = append(*e, VoteExtensionFromProto(ext)) +} + +// MakeVoteExtensionSignItems creates a list SignItem structs for a vote extensions +func (e VoteExtensions) SignItems( + chainID string, + quorumType btcjson.LLMQType, + quorumHash []byte, + height int64, + round int32, +) ([]crypto.SignItem, error) { + + items := make([]crypto.SignItem, 0, e.Len()) + + for _, ext := range e { + item, err := ext.SignItem(chainID, height, round, quorumType, quorumHash) + if err != nil { + return nil, err + } + + items = append(items, item) + } + + return items, nil +} + +func (e VoteExtensions) GetSignatures() [][]byte { + signatures := make([][]byte, 0, e.Len()) + + for _, ext := range e { + signatures = append(signatures, ext.GetSignature()) + } + + return signatures +} + +func (e VoteExtensions) GetExtensions() [][]byte { + exts := make([][]byte, 0, e.Len()) + + for _, ext := range e { + exts = append(exts, ext.GetExtension()) + } + + return exts } // Validate returns error if an added vote-extension is invalid func (e VoteExtensions) Validate() error { - for _, et := range VoteExtensionTypes { - for _, ext := range e[et] { - err := ext.Validate() - if err != nil { - return err - } + var errs *multierror.Error + + for i, ext := range e { + if err := ext.Validate(); err != nil { + errs = multierror.Append(errs, fmt.Errorf("invalid %s vote extension %d: %w", ext.ToProto().Type, i, err)) } } - return nil + + return errs.ErrorOrNil() } // IsEmpty returns true if a vote-extension container is empty, otherwise false func (e VoteExtensions) IsEmpty() bool { - for _, exts := range e { - if len(exts) > 0 { - return false - } - } - return true + return len(e) == 0 } // ToProto transforms the current state of vote-extension container into VoteExtensions's protobuf func (e VoteExtensions) ToProto() []*tmproto.VoteExtension { - extensions := make([]*tmproto.VoteExtension, 0, e.totalCount()) - for _, t := range VoteExtensionTypes { - for _, ext := range e[t] { - cloned := ext.Clone() - extensions = append(extensions, &cloned) - } + extensions := make([]*tmproto.VoteExtension, 0, e.Len()) + for _, ext := range e { + pbExt := ext.ToProto() + extensions = append(extensions, &pbExt) } + return extensions } // ToExtendProto transforms the current state of vote-extension container into ExtendVoteExtension's protobuf func (e VoteExtensions) ToExtendProto() []*abci.ExtendVoteExtension { - proto := make([]*abci.ExtendVoteExtension, 0, e.totalCount()) - for _, et := range VoteExtensionTypes { - for _, ext := range e[et] { - proto = append(proto, &abci.ExtendVoteExtension{ - Type: et, - Extension: ext.Extension, - }) + proto := make([]*abci.ExtendVoteExtension, 0, e.Len()) + + for _, ext := range e { + if err := ext.Validate(); err != nil { + panic(fmt.Errorf("invalid vote extension %v: %w", ext, err)) + } + + pb := ext.ToProto() + + var requestID *abci.ExtendVoteExtension_SignRequestId + if pb.XSignRequestId != nil { + if src := pb.GetSignRequestId(); len(src) > 0 { + requestID = &abci.ExtendVoteExtension_SignRequestId{ + SignRequestId: bytes.Clone(src), + } + } } + + proto = append(proto, &abci.ExtendVoteExtension{ + Type: pb.Type, + Extension: pb.Extension, + XSignRequestId: requestID, + }) } + return proto } // Fingerprint returns a fingerprint of all vote-extensions in a state of this container func (e VoteExtensions) Fingerprint() []byte { - cnt := 0 - for _, v := range e { - cnt += len(v) - } - l := make([][]byte, 0, cnt) - for _, et := range VoteExtensionTypes { - for _, ext := range e[et] { - l = append(l, ext.Extension) + if e.IsEmpty() { + return tmbytes.Fingerprint(nil) + } + sha := sha256.New() + for _, ext := range e { + pb := ext.ToProto() + // type + extension + if _, err := sha.Write(big.NewInt(int64(pb.Type)).Bytes()); err != nil { + panic(err) + } + if _, err := sha.Write(pb.Extension); err != nil { + panic(err) } } - return tmbytes.Fingerprint(bytes.Join(l, nil)) + return tmbytes.Fingerprint(sha.Sum(nil)) } // IsSameWithProto compares the current state of the vote-extension with the same in VoteExtensions's protobuf // checks only the value of extensions -func (e VoteExtensions) IsSameWithProto(proto tmproto.VoteExtensions) bool { - for t, extensions := range e { - if len(proto[t]) != len(extensions) { +func (e VoteExtensions) IsSameWithProto(right tmproto.VoteExtensions) bool { + for t, ext := range e { + pb := ext.ToProto() + other := right[t] + if !pb.Equal(other) { return false } - for i, ext := range extensions { - if !bytes.Equal(ext.Extension, proto[t][i].Extension) { - return false - } - } } return true } -func (e VoteExtensions) totalCount() int { - cnt := 0 - for _, exts := range e { - cnt += len(exts) - } - return cnt +func (e VoteExtensions) Len() int { + return len(e) } // VoteExtensionsFromProto creates VoteExtensions container from VoteExtensions's protobuf -func VoteExtensionsFromProto(pve []*tmproto.VoteExtension) VoteExtensions { - if pve == nil { +func VoteExtensionsFromProto(pve ...*tmproto.VoteExtension) VoteExtensions { + if len(pve) == 0 { return nil } - voteExtensions := make(VoteExtensions) + voteExtensions := make(VoteExtensions, 0, len(pve)) for _, ext := range pve { - voteExtensions[ext.Type] = append(voteExtensions[ext.Type], ext.Clone()) + voteExtensions = append(voteExtensions, VoteExtensionFromProto(*ext)) } + return voteExtensions } // Copy creates a deep copy of VoteExtensions func (e VoteExtensions) Copy() VoteExtensions { - copied := make(VoteExtensions, len(e)) - for extType, extensions := range e { - copied[extType] = make([]tmproto.VoteExtension, len(extensions)) - for k, v := range extensions { - copied[extType][k] = v.Clone() - } + copied := make(VoteExtensions, 0, len(e)) + for _, ext := range e { + copied = append(copied, ext.Copy()) } return copied } +// Filter returns a new VoteExtensions container with vote-extensions filtered by provided function. +// It does not copy data, just creates a new container with references to the same data +func (e VoteExtensions) Filter(fn func(ext VoteExtensionIf) bool) VoteExtensions { + result := make(VoteExtensions, 0, len(e)) + for _, ext := range e { + if fn(ext) { + result = append(result, ext) + } + } + + return result[:] +} + // CopySignsFromProto copies the signatures from VoteExtensions's protobuf into the current VoteExtension state func (e VoteExtensions) CopySignsFromProto(src tmproto.VoteExtensions) error { - return e.copySigns(src, func(a *tmproto.VoteExtension, b *tmproto.VoteExtension) { - b.Signature = a.Signature - }) + if len(e) != len(src) { + return errUnableCopySigns + } + for i, ext := range e { + ext.SetSignature(src[i].Signature) + } + + return nil } // CopySignsToProto copies the signatures from the current VoteExtensions into VoteExtension's protobuf -func (e VoteExtensions) CopySignsToProto(dist tmproto.VoteExtensions) error { - return e.copySigns(dist, func(a *tmproto.VoteExtension, b *tmproto.VoteExtension) { - a.Signature = b.Signature - }) -} - -func (e VoteExtensions) copySigns( - protoMap tmproto.VoteExtensions, - modifier func(a *tmproto.VoteExtension, b *tmproto.VoteExtension), -) error { - for t, exts := range e { - if len(exts) != len(protoMap[t]) { - return errUnableCopySigns - } - for i := range exts { - modifier(protoMap[t][i], &exts[i]) - } +func (e VoteExtensions) CopySignsToProto(dest tmproto.VoteExtensions) error { + if len(e) != len(dest) { + return errUnableCopySigns } + for i, ext := range e { + pb := ext.ToProto() + dest[i].Signature = pb.Signature + } + return nil } + +type VoteExtensionIf interface { + // Return type of this vote extension + GetType() tmproto.VoteExtensionType + // Return extension bytes + GetExtension() []byte + // Return signature bytes + GetSignature() []byte + // Copy creates a deep copy of VoteExtension + Copy() VoteExtensionIf + // ToProto transforms the current state of vote-extension into VoteExtension's proto-generated object. + // It should prioritize performance and can do a shallow copy of the vote-extension, + // so the returned object should not be modified. + ToProto() tmproto.VoteExtension + SignItem(chainID string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) + IsThresholdRecoverable() bool + Validate() error + + SetSignature(sig []byte) +} + +func VoteExtensionFromProto(ve tmproto.VoteExtension) VoteExtensionIf { + switch ve.Type { + case tmproto.VoteExtensionType_DEFAULT: + return &GenericVoteExtension{VoteExtension: ve} + case tmproto.VoteExtensionType_THRESHOLD_RECOVER: + return &ThresholdVoteExtension{GenericVoteExtension: GenericVoteExtension{VoteExtension: ve}} + case tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW: + return &ThresholdRawVoteExtension{GenericVoteExtension: GenericVoteExtension{VoteExtension: ve}} + default: + panic(fmt.Errorf("unknown vote extension type: %s", ve.Type.String())) + } +} + +// VOTE EXTENSION TYPES + +// GenericVoteExtension is a default type of VoteExtension +type GenericVoteExtension struct { + tmproto.VoteExtension +} + +func (e GenericVoteExtension) Copy() VoteExtensionIf { + return &GenericVoteExtension{VoteExtension: e.VoteExtension.Copy()} +} + +func (e GenericVoteExtension) ToProto() tmproto.VoteExtension { + return e.VoteExtension +} + +func (e GenericVoteExtension) SignItem(chainID string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) { + return signItem(&e.VoteExtension, chainID, height, round, quorumType, quorumHash) +} + +func (e GenericVoteExtension) IsThresholdRecoverable() bool { + return false +} + +func (e *GenericVoteExtension) SetSignature(sig []byte) { + e.Signature = sig +} + +// ThresholdVoteExtension is a threshold type of VoteExtension +type ThresholdVoteExtension struct { + GenericVoteExtension + ThresholdSignature []byte +} + +func (e ThresholdVoteExtension) Copy() VoteExtensionIf { + return &ThresholdVoteExtension{GenericVoteExtension: GenericVoteExtension{ + VoteExtension: e.VoteExtension.Copy(), + }, + } +} + +func (e ThresholdVoteExtension) IsThresholdRecoverable() bool { + return true +} + +// ThresholdRawVoteExtension is a threshold raw type of VoteExtension +type ThresholdRawVoteExtension struct { + GenericVoteExtension + ThresholdSignature []byte +} + +func (e ThresholdRawVoteExtension) Copy() VoteExtensionIf { + return &ThresholdRawVoteExtension{GenericVoteExtension: GenericVoteExtension{ + VoteExtension: e.VoteExtension.Copy(), + }} +} + +func (e ThresholdRawVoteExtension) IsThresholdRecoverable() bool { + return true +} + +func (e ThresholdRawVoteExtension) SignItem(chainID string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) { + var signRequestID []byte + var err error + + ext := &e.VoteExtension + + if ext.XSignRequestId != nil && ext.XSignRequestId.Size() > 0 { + signRequestID = crypto.Checksum(crypto.Checksum(ext.GetSignRequestId())) + } else { + if signRequestID, err = voteExtensionRequestID(height, round); err != nil { + return crypto.SignItem{}, err + } + } + + // ensure signBytes is 32 bytes long + signBytes := make([]byte, crypto.DefaultHashSize) + copy(signBytes, ext.Extension) + + signItem, err := crypto.NewSignItemFromHash(quorumType, quorumHash, signRequestID, signBytes), nil + if err != nil { + return crypto.SignItem{}, err + } + signItem.Raw = ext.Extension + + return signItem, nil +} + +// voteExtensionRequestID returns vote extension sign request ID used to generate +// threshold signatures +func voteExtensionRequestID(height int64, round int32) ([]byte, error) { + return heightRoundRequestID("dpevote", height, round), nil +} + +// voteExtensionSignBytes returns the proto-encoding of the canonicalized vote +// extension for signing. Panics if the marshaling fails. +// +// Similar to VoteSignBytes, the encoded Protobuf message is varint +// length-prefixed for backwards-compatibility with the Amino encoding. +func voteExtensionSignBytes(chainID string, height int64, round int32, ext *tmproto.VoteExtension) []byte { + bz, err := CanonicalizeVoteExtension(chainID, ext, height, round) + if err != nil { + panic(err) + } + return bz +} + +func signItem(ext *tmproto.VoteExtension, chainID string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) { + requestID, err := voteExtensionRequestID(height, round) + if err != nil { + return crypto.SignItem{}, err + } + signBytes := voteExtensionSignBytes(chainID, height, round, ext) + return crypto.NewSignItem(quorumType, quorumHash, requestID, signBytes), nil +} diff --git a/types/vote_set.go b/types/vote_set.go index 103e86dcab..7e73c05105 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -70,8 +70,8 @@ type VoteSet struct { peerMaj23s map[string]maj23Info // Maj23 for each peer // dash fields - thresholdBlockSig []byte // If a 2/3 majority is seen, recover the block sig - thresholdVoteExtSigs []ThresholdExtensionSign // If a 2/3 majority is seen, recover the vote extension sigs + thresholdBlockSig []byte // If a 2/3 majority is seen, recover the block sig + thresholdVoteExtSigs VoteExtensions // If a 2/3 majority is seen, recover the vote extension sigs } type maj23Info struct { @@ -349,10 +349,10 @@ func (voteSet *VoteSet) recoverThresholdSignsAndVerify(blockVotes *blockVotes, q // there is only 1 validator vote := blockVotes.votes[0] voteSet.thresholdBlockSig = vote.BlockSignature - voteSet.thresholdVoteExtSigs = MakeThresholdVoteExtensions( - vote.VoteExtensions[tmproto.VoteExtensionType_THRESHOLD_RECOVER], - vote.GetVoteExtensionsSigns(tmproto.VoteExtensionType_THRESHOLD_RECOVER), - ) + voteSet.thresholdVoteExtSigs = vote.VoteExtensions. + Filter(func(ext VoteExtensionIf) bool { + return ext.IsThresholdRecoverable() + }).Copy() return nil } err := voteSet.recoverThresholdSigns(blockVotes) @@ -377,7 +377,7 @@ func (voteSet *VoteSet) recoverThresholdSigns(blockVotes *blockVotes) error { return err } voteSet.thresholdBlockSig = thresholdSigns.BlockSign - voteSet.thresholdVoteExtSigs = thresholdSigns.ExtensionSigns + voteSet.thresholdVoteExtSigs = thresholdSigns.ThresholdVoteExtensions return nil } @@ -742,8 +742,8 @@ func (voteSet *VoteSet) MakeCommit() *Commit { func (voteSet *VoteSet) makeCommitSigns() *CommitSigns { return &CommitSigns{ QuorumSigns: QuorumSigns{ - BlockSign: voteSet.thresholdBlockSig, - ExtensionSigns: voteSet.thresholdVoteExtSigs, + BlockSign: voteSet.thresholdBlockSig, + ThresholdVoteExtensions: voteSet.thresholdVoteExtSigs, }, QuorumHash: voteSet.valSet.QuorumHash, } @@ -751,8 +751,8 @@ func (voteSet *VoteSet) makeCommitSigns() *CommitSigns { func (voteSet *VoteSet) makeQuorumSigns() QuorumSigns { return QuorumSigns{ - BlockSign: voteSet.thresholdBlockSig, - ExtensionSigns: voteSet.thresholdVoteExtSigs, + BlockSign: voteSet.thresholdBlockSig, + ThresholdVoteExtensions: voteSet.thresholdVoteExtSigs, } } diff --git a/types/vote_test.go b/types/vote_test.go index e0cbd8a6ae..3283f46781 100644 --- a/types/vote_test.go +++ b/types/vote_test.go @@ -21,7 +21,7 @@ import ( const ( //nolint: lll - preCommitTestStr = `Vote{56789:959A8F5EF2BE 12345/02/Precommit(8B01023386C3) 000000000000 000000000000}` + preCommitTestStr = `Vote{56789:959A8F5EF2BE 12345/02/Precommit(8B01023386C3) 000000000000 03962B14DA9F}` //nolint: lll preVoteTestStr = `Vote{56789:959A8F5EF2BE 12345/02/Prevote(8B01023386C3) 000000000000 000000000000}` ) @@ -39,12 +39,11 @@ func examplePrevote(t *testing.T) *Vote { func examplePrecommit(t testing.TB) *Vote { t.Helper() vote := exampleVote(t, byte(tmproto.PrecommitType)) - vote.VoteExtensions = VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{ - Type: tmproto.VoteExtensionType_DEFAULT, - Signature: []byte("signature"), - }}, - } + vote.VoteExtensions = VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("extension"), + Signature: make([]byte, SignatureSize), + }) return vote } @@ -182,11 +181,9 @@ func TestVoteSignBytesTestVectors(t *testing.T) { // containing vote extension 5: { "test_chain_id", &Vote{ - Height: 1, - Round: 1, - VoteExtensions: VoteExtensions{ - tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("extension")}}, - }, + Height: 1, + Round: 1, + VoteExtensions: VoteExtensionsFromProto(&tmproto.VoteExtension{Extension: []byte("extension")}), }, []byte{ 0x0, 0x0, 0x0, 0x0, //type @@ -335,47 +332,39 @@ func TestVoteExtension(t *testing.T) { }{ { name: "valid THRESHOLD_RECOVER", - extensions: VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{ - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Extension: []byte("extension")}}, - }, + extensions: VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("extension")}), includeSignature: true, expectError: false, }, { name: "valid THRESHOLD_RECOVER_RAW plwdtx", - extensions: VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW: []tmproto.VoteExtension{{ - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, - XSignRequestId: &tmproto.VoteExtension_SignRequestId{ - SignRequestId: []byte("\x06plwdtx"), - }, - Extension: []byte("extension")}}, - }, + extensions: VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, + XSignRequestId: &tmproto.VoteExtension_SignRequestId{ + SignRequestId: []byte("\x06plwdtx"), + }, + Extension: []byte("extension")}), includeSignature: true, expectError: false, }, { name: "valid THRESHOLD_RECOVER_RAW dpevote", - extensions: VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW: []tmproto.VoteExtension{{ - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, - XSignRequestId: &tmproto.VoteExtension_SignRequestId{ - SignRequestId: []byte("dpevote"), - }, - Extension: []byte("extension")}}, - }, + extensions: VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, + XSignRequestId: &tmproto.VoteExtension_SignRequestId{ + SignRequestId: []byte("dpevote"), + }, + Extension: []byte("extension")}), includeSignature: true, expectError: false, }, { name: "no extension signature", - extensions: VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{ - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Extension: []byte("extension")}}, - }, + extensions: VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("extension")}), includeSignature: false, expectError: true, }, @@ -413,13 +402,11 @@ func TestVoteExtension(t *testing.T) { require.NoError(t, err) vote.BlockSignature = v.BlockSignature if tc.includeSignature { - protoExtensionsMap := v.VoteExtensionsToMap() - for et, extensions := range protoExtensionsMap { - for i, ext := range extensions { - vote.VoteExtensions[et][i].Signature = ext.Signature - } + for i, ext := range v.VoteExtensions { + vote.VoteExtensions[i].SetSignature(ext.Signature) } } + err = vote.VerifyWithExtension("test_chain_id", btcjson.LLMQType_5_60, quorumHash, pk, proTxHash) if tc.expectError { require.Error(t, err) @@ -503,6 +490,7 @@ func TestVoteString(t *testing.T) { vote: func() *Vote { v := examplePrecommit(t) v.BlockID.Hash = nil + v.VoteExtensions = nil return v }(), expectedResult: nilVoteTestStr, @@ -548,7 +536,11 @@ func TestValidVotes(t *testing.T) { { "good precommit with vote extension", examplePrecommit(t), func(v *Vote) { - v.VoteExtensions[tmproto.VoteExtensionType_DEFAULT][0].Extension = []byte("extension") + v.VoteExtensions[0] = VoteExtensionFromProto(tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("extension"), + Signature: make([]byte, SignatureSize), + }) }, }, } @@ -612,13 +604,13 @@ func TestInvalidPrevotes(t *testing.T) { { "vote extension present", func(v *Vote) { - v.VoteExtensions = VoteExtensions{tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Extension: []byte("extension")}}} + v.VoteExtensions = VoteExtensionsFromProto(&tmproto.VoteExtension{Extension: []byte("extension")}) }, }, { "vote extension signature present", func(v *Vote) { - v.VoteExtensions = VoteExtensions{tmproto.VoteExtensionType_DEFAULT: []tmproto.VoteExtension{{Signature: []byte("signature")}}} + v.VoteExtensions = VoteExtensionsFromProto(&tmproto.VoteExtension{Signature: []byte("signature")}) }, }, } @@ -643,9 +635,7 @@ func TestInvalidPrecommitExtensions(t *testing.T) { }{ { "vote extension present without signature", func(v *Vote) { - v.VoteExtensions = VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER: {{Extension: []byte("extension")}}, - } + v.VoteExtensions = VoteExtensionsFromProto(&tmproto.VoteExtension{Extension: []byte("extension")}) }, }, // TODO(thane): Re-enable once https://github.com/tendermint/tendermint/issues/8272 is resolved @@ -653,11 +643,9 @@ func TestInvalidPrecommitExtensions(t *testing.T) { { "oversized vote extension signature", func(v *Vote) { - v.VoteExtensions = VoteExtensions{ - tmproto.VoteExtensionType_THRESHOLD_RECOVER: []tmproto.VoteExtension{{ - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Signature: make([]byte, SignatureSize+1)}}, - } + v.VoteExtensions = VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Signature: make([]byte, SignatureSize+1)}) }, }, } @@ -683,7 +671,11 @@ func TestVoteExtensionsSignBytes(t *testing.T) { Signature: []byte{}, Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, } - actual := VoteExtensionSignBytes("some-chain", 1, 2, &ve) + signItem, err := VoteExtensionFromProto(ve).SignItem("some-chain", 1, 2, btcjson.LLMQType_TEST_PLATFORM, crypto.RandQuorumHash()) + assert.NoError(t, err) + + actual := signItem.Raw + t.Logf("sign bytes: %x", actual) assert.EqualValues(t, expect, actual) } @@ -701,7 +693,11 @@ func TestVoteExtensionsSignBytesRaw(t *testing.T) { SignRequestId: []byte("dpevote-someSignRequestID"), }, } - actual := VoteExtensionSignBytes("some-chain", 1, 2, &ve) + signItem, err := VoteExtensionFromProto(ve).SignItem("some-chain", 1, 2, btcjson.LLMQType_TEST_PLATFORM, crypto.RandQuorumHash()) + assert.NoError(t, err) + + actual := signItem.Raw + t.Logf("sign bytes: %x", actual) assert.EqualValues(t, expect, actual) } From a0af38ff2a0b102cf5f94c453c2f3307f6e16f6d Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 20 Dec 2023 15:09:34 +0100 Subject: [PATCH 24/55] test(e2e): workaround for broken ConsensusParams --- test/e2e/tests/app_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/e2e/tests/app_test.go b/test/e2e/tests/app_test.go index 3c5b239681..03706c2771 100644 --- a/test/e2e/tests/app_test.go +++ b/test/e2e/tests/app_test.go @@ -203,7 +203,10 @@ func TestApp_TxTooBig(t *testing.T) { client, err := node.Client() require.NoError(t, err) - cp, err := client.ConsensusParams(ctx, nil) + // FIXME: ConsensusParams is broken for last height, this is just workaround + status, err := client.Status(ctx) + assert.NoError(t, err) + cp, err := client.ConsensusParams(ctx, &status.SyncInfo.LatestBlockHeight) assert.NoError(t, err) // ensure we have more txs than fits the block From d6e1d9c0d29c9e087839c9fe55baa6492d8acd69 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 21 Dec 2023 00:29:16 +0100 Subject: [PATCH 25/55] refactor: vote extensions refactoring --- internal/consensus/reactor.go | 4 +++ internal/consensus/vote_signer_test.go | 4 +++ internal/state/execution.go | 2 +- privval/dash_core_signer_client.go | 2 +- proto/tendermint/types/dash_test.go | 31 ++++++++++++++++++ test/e2e/app/app.go | 21 ++++++------ types/block.go | 8 ++--- types/canonical.go | 11 +++---- types/quorum.go | 8 ++--- types/signs_recoverer.go | 13 ++++++-- types/validation_test.go | 2 +- types/vote.go | 1 + types/vote_extension.go | 45 ++++++++++++++++++++++++-- types/vote_extension_test.go | 24 ++++++++++++++ 14 files changed, 141 insertions(+), 35 deletions(-) create mode 100644 proto/tendermint/types/dash_test.go create mode 100644 types/vote_extension_test.go diff --git a/internal/consensus/reactor.go b/internal/consensus/reactor.go index bd789bfeec..38c9063d3e 100644 --- a/internal/consensus/reactor.go +++ b/internal/consensus/reactor.go @@ -687,6 +687,10 @@ func (r *Reactor) handleVoteMessage(ctx context.Context, envelope *p2p.Envelope, if isValidator { // ignore votes on non-validator nodes; TODO don't even send it vMsg := msgI.(*VoteMessage) + if err := vMsg.Vote.ValidateBasic(); err != nil { + return fmt.Errorf("invalid vote received from %s: %w", envelope.From, err) + } + ps.EnsureVoteBitArrays(height, valSize) ps.EnsureVoteBitArrays(height-1, lastCommitSize) if err := ps.SetHasVote(vMsg.Vote); err != nil { diff --git a/internal/consensus/vote_signer_test.go b/internal/consensus/vote_signer_test.go index 89b2244c3d..38abd21c45 100644 --- a/internal/consensus/vote_signer_test.go +++ b/internal/consensus/vote_signer_test.go @@ -138,6 +138,10 @@ func TestVoteSigner_signAddVote(t *testing.T) { key, err := privVal.GetPubKey(ctx, valSet.QuorumHash) assert.NoError(t, err) + for _, ext := range vote.VoteExtensions { + assert.NotEmpty(t, ext.GetSignature()) + } + key1, err := bls.G1ElementFromBytes(key.Bytes()) assert.NoError(t, err) diff --git a/internal/state/execution.go b/internal/state/execution.go index 98ba693c40..463474da59 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -615,7 +615,7 @@ func buildLastCommitInfo(block *types.Block, initialHeight int64) abci.CommitInf Round: block.LastCommit.Round, QuorumHash: block.LastCommit.QuorumHash, BlockSignature: block.LastCommit.ThresholdBlockSignature, - ThresholdVoteExtensions: block.LastCommit.ThresholdVoteExtensions.ToProto(), + ThresholdVoteExtensions: block.LastCommit.ThresholdVoteExtensions, } } diff --git a/privval/dash_core_signer_client.go b/privval/dash_core_signer_client.go index 14a3d2704a..3dd46b7e32 100644 --- a/privval/dash_core_signer_client.go +++ b/privval/dash_core_signer_client.go @@ -275,7 +275,7 @@ func (sc *DashCoreSignerClient) SignVote( "voteType", protoVote.Type, "quorumType", quorumType, "quorumHash", quorumHash, - "signature", qs.sign, + "signature", hex.EncodeToString(qs.sign), "proTxHash", proTxHash, "coreBlockRequestId", qs.ID, "coreSignId", tmbytes.Reverse(qs.signHash), diff --git a/proto/tendermint/types/dash_test.go b/proto/tendermint/types/dash_test.go new file mode 100644 index 0000000000..4d430a690d --- /dev/null +++ b/proto/tendermint/types/dash_test.go @@ -0,0 +1,31 @@ +package types_test + +import ( + "testing" + + "github.com/dashpay/tenderdash/internal/libs/protoio" + "github.com/dashpay/tenderdash/proto/tendermint/types" + "github.com/stretchr/testify/assert" +) + +func TestMarshalVoteExtension(t *testing.T) { + + ve := &types.VoteExtension{ + Type: types.VoteExtensionType_THRESHOLD_RECOVER_RAW, + Extension: []byte("threshold"), + XSignRequestId: &types.VoteExtension_SignRequestId{ + SignRequestId: []byte("sign-request-id"), + }, + } + + v := types.Vote{ + Type: types.PrecommitType, + VoteExtensions: []*types.VoteExtension{ve}, + } + v.Marshal() + + ve.Marshal() + marshaled, err := protoio.MarshalDelimited(ve) + assert.NoError(t, err) + assert.NotEmpty(t, marshaled) +} diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index 027577b30a..f5862fa19b 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -6,7 +6,7 @@ import ( "encoding/binary" "errors" "fmt" - "math/rand" + "math/big" "strconv" "strings" "time" @@ -17,6 +17,7 @@ import ( "github.com/dashpay/tenderdash/abci/example/code" "github.com/dashpay/tenderdash/abci/example/kvstore" abci "github.com/dashpay/tenderdash/abci/types" + "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/libs/log" types1 "github.com/dashpay/tenderdash/proto/tendermint/types" "github.com/dashpay/tenderdash/types" @@ -85,22 +86,18 @@ func (app *Application) ExtendVote(_ context.Context, req *abci.RequestExtendVot ) return &abci.ResponseExtendVote{}, nil } - ext := make([]byte, binary.MaxVarintLen64) - // We don't care that these values are generated by a weak random number - // generator. It's just for test purposes. - //nolint:gosec // G404: Use of weak random number generator - num := rand.Int63n(voteExtensionMaxVal) - extLen := binary.PutVarint(ext, num) + ext := make([]byte, crypto.DefaultHashSize) + copy(ext, big.NewInt(lastHeight+1).Bytes()) + app.logger.Info("generated vote extension", - "num", num, - "ext", fmt.Sprintf("%x", ext[:extLen]), - "state.Height", lastHeight, + "ext", fmt.Sprintf("%x", ext), + "state.Height", lastHeight+1, ) return &abci.ResponseExtendVote{ VoteExtensions: []*abci.ExtendVoteExtension{ { - Type: types1.VoteExtensionType_DEFAULT, - Extension: ext[:extLen], + Type: types1.VoteExtensionType_THRESHOLD_RECOVER_RAW, + Extension: ext, }, { Type: types1.VoteExtensionType_THRESHOLD_RECOVER, diff --git a/types/block.go b/types/block.go index 5bcec3d59e..05670545ec 100644 --- a/types/block.go +++ b/types/block.go @@ -737,7 +737,7 @@ type Commit struct { QuorumHash crypto.QuorumHash `json:"quorum_hash"` ThresholdBlockSignature []byte `json:"threshold_block_signature"` // ThresholdVoteExtensions keeps the list of recovered threshold signatures for vote-extensions - ThresholdVoteExtensions VoteExtensions `json:"threshold_vote_extensions"` + ThresholdVoteExtensions tmproto.VoteExtensions `json:"threshold_vote_extensions"` // Memoized in first call to corresponding method. // NOTE: can't memoize in constructor because constructor isn't used for @@ -764,7 +764,7 @@ func (commit *Commit) ToCommitInfo() types.CommitInfo { Round: commit.Round, QuorumHash: commit.QuorumHash, BlockSignature: commit.ThresholdBlockSignature, - ThresholdVoteExtensions: commit.ThresholdVoteExtensions.ToProto(), + ThresholdVoteExtensions: commit.ThresholdVoteExtensions, } } @@ -943,7 +943,7 @@ func (commit *Commit) ToProto() *tmproto.Commit { c.BlockID = commit.BlockID.ToProto() c.ThresholdBlockSignature = commit.ThresholdBlockSignature - c.ThresholdVoteExtensions = commit.ThresholdVoteExtensions.ToProto() + c.ThresholdVoteExtensions = commit.ThresholdVoteExtensions c.QuorumHash = commit.QuorumHash return c @@ -967,7 +967,7 @@ func CommitFromProto(cp *tmproto.Commit) (*Commit, error) { commit.QuorumHash = cp.QuorumHash commit.ThresholdBlockSignature = cp.ThresholdBlockSignature - commit.ThresholdVoteExtensions = VoteExtensionsFromProto(cp.ThresholdVoteExtensions...) + commit.ThresholdVoteExtensions = cp.ThresholdVoteExtensions commit.Height = cp.Height commit.Round = cp.Round diff --git a/types/canonical.go b/types/canonical.go index 53385d9039..1bdaf231b1 100644 --- a/types/canonical.go +++ b/types/canonical.go @@ -1,10 +1,9 @@ package types import ( - "errors" + "fmt" "time" - "github.com/dashpay/tenderdash/internal/libs/protoio" tmtime "github.com/dashpay/tenderdash/libs/time" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" ) @@ -33,7 +32,7 @@ func CanonicalizeProposal(chainID string, proposal *tmproto.Proposal) tmproto.Ca // CanonicalizeVoteExtension extracts the vote extension from the given vote // and constructs a CanonicalizeVoteExtension struct, whose representation in // bytes is what is signed in order to produce the vote extension's signature. -func CanonicalizeVoteExtension(chainID string, ext *tmproto.VoteExtension, height int64, round int32) ([]byte, error) { +func CanonicalizeVoteExtension(chainID string, ext *tmproto.VoteExtension, height int64, round int32) (tmproto.CanonicalVoteExtension, error) { switch ext.Type { case tmproto.VoteExtensionType_DEFAULT, tmproto.VoteExtensionType_THRESHOLD_RECOVER: { @@ -44,12 +43,10 @@ func CanonicalizeVoteExtension(chainID string, ext *tmproto.VoteExtension, heigh Round: int64(round), ChainId: chainID, } - return protoio.MarshalDelimited(&canonical) + return canonical, nil } - case tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW: - return ext.Extension, nil } - return nil, errors.New("provided vote extension type does not have canonical form for signing") + return tmproto.CanonicalVoteExtension{}, fmt.Errorf("provided vote extension type %s does not have canonical form for signing", ext.Type) } // CanonicalTime can be used to stringify time in a canonical way. diff --git a/types/quorum.go b/types/quorum.go index d8ea5e66d0..2ea285798f 100644 --- a/types/quorum.go +++ b/types/quorum.go @@ -17,7 +17,7 @@ type CommitSigns struct { func (c *CommitSigns) CopyToCommit(commit *Commit) { commit.QuorumHash = c.QuorumHash commit.ThresholdBlockSignature = c.BlockSign - commit.ThresholdVoteExtensions = c.ThresholdVoteExtensions + commit.ThresholdVoteExtensions = c.ThresholdVoteExtensions.ToProto() } // QuorumSigns holds all created signatures, block, state and for each recovered vote-extensions @@ -33,7 +33,7 @@ type QuorumSigns struct { func NewQuorumSignsFromCommit(commit *Commit) QuorumSigns { return QuorumSigns{ BlockSign: commit.ThresholdBlockSignature, - ThresholdVoteExtensions: commit.ThresholdVoteExtensions, + ThresholdVoteExtensions: VoteExtensionsFromProto(commit.ThresholdVoteExtensions...), } } @@ -135,8 +135,8 @@ func (q *QuorumSingsVerifier) verifyVoteExtensions( for i, sig := range thresholdSigs { if !pubKey.VerifySignatureDigest(signItems[i].ID, sig) { - return fmt.Errorf("vote-extension %d signature is invalid: %X", i, - signItems[i].Raw) + return fmt.Errorf("vote-extension %d signature is invalid: raw %X, signatrure %X", i, + signItems[i].Raw, sig) } } return nil diff --git a/types/signs_recoverer.go b/types/signs_recoverer.go index e97a437d92..d99bbf5de0 100644 --- a/types/signs_recoverer.go +++ b/types/signs_recoverer.go @@ -96,7 +96,6 @@ func (v *SignsRecoverer) addVoteExtensionSigs(voteExtensions VoteExtensions) { for i, ext := range thresholdExtensions { v.voteThresholdExtensionSigs[i] = append(v.voteThresholdExtensionSigs[i], ext.GetSignature()) } - } func (v *SignsRecoverer) recoverBlockSig(thresholdSigns *QuorumSigns) error { @@ -128,7 +127,17 @@ func (v *SignsRecoverer) recoverVoteExtensionSigs(quorumSigs *QuorumSigns) error thresholdExtIndex++ if len(extensionSignatures) > 0 { - thresholdSignature, err := bls12381.RecoverThresholdSignatureFromShares(extensionSignatures, v.validatorProTxHashes) + // as some nodes might have voted nil, we will have empty sigs from them; + // we need to filter them out before threshold-recovering + sigs := make([][]byte, 0, len(extensionSignatures)) + proTxHashes := make([][]byte, 0, len(extensionSignatures)) + for i, sig := range extensionSignatures { + if len(sig) > 0 { + sigs = append(sigs, sig) + proTxHashes = append(proTxHashes, v.validatorProTxHashes[i]) + } + } + thresholdSignature, err := bls12381.RecoverThresholdSignatureFromShares(sigs, proTxHashes) if err != nil { return fmt.Errorf("error recovering vote-extension %d threshold signature: %w", extIndex, err) } diff --git a/types/validation_test.go b/types/validation_test.go index 57541b768a..88fb57cff4 100644 --- a/types/validation_test.go +++ b/types/validation_test.go @@ -140,7 +140,7 @@ func TestValidatorSet_VerifyCommit_CheckThresholdSignatures(t *testing.T) { thresholdSigns, err := recoverer.Recover() require.NoError(t, err) commit.ThresholdBlockSignature = thresholdSigns.BlockSign - commit.ThresholdVoteExtensions = thresholdSigns.ThresholdVoteExtensions + commit.ThresholdVoteExtensions = thresholdSigns.ThresholdVoteExtensions.ToProto() err = valSet.VerifyCommit(chainID, blockID, h, commit) require.NoError(t, err) } diff --git a/types/vote.go b/types/vote.go index ec708b80ea..f2ba83fb73 100644 --- a/types/vote.go +++ b/types/vote.go @@ -380,6 +380,7 @@ func (vote *Vote) MarshalZerologObject(e *zerolog.Event) { e.Str("val_proTxHash", vote.ValidatorProTxHash.ShortString()) e.Int32("val_index", vote.ValidatorIndex) e.Bool("nil", vote.BlockID.IsNil()) + e.Array("extensions", vote.VoteExtensions) } func (vote *Vote) HasVoteMessage() *tmcons.HasVote { diff --git a/types/vote_extension.go b/types/vote_extension.go index 8e9b641647..3c6938cb94 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -10,9 +10,11 @@ import ( "github.com/dashpay/dashd-go/btcjson" abci "github.com/dashpay/tenderdash/abci/types" "github.com/dashpay/tenderdash/crypto" + "github.com/dashpay/tenderdash/internal/libs/protoio" tmbytes "github.com/dashpay/tenderdash/libs/bytes" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" "github.com/hashicorp/go-multierror" + "github.com/rs/zerolog" ) var ( @@ -191,6 +193,10 @@ func VoteExtensionsFromProto(pve ...*tmproto.VoteExtension) VoteExtensions { // Copy creates a deep copy of VoteExtensions func (e VoteExtensions) Copy() VoteExtensions { + if e.IsEmpty() { + return nil + } + copied := make(VoteExtensions, 0, len(e)) for _, ext := range e { copied = append(copied, ext.Copy()) @@ -237,6 +243,13 @@ func (e VoteExtensions) CopySignsToProto(dest tmproto.VoteExtensions) error { return nil } +// Marshal VoteExtensions as zerolog array +func (e VoteExtensions) MarshalZerologArray(a *zerolog.Array) { + for _, ext := range e { + a.Object(ext) + } +} + type VoteExtensionIf interface { // Return type of this vote extension GetType() tmproto.VoteExtensionType @@ -255,6 +268,8 @@ type VoteExtensionIf interface { Validate() error SetSignature(sig []byte) + + zerolog.LogObjectMarshaler } func VoteExtensionFromProto(ve tmproto.VoteExtension) VoteExtensionIf { @@ -282,7 +297,7 @@ func (e GenericVoteExtension) Copy() VoteExtensionIf { } func (e GenericVoteExtension) ToProto() tmproto.VoteExtension { - return e.VoteExtension + return e.VoteExtension.Clone() } func (e GenericVoteExtension) SignItem(chainID string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) { @@ -297,10 +312,29 @@ func (e *GenericVoteExtension) SetSignature(sig []byte) { e.Signature = sig } +func (e GenericVoteExtension) MarshalZerologObject(o *zerolog.Event) { + o.Str("type", e.GetType().String()) + o.Hex("extension", e.GetExtension()) + o.Hex("signature", e.GetSignature()) + o.Hex("sign_request_id", e.GetSignRequestId()) +} + +//nolint:revive,stylecheck // name is the same as in protobuf-generated code +func (e GenericVoteExtension) GetSignRequestId() []byte { + if e.XSignRequestId == nil { + return nil + } + id, ok := e.XSignRequestId.(*tmproto.VoteExtension_SignRequestId) + if !ok || id == nil { + return nil + } + + return id.SignRequestId +} + // ThresholdVoteExtension is a threshold type of VoteExtension type ThresholdVoteExtension struct { GenericVoteExtension - ThresholdSignature []byte } func (e ThresholdVoteExtension) Copy() VoteExtensionIf { @@ -369,10 +403,15 @@ func voteExtensionRequestID(height int64, round int32) ([]byte, error) { // Similar to VoteSignBytes, the encoded Protobuf message is varint // length-prefixed for backwards-compatibility with the Amino encoding. func voteExtensionSignBytes(chainID string, height int64, round int32, ext *tmproto.VoteExtension) []byte { - bz, err := CanonicalizeVoteExtension(chainID, ext, height, round) + canonical, err := CanonicalizeVoteExtension(chainID, ext, height, round) if err != nil { panic(err) } + bz, err := protoio.MarshalDelimited(&canonical) + if err != nil { + panic(err) + } + return bz } diff --git a/types/vote_extension_test.go b/types/vote_extension_test.go new file mode 100644 index 0000000000..17ed25f02a --- /dev/null +++ b/types/vote_extension_test.go @@ -0,0 +1,24 @@ +package types + +import ( + "testing" + + tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestVoteExtensionCopySignsFromProto(t *testing.T) { + src := tmproto.VoteExtensions{ + &tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("threshold"), + Signature: []byte("signature"), + }, + } + + dst := VoteExtensions{&ThresholdVoteExtension{}} + err := dst.CopySignsFromProto(src) + require.NoError(t, err) + assert.EqualValues(t, src[0].GetSignature(), dst[0].GetSignature()) +} From 59a926285f09740f18ac6b078d3e147315a709f2 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:11:27 +0100 Subject: [PATCH 26/55] refactor: further vote extensions refactoring --- abci/example/kvstore/kvstore.go | 4 +- abci/example/kvstore/verify.go | 8 +- crypto/quorum.go | 68 +++++++----- crypto/quorum_test.go | 32 ++++++ dash/core/mock.go | 4 +- internal/blocksync/reactor_test.go | 5 +- internal/consensus/block_executor.go | 2 +- internal/consensus/block_executor_test.go | 2 +- internal/consensus/replay_test.go | 3 +- internal/consensus/vote_signer_test.go | 8 +- internal/evidence/pool_test.go | 1 + internal/state/execution_test.go | 6 +- internal/state/helpers_test.go | 1 + internal/state/test/factory/block.go | 7 +- internal/state/validation_test.go | 11 +- internal/store/store_test.go | 1 + light/helpers_test.go | 2 +- node/node_test.go | 4 +- privval/dash_consensus_key.go | 2 +- privval/dash_core_signer_client.go | 19 ++-- privval/file.go | 8 +- privval/file_test.go | 10 +- test/e2e/pkg/mockcoreserver/core_server.go | 4 +- types/block.go | 7 +- types/block_test.go | 2 +- types/evidence_test.go | 2 +- types/priv_validator.go | 2 +- types/proposal.go | 2 +- types/quorum.go | 37 +++++-- types/quorum_sign_data.go | 28 ++++- types/quorum_sign_data_test.go | 18 ++-- types/signs_recoverer.go | 117 ++++++++++++--------- types/validation_test.go | 35 ++++-- types/vote.go | 6 +- types/vote_extension.go | 101 +++++++++++++++--- types/vote_set.go | 8 +- 36 files changed, 396 insertions(+), 181 deletions(-) create mode 100644 crypto/quorum_test.go diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index 04acec1898..b7504090ba 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -411,8 +411,8 @@ func (app *Application) FinalizeBlock(_ context.Context, req *abci.RequestFinali if app.shouldCommitVerify { vsu := app.getActiveValidatorSetUpdates() qsd := types.QuorumSignData{ - Block: makeBlockSignItem(req, btcjson.LLMQType_5_60, vsu.QuorumHash), - ThresholdVoteExtensions: makeVoteExtensionSignItems(req, btcjson.LLMQType_5_60, vsu.QuorumHash), + Block: makeBlockSignItem(req, btcjson.LLMQType_5_60, vsu.QuorumHash), + VoteExtensionSignItems: makeVoteExtensionSignItems(req, btcjson.LLMQType_5_60, vsu.QuorumHash), } err := app.verifyBlockCommit(qsd, req.Commit) if err != nil { diff --git a/abci/example/kvstore/verify.go b/abci/example/kvstore/verify.go index 64ae3c94e3..444dbab82e 100644 --- a/abci/example/kvstore/verify.go +++ b/abci/example/kvstore/verify.go @@ -23,9 +23,15 @@ func (app *Application) verifyBlockCommit(qsd types.QuorumSignData, commit abci. if err != nil { return err } + + extSigs := make([][]byte, 0, len(commit.ThresholdVoteExtensions)) + for _, ext := range commit.ThresholdVoteExtensions { + extSigs = append(extSigs, ext.Signature) + } + return verifier.Verify(pubKey, types.QuorumSigns{ BlockSign: commit.BlockSignature, - ThresholdVoteExtensions: types.VoteExtensionsFromProto(commit.ThresholdVoteExtensions...), + VoteExtensionSignatures: extSigs, }) } diff --git a/crypto/quorum.go b/crypto/quorum.go index 1ad885e2af..6d6c0d95a1 100644 --- a/crypto/quorum.go +++ b/crypto/quorum.go @@ -6,34 +6,36 @@ import ( bls "github.com/dashpay/bls-signatures/go-bindings" "github.com/dashpay/dashd-go/btcjson" + tmbytes "github.com/dashpay/tenderdash/libs/bytes" "github.com/rs/zerolog" ) // SignItem represents signing session data (in field SignItem.ID) that will be signed to get threshold signature share. +// Field names are the same as in Dash Core, but the meaning is different. // See DIP-0007 type SignItem struct { - ReqID []byte // Request ID for quorum signing - ID []byte // Signature ID - Raw []byte // Raw data to be signed - Hash []byte // Checksum of Raw - QuorumType btcjson.LLMQType // Quorum type for which this sign item is created + ID []byte // Request ID for quorum signing + SignHash []byte // Hash of llmqType, quorumHash, id, and msgHash - final data to sign/verify + Raw []byte // Raw data to be signed, before any transformations + RawHash []byte // Checksum of Raw + LlmqType btcjson.LLMQType // Quorum type for which this sign item is created QuorumHash []byte // Quorum hash for which this sign item is created } // Validate validates prepared data for signing func (i *SignItem) Validate() error { - if len(i.ReqID) != DefaultHashSize { - return fmt.Errorf("invalid request ID size: %X", i.ReqID) + if len(i.ID) != DefaultHashSize { + return fmt.Errorf("invalid request ID size: %X", i.ID) } - if len(i.Hash) != DefaultHashSize { - return fmt.Errorf("invalid hash size %d: %X", len(i.Hash), i.Hash) + if len(i.RawHash) != DefaultHashSize { + return fmt.Errorf("invalid hash size %d: %X", len(i.RawHash), i.RawHash) } if len(i.QuorumHash) != DefaultHashSize { return fmt.Errorf("invalid quorum hash size %d: %X", len(i.QuorumHash), i.QuorumHash) } if len(i.Raw) > 0 { - if !bytes.Equal(Checksum(i.Raw), i.Hash) { - return fmt.Errorf("invalid hash %X for raw data: %X", i.Hash, i.Raw) + if !bytes.Equal(Checksum(i.Raw), i.RawHash) { + return fmt.Errorf("invalid hash %X for raw data: %X", i.RawHash, i.Raw) } } return nil @@ -41,9 +43,9 @@ func (i *SignItem) Validate() error { func (i SignItem) MarshalZerologObject(e *zerolog.Event) { e.Hex("signBytes", i.Raw) - e.Hex("signRequestID", i.ReqID) - e.Hex("signID", i.ID) - e.Hex("signHash", i.Hash) + e.Hex("signRequestID", i.ID) + e.Hex("signID", i.SignHash) + e.Hex("signHash", i.RawHash) } // NewSignItem creates a new instance of SignItem with calculating a hash for a raw and creating signID @@ -64,31 +66,37 @@ func NewSignItem(quorumType btcjson.LLMQType, quorumHash, reqID, raw []byte) Sig // Create a new sign item without raw value, using provided hash. func NewSignItemFromHash(quorumType btcjson.LLMQType, quorumHash, reqID, msgHash []byte) SignItem { item := SignItem{ - ReqID: reqID, - Hash: msgHash, - QuorumType: quorumType, + ID: reqID, + RawHash: msgHash, + LlmqType: quorumType, QuorumHash: quorumHash, Raw: nil, // Raw is empty, as we don't have it } - item.UpdateID() + + // By default, reverse fields when calculating SignHash + item.UpdateSignHash(true) return item } -func (i *SignItem) UpdateID() { +// UpdateSignHash recalculates signHash field +// If reverse is true, then all []byte elements will be reversed before +// calculating signID +func (i *SignItem) UpdateSignHash(reverse bool) { if err := i.Validate(); err != nil { panic("invalid sign item: " + err.Error()) } - // FIXME: previously we had reversals, but this doesn't work with Core test vectors - // So - // quorumHash := tmbytes.Reverse(i.QuorumHash) + llmqType := i.LlmqType + quorumHash := i.QuorumHash - // requestID := tmbytes.Reverse(i.ReqID) - requestID := i.ReqID - // messageHash := tmbytes.Reverse(i.Hash) - messageHash := i.Hash + requestID := i.ID + messageHash := i.RawHash - llmqType := i.QuorumType + if reverse { + quorumHash = tmbytes.Reverse(quorumHash) + requestID = tmbytes.Reverse(requestID) + messageHash = tmbytes.Reverse(messageHash) + } // if testing.Testing() { // fmt.Printf("generating sign ID using bls.BuildSignHash for %d %X %X %X\n", llmqType, quorumHash, requestID, messageHash) @@ -99,6 +107,7 @@ func (i *SignItem) UpdateID() { // fmt.Printf("data before sha256: %X\n", out) // fmt.Printf("sha256(sha256(data)): %X\n", crypto.Checksum((crypto.Checksum(out)))) // } + var blsQuorumHash bls.Hash copy(blsQuorumHash[:], quorumHash) @@ -112,6 +121,9 @@ func (i *SignItem) UpdateID() { signHash := make([]byte, 32) copy(signHash, blsSignHash[:]) + if reverse { + signHash = tmbytes.Reverse(signHash) + } - i.ID = signHash + i.SignHash = signHash } diff --git a/crypto/quorum_test.go b/crypto/quorum_test.go new file mode 100644 index 0000000000..6b6873f87a --- /dev/null +++ b/crypto/quorum_test.go @@ -0,0 +1,32 @@ +package crypto_test + +import ( + "encoding/hex" + "testing" + + "github.com/dashpay/tenderdash/crypto" + "github.com/stretchr/testify/assert" +) + +func TestQuorumSignItem(t *testing.T) { + + si := crypto.SignItem{ + ID: mustHexDecode("87cda9461081793e7e31ab1def8ffbd453775a0f9987304598398d42a78d68d4"), + RawHash: mustHexDecode("5ef9b9eecc4df7c5aee677c0a72816f4515999a539003cf4bbb6c15c39634c31"), + LlmqType: 106, + QuorumHash: mustHexDecode("366f07c9b80a2661563a33c09f02156720159b911186b4438ff281e537674771"), + } + si.UpdateSignHash(true) + + expectID := mustHexDecode("94635358f4c75a1d0b38314619d1c5d9a16f12961b5314d857e04f2eb61d78d2") + + assert.EqualValues(t, expectID, si.SignHash) +} + +func mustHexDecode(s string) []byte { + b, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return b +} diff --git a/dash/core/mock.go b/dash/core/mock.go index 4d9f07eb80..e36e1f8d56 100644 --- a/dash/core/mock.go +++ b/dash/core/mock.go @@ -152,7 +152,7 @@ func (mc *MockClient) QuorumSign( if !mc.canSign { return nil, errors.New("dash core mock client not set up for signing") } - signID := crypto.NewSignItemFromHash(quorumType, quorumHash, requestID, messageHash).ID + signID := crypto.NewSignItemFromHash(quorumType, quorumHash, requestID, messageHash).SignHash privateKey, err := mc.localPV.GetPrivateKey(context.Background(), quorumHash) if err != nil { @@ -186,7 +186,7 @@ func (mc *MockClient) QuorumVerify( return false, err } - signID := crypto.NewSignItemFromHash(quorumType, quorumHash, requestID, messageHash).ID + signID := crypto.NewSignItemFromHash(quorumType, quorumHash, requestID, messageHash).SignHash thresholdPublicKey, err := mc.localPV.GetThresholdPublicKey(context.Background(), quorumHash) if err != nil { diff --git a/internal/blocksync/reactor_test.go b/internal/blocksync/reactor_test.go index f9c7d7a7d4..08a2770277 100644 --- a/internal/blocksync/reactor_test.go +++ b/internal/blocksync/reactor_test.go @@ -189,7 +189,7 @@ func (rts *reactorTestSuite) addNode( peerEvents := func(ctx context.Context, _ string) *p2p.PeerUpdates { return rts.peerUpdates[nodeID] } reactor := makeReactor(ctx, t, rts.config, proTxHash, nodeID, genDoc, privVal, chCreator, peerEvents) - commit := types.NewCommit(0, 0, types.BlockID{}, nil) + commit := types.NewCommit(0, 0, types.BlockID{}, nil, nil) state, err := reactor.stateStore.Load() require.NoError(t, err) @@ -237,10 +237,11 @@ func makeNextBlock(ctx context.Context, vote.Height, vote.Round, blockID, + vote.VoteExtensions, &types.CommitSigns{ QuorumSigns: types.QuorumSigns{ BlockSign: vote.BlockSignature, - ThresholdVoteExtensions: vote.VoteExtensions.Filter(func(ext types.VoteExtensionIf) bool { return ext.IsThresholdRecoverable() }), + VoteExtensionSignatures: vote.VoteExtensions.GetSignatures(), }, QuorumHash: state.Validators.QuorumHash, }, diff --git a/internal/consensus/block_executor.go b/internal/consensus/block_executor.go index c2beffcb46..6a0e768857 100644 --- a/internal/consensus/block_executor.go +++ b/internal/consensus/block_executor.go @@ -40,7 +40,7 @@ func (c *blockExecutor) create(ctx context.Context, rs *cstypes.RoundState, roun case rs.Height == c.committedState.InitialHeight: // We're creating a proposal for the first block. // The commit is empty, but not nil. - commit = types.NewCommit(0, 0, types.BlockID{}, nil) + commit = types.NewCommit(0, 0, types.BlockID{}, nil, nil) case rs.LastCommit != nil: // Make the commit from LastPrecommits commit = rs.LastCommit diff --git a/internal/consensus/block_executor_test.go b/internal/consensus/block_executor_test.go index 6a2dd76887..9fa00938ee 100644 --- a/internal/consensus/block_executor_test.go +++ b/internal/consensus/block_executor_test.go @@ -53,7 +53,7 @@ func (suite *BlockExecutorTestSuite) TestCreate() { Height: 99, Round: 0, } - emptyCommit := types.NewCommit(0, 0, types.BlockID{}, nil) + emptyCommit := types.NewCommit(0, 0, types.BlockID{}, nil, nil) testCases := []struct { round int32 initialHeight int64 diff --git a/internal/consensus/replay_test.go b/internal/consensus/replay_test.go index 7fbc9d3139..acad5f6f33 100644 --- a/internal/consensus/replay_test.go +++ b/internal/consensus/replay_test.go @@ -1121,10 +1121,11 @@ func makeBlockchainFromWAL(t *testing.T, wal WAL) ([]*types.Block, []*types.Comm if p.Type == tmproto.PrecommitType { thisBlockCommit = types.NewCommit(p.Height, p.Round, p.BlockID, + p.VoteExtensions, &types.CommitSigns{ QuorumSigns: types.QuorumSigns{ BlockSign: p.BlockSignature, - ThresholdVoteExtensions: p.VoteExtensions, + VoteExtensionSignatures: p.VoteExtensions.GetSignatures(), }, QuorumHash: crypto.RandQuorumHash(), }, diff --git a/internal/consensus/vote_signer_test.go b/internal/consensus/vote_signer_test.go index 38abd21c45..c21b18e1fb 100644 --- a/internal/consensus/vote_signer_test.go +++ b/internal/consensus/vote_signer_test.go @@ -87,25 +87,25 @@ func TestVoteSigner_signAddVote(t *testing.T) { { msgType: tmproto.PrevoteType, blockID: blockID, - wantBlockSign: "80B628F02FE2047C7B98175CD8CF609775B95393C63D8EBC2F630D95121C28826C942F6511405D33484639C2906879110FDC293418C95862A60329FDDF0B210654559839B5ABFC11E50AFC4E498B0C9041118394DB04E52D0B28A92FC91DEABC", + wantBlockSign: "8400E1599EB8E954C7DBE069B14941B71E010D92F4999B4A64752AF1969EE9AF140F953A40F212F0E63C4EF92C5F9BDA1930D753B1522183C7EA46EC847C9053FE4AFAEA17B60C263F015380497B64F4CE2480D01CB4DE9A64F9C8E048472CF2", }, { msgType: tmproto.PrecommitType, - wantBlockSign: "8BEEE4EDA67394060C1A1D41797E998120B7BC217E7D36526DA76AE57616475FB1C4DCF08C522E76C75220104611F56800F1CF299ECD98FDB1C598471DC0D4048F8F5381B034270EB0B66E987D61B7DF555DFA92C6B5C9E6FAD608676130A726", + wantBlockSign: "88AB6D08FC3E9D258A1CB78288EF00E49F245A4E9AF5CAFF0DBEBDB31CB0098D7B4A93424681F1747686163938CE6647023424C47E7ED5656F33693D112853D6483CE795F788ED3A657F74B58C2215CA056324EC33DF6C44608DA65B13563224", }, { msgType: tmproto.PrecommitType, blockID: blockID, voteExtensions: nil, mockFn: mockFn, - wantBlockSign: "B2C484BB07094AAB8EFAB187982F6A8E8172FBEBAE5B6EB6304E527ABAAB7D059D9A43DDDBA82A6D296AF30E67C28D250449A586E9A69C2577057E01FA290BB03C186982D4D45E6016935AD4B9A84EB0911B62A83E457E25CE44DC28516D0E0A", + wantBlockSign: "B89D8AB4B59B4285A05C59C7C2641EF64DBB1A68C99F55FB2716EE25CDA264A0F87D02767EEBA7124E926325CE36D96D157674633C229D8BFCD8CB039889700D87A2041CF9D44A3D0BC2F231E64EB3815199DCB70184BCDC8CAC593AF3C3FE5F", }, { msgType: tmproto.PrecommitType, blockID: blockID, voteExtensions: types.VoteExtensionsFromProto(voteExtensions...), mockFn: mockFn, - wantBlockSign: "B2C484BB07094AAB8EFAB187982F6A8E8172FBEBAE5B6EB6304E527ABAAB7D059D9A43DDDBA82A6D296AF30E67C28D250449A586E9A69C2577057E01FA290BB03C186982D4D45E6016935AD4B9A84EB0911B62A83E457E25CE44DC28516D0E0A", + wantBlockSign: "B89D8AB4B59B4285A05C59C7C2641EF64DBB1A68C99F55FB2716EE25CDA264A0F87D02767EEBA7124E926325CE36D96D157674633C229D8BFCD8CB039889700D87A2041CF9D44A3D0BC2F231E64EB3815199DCB70184BCDC8CAC593AF3C3FE5F", }, } for i, tc := range testCases { diff --git a/internal/evidence/pool_test.go b/internal/evidence/pool_test.go index 1669a47146..faf95de6a3 100644 --- a/internal/evidence/pool_test.go +++ b/internal/evidence/pool_test.go @@ -563,6 +563,7 @@ func makeCommit(height int64, quorumHash []byte, valProTxHash []byte) *types.Com height, 0, types.BlockID{}, + nil, &types.CommitSigns{ QuorumSigns: types.QuorumSigns{ BlockSign: crypto.CRandBytes(types.SignatureSize), diff --git a/internal/state/execution_test.go b/internal/state/execution_test.go index 41f6673cc7..fe890f927f 100644 --- a/internal/state/execution_test.go +++ b/internal/state/execution_test.go @@ -236,7 +236,7 @@ func TestProcessProposal(t *testing.T) { Signature: make([]byte, bls12381.SignatureSize), } - lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, nil) + lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, nil, nil) block1, err := sf.MakeBlock(state, height, lastCommit, 1) require.NoError(t, err) block1.SetCoreChainLock(&coreChainLockUpdate) @@ -316,7 +316,7 @@ func TestUpdateConsensusParams(t *testing.T) { eventBus, ) - lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, nil) + lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, nil, nil) txResults := factory.ExecTxResults(txs) app.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{ @@ -601,7 +601,7 @@ func TestFinalizeBlockValidatorUpdates(t *testing.T) { 1, round, state, - types.NewCommit(state.LastBlockHeight, 0, state.LastBlockID, nil), + types.NewCommit(state.LastBlockHeight, 0, state.LastBlockID, nil, nil), proTxHashes[0], 1, ) diff --git a/internal/state/helpers_test.go b/internal/state/helpers_test.go index 699f855b56..28b3b0a862 100644 --- a/internal/state/helpers_test.go +++ b/internal/state/helpers_test.go @@ -102,6 +102,7 @@ func makeValidCommit( return types.NewCommit( height, 0, blockID, + votes[0].VoteExtensions, &types.CommitSigns{ QuorumSigns: *thresholdSigns, QuorumHash: vals.QuorumHash, diff --git a/internal/state/test/factory/block.go b/internal/state/test/factory/block.go index d6ff4f237a..feff7ec174 100644 --- a/internal/state/test/factory/block.go +++ b/internal/state/test/factory/block.go @@ -84,7 +84,11 @@ func makeBlockAndPartSet( t.Helper() quorumSigns := &types.CommitSigns{QuorumHash: state.LastValidators.QuorumHash} - lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, quorumSigns) + var ve types.VoteExtensions + if lastBlock != nil && lastBlock.LastCommit != nil { + ve = types.VoteExtensionsFromProto(lastBlock.LastCommit.ThresholdVoteExtensions...) + } + lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, ve, quorumSigns) if height > 1 { var err error votes := make([]*types.Vote, len(privVals)) @@ -106,6 +110,7 @@ func makeBlockAndPartSet( lastBlock.Header.Height, 0, lastBlockMeta.BlockID, + types.VoteExtensionsFromProto(lastBlock.LastCommit.ThresholdVoteExtensions...), &types.CommitSigns{ QuorumSigns: *thresholdSigns, QuorumHash: state.LastValidators.QuorumHash, diff --git a/internal/state/validation_test.go b/internal/state/validation_test.go index eb6632d2fe..be1c3abb96 100644 --- a/internal/state/validation_test.go +++ b/internal/state/validation_test.go @@ -78,7 +78,7 @@ func TestValidateBlockHeader(t *testing.T) { }) require.NoError(t, err) - lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil) + lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil, nil) // some bad values wrongHash := crypto.Checksum([]byte("this hash is wrong")) @@ -206,8 +206,8 @@ func TestValidateBlockCommit(t *testing.T) { blockStore, eventBus, ) - lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil) - wrongVoteMessageSignedCommit := types.NewCommit(1, 0, types.BlockID{}, nil) + lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil, nil) + wrongVoteMessageSignedCommit := types.NewCommit(1, 0, types.BlockID{}, nil, nil) badPrivValQuorumHash := crypto.RandQuorumHash() badPrivVal := types.NewMockPVForQuorum(badPrivValQuorumHash) @@ -235,6 +235,7 @@ func TestValidateBlockCommit(t *testing.T) { wrongHeightVote.Height, wrongHeightVote.Round, state.LastBlockID, + wrongHeightVote.VoteExtensions, &types.CommitSigns{ QuorumSigns: *thresholdSigns, QuorumHash: state.Validators.QuorumHash, @@ -338,7 +339,7 @@ func TestValidateBlockCommit(t *testing.T) { QuorumHash: state.Validators.QuorumHash, } wrongVoteMessageSignedCommit = types.NewCommit(goodVote.Height, goodVote.Round, - blockID, quorumSigns) + blockID, goodVote.VoteExtensions, quorumSigns) } } @@ -385,7 +386,7 @@ func TestValidateBlockEvidence(t *testing.T) { blockStore, eventBus, ) - lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil) + lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil,nil) for height := int64(1); height < validationTestsStopHeight; height++ { proposerProTxHash := state.Validators.GetProposer().ProTxHash diff --git a/internal/store/store_test.go b/internal/store/store_test.go index f72816b640..bb719b672a 100644 --- a/internal/store/store_test.go +++ b/internal/store/store_test.go @@ -62,6 +62,7 @@ func makeTestCommit(state sm.State, height int64, timestamp time.Time) *types.Co PartSetHeader: types.PartSetHeader{Hash: []byte(""), Total: 2}, StateID: []byte{}, }, + goodVote.VoteExtensions, &types.CommitSigns{ QuorumSigns: *thresholdSigns, QuorumHash: crypto.RandQuorumHash(), diff --git a/light/helpers_test.go b/light/helpers_test.go index 4b68cfc953..9ff02e0ca0 100644 --- a/light/helpers_test.go +++ b/light/helpers_test.go @@ -87,7 +87,7 @@ func (pkz privKeys) signHeader(t testing.TB, header *types.Header, valSet *types QuorumSigns: *thresholdSigns, QuorumHash: valSet.QuorumHash, } - return types.NewCommit(header.Height, 1, blockID, quorumSigns) + return types.NewCommit(header.Height, 1, blockID, votes[0].VoteExtensions, quorumSigns) } func makeVote(t testing.TB, header *types.Header, valset *types.ValidatorSet, proTxHash crypto.ProTxHash, diff --git a/node/node_test.go b/node/node_test.go index 4376202e41..ab0bf7e047 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -378,7 +378,7 @@ func TestCreateProposalBlock(t *testing.T) { ) proposedAppVersion := uint64(1) - commit := types.NewCommit(height-1, 0, types.BlockID{}, nil) + commit := types.NewCommit(height-1, 0, types.BlockID{}, nil, nil) block, _, err := blockExec.CreateProposalBlock( ctx, height, @@ -466,7 +466,7 @@ func TestMaxTxsProposalBlockSize(t *testing.T) { eventBus, ) - commit := types.NewCommit(height-1, 0, types.BlockID{}, nil) + commit := types.NewCommit(height-1, 0, types.BlockID{}, nil, nil) block, _, err := blockExec.CreateProposalBlock( ctx, height, diff --git a/privval/dash_consensus_key.go b/privval/dash_consensus_key.go index 6fcf1be299..427b6f4f32 100644 --- a/privval/dash_consensus_key.go +++ b/privval/dash_consensus_key.go @@ -105,7 +105,7 @@ func (pub DashConsensusPublicKey) VerifySignature(msg []byte, sig []byte) bool { return pub.VerifySignatureDigest(hash, sig) } func (pub DashConsensusPublicKey) VerifySignatureDigest(hash []byte, sig []byte) bool { - signID := crypto.NewSignItemFromHash(pub.quorumType, pub.quorumHash, hash, hash).ID + signID := crypto.NewSignItemFromHash(pub.quorumType, pub.quorumHash, hash, hash).SignHash return pub.PubKey.VerifySignatureDigest(signID, sig) } diff --git a/privval/dash_core_signer_client.go b/privval/dash_core_signer_client.go index 3dd46b7e32..68acd6ec93 100644 --- a/privval/dash_core_signer_client.go +++ b/privval/dash_core_signer_client.go @@ -278,7 +278,7 @@ func (sc *DashCoreSignerClient) SignVote( "signature", hex.EncodeToString(qs.sign), "proTxHash", proTxHash, "coreBlockRequestId", qs.ID, - "coreSignId", tmbytes.Reverse(qs.signHash), + "coreSignId", hex.EncodeToString(tmbytes.Reverse(qs.signHash)), "signItem", quorumSigns, "signResult", qs, ) @@ -369,6 +369,8 @@ func (sc *DashCoreSignerClient) signVoteExtensions( protoVote *tmproto.Vote, quorumSignData types.QuorumSignData, ) error { + sc.logger.Trace("signing vote extensions", "vote", protoVote) + if protoVote.Type != tmproto.PrecommitType { if len(protoVote.VoteExtensions) > 0 { return errors.New("unexpected vote extension - extensions are only allowed in precommits") @@ -376,7 +378,7 @@ func (sc *DashCoreSignerClient) signVoteExtensions( return nil } - for i, ext := range quorumSignData.ThresholdVoteExtensions { + for i, ext := range quorumSignData.VoteExtensionSignItems { signItem := ext resp, err := sc.quorumSignAndVerify(ctx, quorumType, quorumHash, signItem) if err != nil { @@ -385,6 +387,9 @@ func (sc *DashCoreSignerClient) signVoteExtensions( protoVote.VoteExtensions[i].Signature = resp.sign } + + sc.logger.Trace("vote extensions signed", "extensions", protoVote.VoteExtensions) + return nil } @@ -401,16 +406,16 @@ func (sc *DashCoreSignerClient) quorumSignAndVerify( sc.logger.Trace("quorum sign result", "sign", hex.EncodeToString(qs.sign), "sign_hash", hex.EncodeToString(qs.signHash), - "req_id", hex.EncodeToString(signItem.ReqID), - "id", hex.EncodeToString(signItem.ID), + "req_id", hex.EncodeToString(signItem.ID), + "id", hex.EncodeToString(signItem.SignHash), "raw", hex.EncodeToString(signItem.Raw), - "hash", hex.EncodeToString(signItem.Hash), + "hash", hex.EncodeToString(signItem.RawHash), "quorum_sign_result", *qs.QuorumSignResult) pubKey, err := sc.GetPubKey(ctx, quorumHash) if err != nil { return nil, &RemoteSignerError{Code: 500, Description: err.Error()} } - verified := pubKey.VerifySignatureDigest(signItem.ID, qs.sign) + verified := pubKey.VerifySignatureDigest(signItem.SignHash, qs.sign) if !verified { return nil, fmt.Errorf("unable to verify signature with pubkey %s", pubKey.String()) } @@ -422,7 +427,7 @@ func (sc *DashCoreSignerClient) quorumSign( quorumHash crypto.QuorumHash, signItem crypto.SignItem, ) (*quorumSignResult, error) { - resp, err := sc.dashCoreRPCClient.QuorumSign(quorumType, signItem.ReqID, signItem.Hash, quorumHash) + resp, err := sc.dashCoreRPCClient.QuorumSign(quorumType, signItem.ID, signItem.RawHash, quorumHash) if err != nil { return nil, &RemoteSignerError{Code: 500, Description: "cannot sign vote: " + err.Error()} } diff --git a/privval/file.go b/privval/file.go index 8023d439d3..9131e53f9b 100644 --- a/privval/file.go +++ b/privval/file.go @@ -686,10 +686,10 @@ func (pv *FilePV) signVote( // application may have created a different extension. We therefore always // re-sign the vote extensions of precommits. For prevotes, the extension // signature will always be empty. - extSigns := make([]tmbytes.HexBytes, 0, len(quorumSigns.ThresholdVoteExtensions)) + extSigns := make([]tmbytes.HexBytes, 0, len(quorumSigns.VoteExtensionSignItems)) if vote.Type == tmproto.PrecommitType { - for _, signItem := range quorumSigns.ThresholdVoteExtensions { - extSig, err := privKey.SignDigest(signItem.ID) + for _, signItem := range quorumSigns.VoteExtensionSignItems { + extSig, err := privKey.SignDigest(signItem.SignHash) if err != nil { return err } @@ -714,7 +714,7 @@ func (pv *FilePV) signVote( return nil } - sigBlock, err := privKey.SignDigest(quorumSigns.Block.ID) + sigBlock, err := privKey.SignDigest(quorumSigns.Block.SignHash) if err != nil { return err } diff --git a/privval/file_test.go b/privval/file_test.go index 2155e012a9..ef51f62482 100644 --- a/privval/file_test.go +++ b/privval/file_test.go @@ -374,7 +374,7 @@ func TestVoteExtensionsAreAlwaysSigned(t *testing.T) { extSignItem1, err := types.VoteExtensionsFromProto(vpb1.VoteExtensions...).SignItems(chainID, quorumType, quorumHash, vpb1.Height, vpb1.Round) require.NoError(t, err) - assert.True(t, pubKey.VerifySignatureDigest(extSignItem1[0].ID, vpb1.VoteExtensions[0].Signature)) + assert.True(t, pubKey.VerifySignatureDigest(extSignItem1[0].SignHash, vpb1.VoteExtensions[0].Signature)) // We duplicate this vote precisely, including its timestamp, but change // its extension @@ -394,8 +394,8 @@ func TestVoteExtensionsAreAlwaysSigned(t *testing.T) { // with the old extension. extSignItem2, err := types.VoteExtensionsFromProto(vpb2.VoteExtensions...).SignItems(chainID, quorumType, quorumHash, vpb2.Height, vpb2.Round) require.NoError(t, err) - assert.True(t, pubKey.VerifySignatureDigest(extSignItem2[0].ID, vpb2.VoteExtensions[0].Signature)) - assert.False(t, pubKey.VerifySignatureDigest(extSignItem1[0].ID, vpb2.VoteExtensions[0].Signature)) + assert.True(t, pubKey.VerifySignatureDigest(extSignItem2[0].SignHash, vpb2.VoteExtensions[0].Signature)) + assert.False(t, pubKey.VerifySignatureDigest(extSignItem1[0].SignHash, vpb2.VoteExtensions[0].Signature)) vpb2.BlockSignature = nil vpb2.VoteExtensions[0].Signature = nil @@ -405,8 +405,8 @@ func TestVoteExtensionsAreAlwaysSigned(t *testing.T) { extSignItem3, err := types.VoteExtensionsFromProto(vpb2.VoteExtensions...).SignItems(chainID, quorumType, quorumHash, vpb2.Height, vpb2.Round) require.NoError(t, err) - assert.True(t, pubKey.VerifySignatureDigest(extSignItem3[0].ID, vpb2.VoteExtensions[0].Signature)) - assert.False(t, pubKey.VerifySignatureDigest(extSignItem1[0].ID, vpb2.VoteExtensions[0].Signature)) + assert.True(t, pubKey.VerifySignatureDigest(extSignItem3[0].SignHash, vpb2.VoteExtensions[0].Signature)) + assert.False(t, pubKey.VerifySignatureDigest(extSignItem1[0].SignHash, vpb2.VoteExtensions[0].Signature)) } func newVote(proTxHash types.ProTxHash, idx int32, height int64, round int32, diff --git a/test/e2e/pkg/mockcoreserver/core_server.go b/test/e2e/pkg/mockcoreserver/core_server.go index 183929f228..71a85805c8 100644 --- a/test/e2e/pkg/mockcoreserver/core_server.go +++ b/test/e2e/pkg/mockcoreserver/core_server.go @@ -92,7 +92,7 @@ func (c *MockCoreServer) QuorumSign(ctx context.Context, cmd btcjson.QuorumCmd) panic(err) } quorumHash := crypto.QuorumHash(quorumHashBytes) - signID := crypto.NewSignItemFromHash(*cmd.LLMQType, quorumHash, reqID, msgHash).ID + signID := crypto.NewSignItemFromHash(*cmd.LLMQType, quorumHash, reqID, msgHash).SignHash privateKey, err := c.FilePV.GetPrivateKey(ctx, quorumHash) if err != nil { @@ -136,7 +136,7 @@ func (c *MockCoreServer) QuorumVerify(ctx context.Context, cmd btcjson.QuorumCmd if err != nil { panic(err) } - signID := crypto.NewSignItemFromHash(*cmd.LLMQType, quorumHash, reqID, msgHash).ID + signID := crypto.NewSignItemFromHash(*cmd.LLMQType, quorumHash, reqID, msgHash).SignHash thresholdPublicKey, err := c.FilePV.GetThresholdPublicKey(ctx, quorumHash) if err != nil { diff --git a/types/block.go b/types/block.go index 05670545ec..4d98c855f7 100644 --- a/types/block.go +++ b/types/block.go @@ -746,12 +746,17 @@ type Commit struct { } // NewCommit returns a new Commit. -func NewCommit(height int64, round int32, blockID BlockID, commitSigns *CommitSigns) *Commit { +func NewCommit(height int64, round int32, blockID BlockID, voteExtensions VoteExtensions, commitSigns *CommitSigns) *Commit { commit := &Commit{ Height: height, Round: round, BlockID: blockID, + ThresholdVoteExtensions: voteExtensions.Filter(func(ext VoteExtensionIf) bool { + _, ok := ext.(ThresholdVoteExtensionIf) + return ok + }).ToProto(), } + if commitSigns != nil { commitSigns.CopyToCommit(commit) } diff --git a/types/block_test.go b/types/block_test.go index d770b32179..743237f491 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -117,7 +117,7 @@ func TestBlockValidateBasic(t *testing.T) { blk.LastCommit = nil }, true}, {"Invalid LastCommit", func(blk *Block) { - blk.LastCommit = NewCommit(-1, 0, *voteSet.maj23, nil) + blk.LastCommit = NewCommit(-1, 0, *voteSet.maj23, nil, nil) }, true}, {"Invalid Evidence", func(blk *Block) { emptyEv := &DuplicateVoteEvidence{} diff --git a/types/evidence_test.go b/types/evidence_test.go index 9fb19a84e9..7b6c007078 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -302,7 +302,7 @@ func TestEvidenceVectors(t *testing.T) { }{ {"duplicateVoteEvidence", EvidenceList{&DuplicateVoteEvidence{VoteA: v2, VoteB: v}}, - "54b4c93161a227c5387bd5da81b533c399097877217d08d1f579038a9c527775", + "c031e2c89a40678572c2353a302d7823b968e0470384471481e0aadd95e4f8c0", }, } diff --git a/types/priv_validator.go b/types/priv_validator.go index 96695343d4..39c84acf76 100644 --- a/types/priv_validator.go +++ b/types/priv_validator.go @@ -288,7 +288,7 @@ func (pv *MockPV) SignVote( } for i, sign := range signItems { - sig, err := privKey.SignDigest(sign.ID) + sig, err := privKey.SignDigest(sign.SignHash) if err != nil { return err } diff --git a/types/proposal.go b/types/proposal.go index 04c4fe26c7..ca7814fc0e 100644 --- a/types/proposal.go +++ b/types/proposal.go @@ -182,7 +182,7 @@ func ProposalBlockSignID( proposalRequestID := ProposalRequestIDProto(p) - signID := crypto.NewSignItemFromHash(quorumType, quorumHash, proposalRequestID, proposalMessageHash[:]).ID + signID := crypto.NewSignItemFromHash(quorumType, quorumHash, proposalRequestID, proposalMessageHash[:]).SignHash return signID } diff --git a/types/quorum.go b/types/quorum.go index 2ea285798f..a24f7a3e01 100644 --- a/types/quorum.go +++ b/types/quorum.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "fmt" "github.com/dashpay/tenderdash/crypto" @@ -14,26 +15,40 @@ type CommitSigns struct { } // CopyToCommit copies threshold signature to commit +// +// commit.ThresholdVoteExtensions must be initialized func (c *CommitSigns) CopyToCommit(commit *Commit) { commit.QuorumHash = c.QuorumHash commit.ThresholdBlockSignature = c.BlockSign - commit.ThresholdVoteExtensions = c.ThresholdVoteExtensions.ToProto() + if len(c.VoteExtensionSignatures) != len(commit.ThresholdVoteExtensions) { + panic(fmt.Sprintf("count of threshold vote extension signatures (%d) doesn't match vote extensions in commit (%d)", + len(commit.ThresholdVoteExtensions), len(c.VoteExtensionSignatures), + )) + } + for i, ext := range c.VoteExtensionSignatures { + commit.ThresholdVoteExtensions[i].Signature = bytes.Clone(ext) + } } // QuorumSigns holds all created signatures, block, state and for each recovered vote-extensions type QuorumSigns struct { BlockSign []byte - // Signed vote extensions - ThresholdVoteExtensions VoteExtensions + // List of vote extensions signatures. Order matters. + VoteExtensionSignatures [][]byte } // NewQuorumSignsFromCommit creates and returns QuorumSigns using threshold signatures from a commit. // // Note it only uses threshold-revoverable vote extension signatures, as non-threshold signatures are not included in the commit func NewQuorumSignsFromCommit(commit *Commit) QuorumSigns { + sigs := make([][]byte, 0, len(commit.ThresholdVoteExtensions)) + for _, ext := range commit.ThresholdVoteExtensions { + sigs = append(sigs, ext.Signature) + } + return QuorumSigns{ BlockSign: commit.ThresholdBlockSignature, - ThresholdVoteExtensions: VoteExtensionsFromProto(commit.ThresholdVoteExtensions...), + VoteExtensionSignatures: sigs, } } @@ -102,11 +117,11 @@ func (q *QuorumSingsVerifier) verifyBlock(pubKey crypto.PubKey, signs QuorumSign if !q.shouldVerifyBlock { return nil } - if !pubKey.VerifySignatureDigest(q.Block.ID, signs.BlockSign) { + if !pubKey.VerifySignatureDigest(q.Block.SignHash, signs.BlockSign) { return fmt.Errorf( "threshold block signature is invalid: (%X) signID=%X: %w", q.Block.Raw, - q.Block.ID, + q.Block.SignHash, ErrVoteInvalidBlockSignature, ) } @@ -122,20 +137,20 @@ func (q *QuorumSingsVerifier) verifyVoteExtensions( return nil } - thresholdSigs := signs.ThresholdVoteExtensions.GetSignatures() - signItems := q.ThresholdVoteExtensions + thresholdSigs := signs.VoteExtensionSignatures + signItems := q.VoteExtensionSignItems if len(signItems) == 0 { return nil } if len(signItems) != len(thresholdSigs) { - return fmt.Errorf("count of threshold vote extension signatures (%d) doesn't match with recoverable vote extensions (%d)", + return fmt.Errorf("count of threshold vote extension signatures (%d) doesn't match recoverable vote extensions (%d)", len(thresholdSigs), len(signItems), ) } for i, sig := range thresholdSigs { - if !pubKey.VerifySignatureDigest(signItems[i].ID, sig) { - return fmt.Errorf("vote-extension %d signature is invalid: raw %X, signatrure %X", i, + if !pubKey.VerifySignatureDigest(signItems[i].SignHash, sig) { + return fmt.Errorf("vote-extension %d signature is invalid: raw %X, signature %X", i, signItems[i].Raw, sig) } } diff --git a/types/quorum_sign_data.go b/types/quorum_sign_data.go index 737aa65b4b..65267bc35b 100644 --- a/types/quorum_sign_data.go +++ b/types/quorum_sign_data.go @@ -11,8 +11,30 @@ import ( // QuorumSignData holds data which is necessary for signing and verification block, state, and each vote-extension in a list type QuorumSignData struct { - Block crypto.SignItem - ThresholdVoteExtensions []crypto.SignItem + Block crypto.SignItem + VoteExtensionSignItems []crypto.SignItem +} + +// Signs items inside QuorumSignData using a given private key. +// +// Mainly for testing. +func (q QuorumSignData) SignWithPrivkey(key crypto.PrivKey) (QuorumSigns, error) { + var err error + var signs QuorumSigns + if signs.BlockSign, err = key.SignDigest(q.Block.SignHash); err != nil { + return signs, err + } + + signs.VoteExtensionSignatures = make([][]byte, 0, len(q.VoteExtensionSignItems)) + for _, item := range q.VoteExtensionSignItems { + var sign []byte + if sign, err = key.SignDigest(item.SignHash); err != nil { + return signs, err + } + signs.VoteExtensionSignatures = append(signs.VoteExtensionSignatures, sign) + } + + return signs, nil } // Verify verifies a quorum signatures: block, state and vote-extensions @@ -42,7 +64,7 @@ func MakeQuorumSigns( Block: MakeBlockSignItem(chainID, protoVote, quorumType, quorumHash), } var err error - quorumSign.ThresholdVoteExtensions, err = + quorumSign.VoteExtensionSignItems, err = VoteExtensionsFromProto(protoVote.VoteExtensions...). Filter(func(ext VoteExtensionIf) bool { return ext.IsThresholdRecoverable() diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index 1609e58138..799ea339d0 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -41,7 +41,7 @@ func TestMakeBlockSignID(t *testing.T) { quorumHash: tmbytes.MustHexDecode("6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD"), want: newSignItem( "C8F2E1FE35DE03AC94F76191F59CAD1BA1F7A3C63742B7125990D996315001CC", - "C2CB4650EFA1179482AF85591E0C065563BD9EBBAF588ACD3BD3F5EBDD997DD6", + "2E8CEF1D36C4655225BE7CC6EE8169C80C9D1D0BF336D7B547DF1D7846B725DA", "02000000E9030000000000000000000000000000E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B"+ "7852B855E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855646173682D706C6174666F726D", "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", @@ -53,9 +53,9 @@ func TestMakeBlockSignID(t *testing.T) { for i, tc := range testCases { t.Run(fmt.Sprintf("test-case %d", i), func(t *testing.T) { signItem := MakeBlockSignItem(chainID, tc.vote.ToProto(), quorumType, tc.quorumHash) - t.Logf("hash %X id %X raw %X reqID %X", signItem.Hash, signItem.ID, signItem.Raw, signItem.ReqID) - require.Equal(t, tc.want, signItem, "Got ID: %X", signItem.ID) - require.Equal(t, tc.wantHash, signItem.Hash) + t.Logf("hash %X id %X raw %X reqID %X", signItem.RawHash, signItem.SignHash, signItem.Raw, signItem.ID) + require.Equal(t, tc.want, signItem, "Got ID: %X", signItem.SignHash) + require.Equal(t, tc.wantHash, signItem.RawHash) }) } } @@ -115,8 +115,8 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { require.NoError(t, err) for i, sign := range signItems { - assert.Equal(t, tc.wantHash[i], sign.Hash, "want %X, actual %X", tc.wantHash[i], sign.Hash) - if !assert.Equal(t, tc.want[i], sign, "Got ID(%d): %X", i, sign.ID) { + assert.Equal(t, tc.wantHash[i], sign.RawHash, "want %X, actual %X", tc.wantHash[i], sign.RawHash) + if !assert.Equal(t, tc.want[i], sign, "Got ID(%d): %X", i, sign.SignHash) { logger.Error("invalid sign", "sign", sign, "i", i) } } @@ -164,7 +164,7 @@ func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { item, err := ve.SignItem(chainID, 1, 0, llmqType, quorumHash) assert.NoError(t, err) - actual := item.ID + actual := item.SignHash t.Logf("LLMQ type: %s (%d)\n", llmqType.Name(), llmqType) t.Logf("extension: %X\n", extension) @@ -176,8 +176,8 @@ func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { } -func newSignItem(reqID, ID, raw, quorumHash string, quorumType btcjson.LLMQType) crypto.SignItem { +func newSignItem(reqID, signHash, raw, quorumHash string, quorumType btcjson.LLMQType) crypto.SignItem { item := crypto.NewSignItem(quorumType, tmbytes.MustHexDecode(quorumHash), tmbytes.MustHexDecode(reqID), tmbytes.MustHexDecode(raw)) - item.ID = tmbytes.MustHexDecode(ID) + item.SignHash = tmbytes.MustHexDecode(signHash) return item } diff --git a/types/signs_recoverer.go b/types/signs_recoverer.go index d99bbf5de0..ec8db95476 100644 --- a/types/signs_recoverer.go +++ b/types/signs_recoverer.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/dashpay/tenderdash/crypto/bls12381" + "github.com/dashpay/tenderdash/proto/tendermint/types" ) // SignsRecoverer is used to recover threshold block, state, and vote-extension signatures @@ -12,10 +13,11 @@ type SignsRecoverer struct { blockSigs [][]byte stateSigs [][]byte validatorProTxHashes [][]byte - // List of all threshold-recovered vote extensions, indexed by vote extension number - voteThresholdExts VoteExtensions - // voteThresholdExtensionSigs is a list of signatures for each threshold-recovered vote-extension, indexed by vote extension number - voteThresholdExtensionSigs [][][]byte + // List of all vote extensions. Order matters. + voteExtensions VoteExtensions + + // true when the recovery of vote extensions was already executed + voteExtensionsRecovered bool quorumReached bool } @@ -56,11 +58,32 @@ func (v *SignsRecoverer) Recover() (*QuorumSigns, error) { return thresholdSigns, nil } +// Helper function that returns deep copy of recovered vote extensions with signatures from QuorumSigns. +// +// Note that this method doesn't recover threshold signatures. +// It requires to call Recover() method first. +// +// ## Panics +// +// Panics when the count of threshold vote extension signatures in QuorumSigns doesn't match recoverable vote extensions +func (v *SignsRecoverer) GetVoteExtensions(qs QuorumSigns) VoteExtensions { + if len(qs.VoteExtensionSignatures) != len(v.voteExtensions) { + panic(fmt.Sprintf("count of threshold vote extension signatures (%d) doesn't match recoverable vote extensions (%d)", + len(qs.VoteExtensionSignatures), len(v.voteExtensions))) + } + exts := v.voteExtensions.Copy() + for i, ext := range exts { + ext.SetSignature(qs.VoteExtensionSignatures[i]) + } + + return exts +} + func (v *SignsRecoverer) init(votes []*Vote) { v.blockSigs = nil v.stateSigs = nil v.validatorProTxHashes = nil - v.voteThresholdExtensionSigs = nil + for _, vote := range votes { v.addVoteSigs(vote) } @@ -70,31 +93,39 @@ func (v *SignsRecoverer) addVoteSigs(vote *Vote) { if vote == nil { return } + v.blockSigs = append(v.blockSigs, vote.BlockSignature) v.validatorProTxHashes = append(v.validatorProTxHashes, vote.ValidatorProTxHash) - v.addVoteExtensionSigs(vote.VoteExtensions) + v.addVoteExtensionSigs(vote) } // Add threshold-recovered vote extensions -func (v *SignsRecoverer) addVoteExtensionSigs(voteExtensions VoteExtensions) { - // Skip non-threshold vote-extensions - thresholdExtensions := voteExtensions.Filter(func(ext VoteExtensionIf) bool { - return ext.IsThresholdRecoverable() - }) - // initialize vote extensions if it's empty - if len(v.voteThresholdExts) == 0 && !thresholdExtensions.IsEmpty() { - v.voteThresholdExts = thresholdExtensions.Copy() - v.voteThresholdExtensionSigs = make([][][]byte, len(thresholdExtensions)) +func (v *SignsRecoverer) addVoteExtensionSigs(vote *Vote) { + if len(vote.VoteExtensions) == 0 { + return + } + + // initialize vote extensions + if v.voteExtensions.IsEmpty() { + v.voteExtensions = vote.VoteExtensions.Copy() } // sanity check; this should be detected on higher layers - if len(v.voteThresholdExts) != len(thresholdExtensions) { - panic(fmt.Sprintf("received vote extensions with different length: current %d, new %d", len(v.voteThresholdExts), len(thresholdExtensions))) + if vote.Type != types.PrecommitType || vote.BlockID.IsNil() { + panic(fmt.Sprintf("only non-nil precommits can have vote extensions, got: %s", vote.String())) + } + + if len(vote.VoteExtensions) != len(v.voteExtensions) { + panic(fmt.Sprintf("received vote extensions with different length: current %d, new %d", len(v.voteExtensions), len(v.voteExtensions))) } // append signatures from this vote to each extension - for i, ext := range thresholdExtensions { - v.voteThresholdExtensionSigs[i] = append(v.voteThresholdExtensionSigs[i], ext.GetSignature()) + for i, ext := range vote.VoteExtensions { + if recoverable, ok := (v.voteExtensions[i]).(ThresholdVoteExtensionIf); ok { + if err := recoverable.AddThresholdSignature(vote.ValidatorProTxHash, ext.GetSignature()); err != nil { + panic(fmt.Errorf("failed to add vote %s to recover vote extension threshold sig: %w", vote.String(), err)) + } + } } } @@ -113,40 +144,26 @@ func (v *SignsRecoverer) recoverVoteExtensionSigs(quorumSigs *QuorumSigns) error return nil } - // initialize threshold vote extensions with empty signatures - quorumSigs.ThresholdVoteExtensions = v.voteThresholdExts.Filter(func(ext VoteExtensionIf) bool { return ext.IsThresholdRecoverable() }).Copy() - for i := range quorumSigs.ThresholdVoteExtensions { - quorumSigs.ThresholdVoteExtensions[i].SetSignature(nil) - } - - // for each vote extension, if it's threshold-recoverable, recover its signature - thresholdExtIndex := 0 - for extIndex, extension := range quorumSigs.ThresholdVoteExtensions { - if extension.IsThresholdRecoverable() { - extensionSignatures := v.voteThresholdExtensionSigs[thresholdExtIndex] - thresholdExtIndex++ - - if len(extensionSignatures) > 0 { - // as some nodes might have voted nil, we will have empty sigs from them; - // we need to filter them out before threshold-recovering - sigs := make([][]byte, 0, len(extensionSignatures)) - proTxHashes := make([][]byte, 0, len(extensionSignatures)) - for i, sig := range extensionSignatures { - if len(sig) > 0 { - sigs = append(sigs, sig) - proTxHashes = append(proTxHashes, v.validatorProTxHashes[i]) - } - } - thresholdSignature, err := bls12381.RecoverThresholdSignatureFromShares(sigs, proTxHashes) - if err != nil { - return fmt.Errorf("error recovering vote-extension %d threshold signature: %w", extIndex, err) - } - quorumSigs.ThresholdVoteExtensions[extIndex].SetSignature(thresholdSignature) - } else { - return fmt.Errorf("vote extension %d does not have any signatures for threshold-recovering", extIndex) + if quorumSigs.VoteExtensionSignatures == nil { + quorumSigs.VoteExtensionSignatures = make([][]byte, len(v.voteExtensions)) + } + + if len(v.voteExtensions) != len(quorumSigs.VoteExtensionSignatures) { + return fmt.Errorf("count of threshold vote extension signatures (%d) doesn't match recoverable vote extensions (%d)", + len(quorumSigs.VoteExtensionSignatures), len(v.voteExtensions)) + } + + for i, ext := range v.voteExtensions { + if extension, ok := ext.(ThresholdVoteExtensionIf); ok { + sig, err := extension.ThresholdRecover() + if err != nil { + return fmt.Errorf("error recovering threshold signature for vote extension %d: %w", i, err) } + quorumSigs.VoteExtensionSignatures[i] = sig } } + v.voteExtensionsRecovered = true + return nil } diff --git a/types/validation_test.go b/types/validation_test.go index 88fb57cff4..9d1224c0e9 100644 --- a/types/validation_test.go +++ b/types/validation_test.go @@ -31,21 +31,24 @@ func TestValidatorSet_VerifyCommit_All(t *testing.T) { vote.ValidatorProTxHash = proTxHash v := vote.ToProto() - quorumSigns, err := MakeQuorumSigns(chainID, btcjson.LLMQType_5_60, quorumHash, v) + dataToSign, err := MakeQuorumSigns(chainID, btcjson.LLMQType_5_60, quorumHash, v) require.NoError(t, err) - blockSig, err := privKey.SignDigest(quorumSigns.Block.ID) + sig, err := dataToSign.SignWithPrivkey(privKey) + require.NoError(t, err) + + vote.BlockSignature = sig.BlockSign + err = vote.VoteExtensions.SetSignatures(sig.VoteExtensionSignatures) require.NoError(t, err) - vote.BlockSignature = blockSig commit := NewCommit(vote.Height, vote.Round, vote.BlockID, + vote.VoteExtensions, + &CommitSigns{ - QuorumSigns: QuorumSigns{ - BlockSign: blockSig, - }, - QuorumHash: quorumHash, + QuorumSigns: sig, + QuorumHash: quorumHash, }, ) @@ -83,13 +86,20 @@ func TestValidatorSet_VerifyCommit_All(t *testing.T) { {"wrong height", chainID, vote.BlockID, vote.Height - 1, commit, true}, {"threshold block signature is invalid", chainID, vote.BlockID, vote.Height, - NewCommit(vote.Height, vote.Round, vote.BlockID, &CommitSigns{QuorumHash: quorumHash}), true}, + NewCommit(vote.Height, vote.Round, vote.BlockID, vote.VoteExtensions, + &CommitSigns{ + QuorumHash: quorumHash, + QuorumSigns: QuorumSigns{ + BlockSign: []byte("invalid block signature"), + VoteExtensionSignatures: sig.VoteExtensionSignatures, + }}), true}, {"threshold block signature is invalid", chainID, vote.BlockID, vote.Height, NewCommit(vote.Height, vote.Round, vote.BlockID, + vote.VoteExtensions, &CommitSigns{ QuorumHash: quorumHash, - QuorumSigns: QuorumSigns{BlockSign: vote2.BlockSignature}, + QuorumSigns: QuorumSigns{BlockSign: vote2.BlockSignature, VoteExtensionSignatures: vote2.VoteExtensions.GetSignatures()}, }, ), true}, } @@ -136,11 +146,16 @@ func TestValidatorSet_VerifyCommit_CheckThresholdSignatures(t *testing.T) { assert.Contains(t, err.Error(), "threshold block signature is invalid") } + goodVote := voteSet.GetByIndex(0) recoverer := NewSignsRecoverer(voteSet.votes) thresholdSigns, err := recoverer.Recover() require.NoError(t, err) commit.ThresholdBlockSignature = thresholdSigns.BlockSign - commit.ThresholdVoteExtensions = thresholdSigns.ThresholdVoteExtensions.ToProto() + exts := goodVote.VoteExtensions.Copy() + for i, ext := range exts { + ext.SetSignature(thresholdSigns.VoteExtensionSignatures[i]) + } + commit.ThresholdVoteExtensions = exts.ToProto() err = valSet.VerifyCommit(chainID, blockID, h, commit) require.NoError(t, err) } diff --git a/types/vote.go b/types/vote.go index f2ba83fb73..371bef640a 100644 --- a/types/vote.go +++ b/types/vote.go @@ -109,7 +109,7 @@ func VoteFromProto(pv *tmproto.Vote) (*Vote, error) { // VoteBlockSignID returns signID that should be signed for the block func VoteBlockSignID(chainID string, vote *tmproto.Vote, quorumType btcjson.LLMQType, quorumHash []byte) []byte { signID := MakeBlockSignItem(chainID, vote, quorumType, quorumHash) - return signID.ID + return signID.SignHash } // Copy creates a deep copy of the vote @@ -258,9 +258,9 @@ func (vote *Vote) verifySign( func (vote *Vote) makeQuorumSigns() QuorumSigns { return QuorumSigns{ BlockSign: vote.BlockSignature, - ThresholdVoteExtensions: vote.VoteExtensions.Filter(func(ext VoteExtensionIf) bool { + VoteExtensionSignatures: vote.VoteExtensions.Filter(func(ext VoteExtensionIf) bool { return ext.IsThresholdRecoverable() - }).Copy(), + }).GetSignatures(), } } diff --git a/types/vote_extension.go b/types/vote_extension.go index 3c6938cb94..31a976d26e 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -10,6 +10,7 @@ import ( "github.com/dashpay/dashd-go/btcjson" abci "github.com/dashpay/tenderdash/abci/types" "github.com/dashpay/tenderdash/crypto" + "github.com/dashpay/tenderdash/crypto/bls12381" "github.com/dashpay/tenderdash/internal/libs/protoio" tmbytes "github.com/dashpay/tenderdash/libs/bytes" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" @@ -193,7 +194,7 @@ func VoteExtensionsFromProto(pve ...*tmproto.VoteExtension) VoteExtensions { // Copy creates a deep copy of VoteExtensions func (e VoteExtensions) Copy() VoteExtensions { - if e.IsEmpty() { + if e == nil || e.IsEmpty() { return nil } @@ -223,6 +224,7 @@ func (e VoteExtensions) CopySignsFromProto(src tmproto.VoteExtensions) error { if len(e) != len(src) { return errUnableCopySigns } + for i, ext := range e { ext.SetSignature(src[i].Signature) } @@ -230,6 +232,18 @@ func (e VoteExtensions) CopySignsFromProto(src tmproto.VoteExtensions) error { return nil } +func (e VoteExtensions) SetSignatures(src [][]byte) error { + if len(e) != len(src) { + return errUnableCopySigns + } + + for i, ext := range e { + ext.SetSignature(src[i]) + } + + return nil +} + // CopySignsToProto copies the signatures from the current VoteExtensions into VoteExtension's protobuf func (e VoteExtensions) CopySignsToProto(dest tmproto.VoteExtensions) error { if len(e) != len(dest) { @@ -272,19 +286,35 @@ type VoteExtensionIf interface { zerolog.LogObjectMarshaler } +type ThresholdVoteExtensionIf interface { + VoteExtensionIf + + AddThresholdSignature(validator ProTxHash, sig []byte) error + // Recover threshold signature from collected signatures + // + // Returns recovered signature or error. VoteExtension, including any signature already set, is not modified. + ThresholdRecover() ([]byte, error) +} + func VoteExtensionFromProto(ve tmproto.VoteExtension) VoteExtensionIf { switch ve.Type { case tmproto.VoteExtensionType_DEFAULT: return &GenericVoteExtension{VoteExtension: ve} case tmproto.VoteExtensionType_THRESHOLD_RECOVER: - return &ThresholdVoteExtension{GenericVoteExtension: GenericVoteExtension{VoteExtension: ve}} + ext := newThresholdVoteExtension(ve) + return &ext case tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW: - return &ThresholdRawVoteExtension{GenericVoteExtension: GenericVoteExtension{VoteExtension: ve}} + ext := newThresholdVoteExtension(ve) + return &ThresholdRawVoteExtension{ThresholdVoteExtension: ext} default: panic(fmt.Errorf("unknown vote extension type: %s", ve.Type.String())) } } +func newThresholdVoteExtension(ve tmproto.VoteExtension) ThresholdVoteExtension { + return ThresholdVoteExtension{GenericVoteExtension: GenericVoteExtension{VoteExtension: ve}} +} + // VOTE EXTENSION TYPES // GenericVoteExtension is a default type of VoteExtension @@ -332,9 +362,13 @@ func (e GenericVoteExtension) GetSignRequestId() []byte { return id.SignRequestId } +type ThresholdSignature [bls12381.SignatureSize]byte + // ThresholdVoteExtension is a threshold type of VoteExtension type ThresholdVoteExtension struct { GenericVoteExtension + // threshold signatures for this vote extension, collected from validators + thresholdSignatures map[[crypto.ProTxHashSize]byte]ThresholdSignature } func (e ThresholdVoteExtension) Copy() VoteExtensionIf { @@ -348,23 +382,57 @@ func (e ThresholdVoteExtension) IsThresholdRecoverable() bool { return true } +func (e *ThresholdVoteExtension) AddThresholdSignature(validator ProTxHash, sig []byte) error { + if e.thresholdSignatures == nil { + e.thresholdSignatures = make(map[[crypto.ProTxHashSize]byte]ThresholdSignature) + } + + proTxHash := [crypto.ProTxHashSize]byte(validator) + e.thresholdSignatures[proTxHash] = ThresholdSignature(sig) + + return nil +} + +func (e *ThresholdVoteExtension) ThresholdRecover() ([]byte, error) { + proTxHashes := make([][]byte, 0, len(e.thresholdSignatures)) + signatures := make([][]byte, 0, len(e.thresholdSignatures)) + + // collect signatures and proTxHashes + for proTxHash, signature := range e.thresholdSignatures { + if len(signature) != bls12381.SignatureSize { + return nil, fmt.Errorf("invalid vote extension signature from validator %s: got %d, expected %d", + proTxHash, len(signature), bls12381.SignatureSize) + } + + proTxHashes = append(proTxHashes, bytes.Clone(proTxHash[:])) + signatures = append(signatures, bytes.Clone(signature[:])) + } + + if len(signatures) > 0 { + thresholdSignature, err := bls12381.RecoverThresholdSignatureFromShares(signatures, proTxHashes) + if err != nil { + return nil, fmt.Errorf("error recovering vote extension %s %X threshold signature: %w", + e.GetType().String(), e.GetExtension(), err) + } + + return thresholdSignature, nil + } + + return nil, fmt.Errorf("vote extension %s of type %X does not have any signatures for threshold-recovering", + e.GetType().String(), e.GetExtension()) +} + // ThresholdRawVoteExtension is a threshold raw type of VoteExtension type ThresholdRawVoteExtension struct { - GenericVoteExtension - ThresholdSignature []byte + ThresholdVoteExtension } func (e ThresholdRawVoteExtension) Copy() VoteExtensionIf { - return &ThresholdRawVoteExtension{GenericVoteExtension: GenericVoteExtension{ - VoteExtension: e.VoteExtension.Copy(), - }} -} - -func (e ThresholdRawVoteExtension) IsThresholdRecoverable() bool { - return true + inner := e.ThresholdVoteExtension.Copy().(*ThresholdVoteExtension) + return &ThresholdRawVoteExtension{ThresholdVoteExtension: *inner} } -func (e ThresholdRawVoteExtension) SignItem(chainID string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) { +func (e ThresholdRawVoteExtension) SignItem(_ string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) { var signRequestID []byte var err error @@ -386,6 +454,8 @@ func (e ThresholdRawVoteExtension) SignItem(chainID string, height int64, round if err != nil { return crypto.SignItem{}, err } + // we do not reverse fields when calculating SignHash for vote extensions + // signItem.UpdateSignHash(false) signItem.Raw = ext.Extension return signItem, nil @@ -421,5 +491,8 @@ func signItem(ext *tmproto.VoteExtension, chainID string, height int64, round in return crypto.SignItem{}, err } signBytes := voteExtensionSignBytes(chainID, height, round, ext) - return crypto.NewSignItem(quorumType, quorumHash, requestID, signBytes), nil + si := crypto.NewSignItem(quorumType, quorumHash, requestID, signBytes) + // we do not reverse fields when calculating SignHash for vote extensions + // si.UpdateSignHash(false) + return si, nil } diff --git a/types/vote_set.go b/types/vote_set.go index 7e73c05105..b80ce203aa 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -376,8 +376,9 @@ func (voteSet *VoteSet) recoverThresholdSigns(blockVotes *blockVotes) error { if err != nil { return err } + voteSet.thresholdBlockSig = thresholdSigns.BlockSign - voteSet.thresholdVoteExtSigs = thresholdSigns.ThresholdVoteExtensions + voteSet.thresholdVoteExtSigs = signsRecoverer.GetVoteExtensions(*thresholdSigns) return nil } @@ -735,6 +736,7 @@ func (voteSet *VoteSet) MakeCommit() *Commit { voteSet.GetHeight(), voteSet.GetRound(), *voteSet.maj23, + voteSet.thresholdVoteExtSigs, voteSet.makeCommitSigns(), ) } @@ -743,7 +745,7 @@ func (voteSet *VoteSet) makeCommitSigns() *CommitSigns { return &CommitSigns{ QuorumSigns: QuorumSigns{ BlockSign: voteSet.thresholdBlockSig, - ThresholdVoteExtensions: voteSet.thresholdVoteExtSigs, + VoteExtensionSignatures: voteSet.thresholdVoteExtSigs.GetSignatures(), }, QuorumHash: voteSet.valSet.QuorumHash, } @@ -752,7 +754,7 @@ func (voteSet *VoteSet) makeCommitSigns() *CommitSigns { func (voteSet *VoteSet) makeQuorumSigns() QuorumSigns { return QuorumSigns{ BlockSign: voteSet.thresholdBlockSig, - ThresholdVoteExtensions: voteSet.thresholdVoteExtSigs, + VoteExtensionSignatures: voteSet.thresholdVoteExtSigs.GetSignatures(), } } From 12884fd7261c707d6c7e07c0e408f7bce70f3883 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 21 Dec 2023 21:29:21 +0100 Subject: [PATCH 27/55] chore: don't reverse signhash --- crypto/quorum.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/crypto/quorum.go b/crypto/quorum.go index 6d6c0d95a1..e6447fdad4 100644 --- a/crypto/quorum.go +++ b/crypto/quorum.go @@ -121,9 +121,6 @@ func (i *SignItem) UpdateSignHash(reverse bool) { signHash := make([]byte, 32) copy(signHash, blsSignHash[:]) - if reverse { - signHash = tmbytes.Reverse(signHash) - } i.SignHash = signHash } From 658131ace181d00312f8c1e9eaf4bbcd06ae307b Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 21 Dec 2023 21:36:40 +0100 Subject: [PATCH 28/55] test: update sign id test vectors --- types/quorum_sign_data_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index 799ea339d0..1583cc2692 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -41,7 +41,7 @@ func TestMakeBlockSignID(t *testing.T) { quorumHash: tmbytes.MustHexDecode("6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD"), want: newSignItem( "C8F2E1FE35DE03AC94F76191F59CAD1BA1F7A3C63742B7125990D996315001CC", - "2E8CEF1D36C4655225BE7CC6EE8169C80C9D1D0BF336D7B547DF1D7846B725DA", + "DA25B746781DDF47B5D736F30B1D9D0CC86981EEC67CBE255265C4361DEF8C2E", "02000000E9030000000000000000000000000000E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B"+ "7852B855E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855646173682D706C6174666F726D", "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", @@ -86,17 +86,16 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { }, quorumHash: tmbytes.MustHexDecode("6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD"), want: []crypto.SignItem{ - newSignItem( "FB95F2CA6530F02AC623589D7938643FF22AE79A75DD79AEA1C8871162DE675E", - "920740B3DA954CDB33F05F542E46502C10BACF8C085E8F8738B6BA99083FD1DF", + "533524404D3A905F5AC9A30FCEB5A922EAD96F30DA02F979EE41C4342F540467", "210A0764656661756C7411E903000000000000220D646173682D706C6174666F726D", "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", quorumType, ), newSignItem( "fb95f2ca6530f02ac623589d7938643ff22ae79a75dd79aea1c8871162de675e", - "A3B22D7D0D3D7DEB91AE414E8911AAB7BA476455113CA0E847628910C2FF312E", + "D3B7D53A0F9CA8072D47D6C18E782EE3155EF8DCDDB010087030B6CBC63978BC", "250a097468726573686f6c6411e903000000000000220d646173682d706c6174666f726d2801", "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", quorumType, @@ -128,6 +127,7 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { // // Given some vote extension, llmq type, quorum hash and sign request id, sign data should match predefined test vector. func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { + t.Skip("TODO: this should use the same test vectors as dash core") const chainID = "some-chain" const llmqType = btcjson.LLMQType_TEST_PLATFORM From f93f40e4edafa3a5501391a656fe38794a6d9d9d Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 21 Dec 2023 21:39:05 +0100 Subject: [PATCH 29/55] test(e2e): double-check that each vote extension has signature --- test/e2e/app/app.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index f5862fa19b..bffc288e0f 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -158,6 +158,14 @@ func (app *Application) FinalizeBlock(ctx context.Context, req *abci.RequestFina app.mu.Lock() defer app.mu.Unlock() + for i, ext := range req.Commit.ThresholdVoteExtensions { + if len(ext.Signature) == 0 { + return &abci.ResponseFinalizeBlock{}, fmt.Errorf("vote extension signature is empty: %+v", ext) + } + + app.logger.Debug("vote extension received in FinalizeBlock", "extension", ext, "i", i) + } + prevState := kvstore.NewKvState(db.NewMemDB(), 0) if err := app.LastCommittedState.Copy(prevState); err != nil { return &abci.ResponseFinalizeBlock{}, err From 50f35c33888066c44ef1c7879decee4a884fbbe4 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 21 Dec 2023 21:47:22 +0100 Subject: [PATCH 30/55] test: fix test vector --- crypto/quorum_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/quorum_test.go b/crypto/quorum_test.go index 6b6873f87a..ad8309c68b 100644 --- a/crypto/quorum_test.go +++ b/crypto/quorum_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/dashpay/tenderdash/crypto" + tmbytes "github.com/dashpay/tenderdash/libs/bytes" "github.com/stretchr/testify/assert" ) @@ -18,7 +19,7 @@ func TestQuorumSignItem(t *testing.T) { } si.UpdateSignHash(true) - expectID := mustHexDecode("94635358f4c75a1d0b38314619d1c5d9a16f12961b5314d857e04f2eb61d78d2") + expectID := tmbytes.Reverse(mustHexDecode("94635358f4c75a1d0b38314619d1c5d9a16f12961b5314d857e04f2eb61d78d2")) assert.EqualValues(t, expectID, si.SignHash) } From 5f5ded8d7c3b90c104692f983467d6533eb195c2 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 21 Dec 2023 21:47:45 +0100 Subject: [PATCH 31/55] build: allow choice of docker image architecture to use --- .github/workflows/docker.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 32ff9df20a..7c41562ab9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -9,6 +9,15 @@ on: type: string description: "Docker tag" required: false + + platforms: + type: choice + description: "Image architecture to build" + default: "linux/amd64,linux/arm64" + options: + - "linux/amd64,linux/arm64" + - "linux/amd64" + - "linux/arm64" release: types: - published @@ -79,7 +88,7 @@ jobs: with: context: . file: ./DOCKER/Dockerfile - platforms: linux/amd64,linux/arm64 + platforms: ${{ github.event.inputs.platforms }} target: base push: false cache-from: | From 9e1d9a1bb9cefe76a400dfca2b24ce05e1a04ba0 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 21 Dec 2023 22:17:23 +0100 Subject: [PATCH 32/55] test(e2e): TestApp_TxTooBig needs correct tx order --- test/e2e/app/app.go | 11 ++++++++++- test/e2e/tests/app_test.go | 5 +---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index bffc288e0f..1c3bba6b33 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -263,5 +263,14 @@ func verifyTx(tx types.Tx, _ abci.CheckTxType) (abci.ResponseCheckTx, error) { fmt.Errorf("malformed vote extension transaction %X=%X: %w", k, v, err) } } - return abci.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1}, nil + // For TestApp_TxTooBig we need to preserve order of transactions + var priority int64 + // in this case, k is defined as fmt.Sprintf("testapp-big-tx-%v-%08x-%d=", node.Name, session, i) + // but in general, we take last digit as inverse priority + split = bytes.Split(k, []byte{'-'}) + if n, err := strconv.ParseInt(string(split[len(split)-1]), 10, 64); err == nil { + priority = 1000000000 - n + } + + return abci.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1, Priority: priority}, nil } diff --git a/test/e2e/tests/app_test.go b/test/e2e/tests/app_test.go index 03706c2771..ac9b3566f5 100644 --- a/test/e2e/tests/app_test.go +++ b/test/e2e/tests/app_test.go @@ -219,7 +219,7 @@ func TestApp_TxTooBig(t *testing.T) { var key string for i := 0; i < numTxs; i++ { - key = fmt.Sprintf("testapp-big-tx-%v-%08x-%06x=", node.Name, session, i) + key = fmt.Sprintf("testapp-big-tx-%v-%08x-%d=", node.Name, session, i) copy(tx, key) payloadOffset := len(tx) - 8 // where we put the `i` into the payload @@ -233,7 +233,6 @@ func TestApp_TxTooBig(t *testing.T) { } _, err = client.BroadcastTxAsync(ctx, tx) - t.Logf("submitted tx %x", tx.Hash()) assert.NoError(t, err, "failed to broadcast tx %06x", i) } @@ -257,8 +256,6 @@ func TestApp_TxTooBig(t *testing.T) { return true } - // tx2 not there yet - t.Log("last tx not committed within timeout") return false }, timeout, // timeout From 615251a18923aa460df2ea33a01e99f727262c70 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 21 Dec 2023 23:49:32 +0100 Subject: [PATCH 33/55] fix: vote extension marshal panic --- abci/types/types.go | 16 +++++++++------- proto/tendermint/types/dash.go | 30 ++++++++++++++---------------- types/vote_extension.go | 13 ++++++------- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/abci/types/types.go b/abci/types/types.go index 5458b53f4d..23779998d4 100644 --- a/abci/types/types.go +++ b/abci/types/types.go @@ -374,17 +374,19 @@ func (m *RequestFinalizeBlock) ToCanonicalVote() (types.CanonicalVote, error) { // Convert to proto.types.VoteExtension. // Signature field will be nil, as ExtendVoteExtension doesn't have it. func (m *ExtendVoteExtension) ToVoteExtension() types.VoteExtension { - var requestID *types.VoteExtension_SignRequestId + ve := types.VoteExtension{ + Type: m.Type, + Extension: m.Extension, + } + + // workaround for a bug in gogoproto if m.XSignRequestId != nil { src := m.GetSignRequestId() - requestID = &types.VoteExtension_SignRequestId{ + ve.XSignRequestId = &types.VoteExtension_SignRequestId{ SignRequestId: bytes.Clone(src), } } - return types.VoteExtension{ - Type: m.Type, - Extension: m.Extension, - XSignRequestId: requestID, - } + + return ve } diff --git a/proto/tendermint/types/dash.go b/proto/tendermint/types/dash.go index 0c2a4f4b63..5dd6232a96 100644 --- a/proto/tendermint/types/dash.go +++ b/proto/tendermint/types/dash.go @@ -28,20 +28,19 @@ func (v *VoteExtension) Clone() VoteExtension { panic("cannot clone nil vote-extension") } - var xSignRequestID isVoteExtension_XSignRequestId + ve := VoteExtension{ + Type: v.Type, + Extension: v.Extension, + Signature: v.Signature, + } if v.XSignRequestId != nil && v.XSignRequestId.Size() > 0 { - xSignRequestID = &VoteExtension_SignRequestId{ + ve.XSignRequestId = &VoteExtension_SignRequestId{ SignRequestId: v.GetSignRequestId(), } } - return VoteExtension{ - Type: v.Type, - Extension: v.Extension, - Signature: v.Signature, - XSignRequestId: xSignRequestID, - } + return ve } // Copy returns a deep copy of current vote-extension. @@ -50,20 +49,19 @@ func (v *VoteExtension) Copy() VoteExtension { panic("cannot copy nil vote-extension") } - var xSignRequestID isVoteExtension_XSignRequestId + ve := VoteExtension{ + Type: v.Type, + Extension: bytes.Clone(v.Extension), + Signature: bytes.Clone(v.Signature), + } if v.XSignRequestId != nil && v.XSignRequestId.Size() > 0 { - xSignRequestID = &VoteExtension_SignRequestId{ + ve.XSignRequestId = &VoteExtension_SignRequestId{ SignRequestId: bytes.Clone(v.GetSignRequestId()), } } - return VoteExtension{ - Type: v.Type, - Extension: bytes.Clone(v.Extension), - Signature: bytes.Clone(v.Signature), - XSignRequestId: xSignRequestID, - } + return ve } func (v *VoteExtension) Equal(other *VoteExtension) bool { diff --git a/types/vote_extension.go b/types/vote_extension.go index 31a976d26e..cb94b06df8 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -123,21 +123,20 @@ func (e VoteExtensions) ToExtendProto() []*abci.ExtendVoteExtension { } pb := ext.ToProto() + eve := &abci.ExtendVoteExtension{ + Type: pb.Type, + Extension: pb.Extension, + } - var requestID *abci.ExtendVoteExtension_SignRequestId if pb.XSignRequestId != nil { if src := pb.GetSignRequestId(); len(src) > 0 { - requestID = &abci.ExtendVoteExtension_SignRequestId{ + eve.XSignRequestId = &abci.ExtendVoteExtension_SignRequestId{ SignRequestId: bytes.Clone(src), } } } - proto = append(proto, &abci.ExtendVoteExtension{ - Type: pb.Type, - Extension: pb.Extension, - XSignRequestId: requestID, - }) + proto = append(proto, eve) } return proto From b158f3bf5d13d3907d06a2bd1290edd23185e1b3 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 22 Dec 2023 00:09:54 +0100 Subject: [PATCH 34/55] build: fix platform selection for docker build --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 7c41562ab9..a21b5d6428 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -104,7 +104,7 @@ jobs: with: context: . file: ./DOCKER/Dockerfile - platforms: linux/amd64,linux/arm64 + platforms: ${{ github.event.inputs.platforms }} push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} From db1e2f0a1f13a3a6a390cad202abdc5a99d01ea0 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 22 Dec 2023 00:27:29 +0100 Subject: [PATCH 35/55] test(types): test vote extension marshaling --- proto/tendermint/types/dash_test.go | 76 +++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/proto/tendermint/types/dash_test.go b/proto/tendermint/types/dash_test.go index 4d430a690d..0191df6952 100644 --- a/proto/tendermint/types/dash_test.go +++ b/proto/tendermint/types/dash_test.go @@ -3,29 +3,73 @@ package types_test import ( "testing" - "github.com/dashpay/tenderdash/internal/libs/protoio" "github.com/dashpay/tenderdash/proto/tendermint/types" "github.com/stretchr/testify/assert" ) func TestMarshalVoteExtension(t *testing.T) { - - ve := &types.VoteExtension{ - Type: types.VoteExtensionType_THRESHOLD_RECOVER_RAW, - Extension: []byte("threshold"), - XSignRequestId: &types.VoteExtension_SignRequestId{ - SignRequestId: []byte("sign-request-id"), - }, + testCases := []struct { + extension types.VoteExtension + expectPanic bool + }{ + { + extension: types.VoteExtension{ + Type: types.VoteExtensionType_THRESHOLD_RECOVER_RAW, + Extension: []byte("threshold"), + XSignRequestId: &types.VoteExtension_SignRequestId{ + SignRequestId: []byte("sign-request-id"), + }}}, + { + extension: types.VoteExtension{ + Type: types.VoteExtensionType_THRESHOLD_RECOVER_RAW, + Extension: []byte("threshold"), + XSignRequestId: nil, + }}, + { + extension: types.VoteExtension{ + Type: types.VoteExtensionType_THRESHOLD_RECOVER_RAW, + Extension: []byte("threshold"), + XSignRequestId: &types.VoteExtension_SignRequestId{nil}, + }}, + // Test below panics because of nil pointer dereference bug in gogoproto + // FIXME: remove expectPanic when we replace gogoproto + { + expectPanic: true, + extension: types.VoteExtension{ + Type: types.VoteExtensionType_THRESHOLD_RECOVER_RAW, + Extension: []byte("threshold"), + XSignRequestId: (*types.VoteExtension_SignRequestId)(nil), + }}, + { + extension: (&types.VoteExtension{ + Type: types.VoteExtensionType_THRESHOLD_RECOVER_RAW, + Extension: []byte("threshold"), + XSignRequestId: (*types.VoteExtension_SignRequestId)(nil), + }).Clone()}, } - v := types.Vote{ - Type: types.PrecommitType, - VoteExtensions: []*types.VoteExtension{ve}, + for _, tc := range testCases { + t.Run("", func(t *testing.T) { + // marshaled, err := protoio.MarshalDelimited(tc) + // assert.NoError(t, err) + // assert.NotEmpty(t, marshaled) + + v := types.Vote{ + Type: types.PrecommitType, + VoteExtensions: []*types.VoteExtension{&tc.extension}, + } + f := func() { + marshaled, err := v.Marshal() + assert.NoError(t, err) + assert.NotEmpty(t, marshaled) + } + + if tc.expectPanic { + assert.Panics(t, f) + } else { + assert.NotPanics(t, f) + } + }) } - v.Marshal() - ve.Marshal() - marshaled, err := protoio.MarshalDelimited(ve) - assert.NoError(t, err) - assert.NotEmpty(t, marshaled) } From b7c67dc705ad8fe94715982443e1b52e93b26a85 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 3 Jan 2024 12:47:49 +0100 Subject: [PATCH 36/55] chore: reverse sign request id --- types/vote_extension.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/vote_extension.go b/types/vote_extension.go index cb94b06df8..fd026b5b7d 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -438,7 +438,8 @@ func (e ThresholdRawVoteExtension) SignItem(_ string, height int64, round int32, ext := &e.VoteExtension if ext.XSignRequestId != nil && ext.XSignRequestId.Size() > 0 { - signRequestID = crypto.Checksum(crypto.Checksum(ext.GetSignRequestId())) + receivedReqID := tmbytes.Reverse(ext.GetSignRequestId()) + signRequestID = crypto.Checksum(crypto.Checksum(receivedReqID)) // reverse ext.GetSignRequestId()? } else { if signRequestID, err = voteExtensionRequestID(height, round); err != nil { return crypto.SignItem{}, err From d9eca5e0905bb7c67d85bcb0712309dfd4dc3351 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 3 Jan 2024 14:38:27 +0100 Subject: [PATCH 37/55] chore: simplify code --- types/vote_extension.go | 49 +++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/types/vote_extension.go b/types/vote_extension.go index fd026b5b7d..fc8aa79ef1 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -330,7 +330,24 @@ func (e GenericVoteExtension) ToProto() tmproto.VoteExtension { } func (e GenericVoteExtension) SignItem(chainID string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) { - return signItem(&e.VoteExtension, chainID, height, round, quorumType, quorumHash) + requestID, err := voteExtensionRequestID(height, round) + if err != nil { + return crypto.SignItem{}, err + } + canonical, err := CanonicalizeVoteExtension(chainID, &e.VoteExtension, height, round) + if err != nil { + panic(err) + } + + signBytes, err := protoio.MarshalDelimited(&canonical) + if err != nil { + panic(err) + } + + si := crypto.NewSignItem(quorumType, quorumHash, requestID, signBytes) + // we do not reverse fields when calculating SignHash for vote extensions + // si.UpdateSignHash(false) + return si, nil } func (e GenericVoteExtension) IsThresholdRecoverable() bool { @@ -466,33 +483,3 @@ func (e ThresholdRawVoteExtension) SignItem(_ string, height int64, round int32, func voteExtensionRequestID(height int64, round int32) ([]byte, error) { return heightRoundRequestID("dpevote", height, round), nil } - -// voteExtensionSignBytes returns the proto-encoding of the canonicalized vote -// extension for signing. Panics if the marshaling fails. -// -// Similar to VoteSignBytes, the encoded Protobuf message is varint -// length-prefixed for backwards-compatibility with the Amino encoding. -func voteExtensionSignBytes(chainID string, height int64, round int32, ext *tmproto.VoteExtension) []byte { - canonical, err := CanonicalizeVoteExtension(chainID, ext, height, round) - if err != nil { - panic(err) - } - bz, err := protoio.MarshalDelimited(&canonical) - if err != nil { - panic(err) - } - - return bz -} - -func signItem(ext *tmproto.VoteExtension, chainID string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) { - requestID, err := voteExtensionRequestID(height, round) - if err != nil { - return crypto.SignItem{}, err - } - signBytes := voteExtensionSignBytes(chainID, height, round, ext) - si := crypto.NewSignItem(quorumType, quorumHash, requestID, signBytes) - // we do not reverse fields when calculating SignHash for vote extensions - // si.UpdateSignHash(false) - return si, nil -} From 80185941a9db10f8560aa12cef7d71059479241c Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 3 Jan 2024 15:46:52 +0100 Subject: [PATCH 38/55] chore: remove reverse --- types/vote_extension.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/vote_extension.go b/types/vote_extension.go index fc8aa79ef1..928c96620d 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -455,7 +455,7 @@ func (e ThresholdRawVoteExtension) SignItem(_ string, height int64, round int32, ext := &e.VoteExtension if ext.XSignRequestId != nil && ext.XSignRequestId.Size() > 0 { - receivedReqID := tmbytes.Reverse(ext.GetSignRequestId()) + receivedReqID := ext.GetSignRequestId() signRequestID = crypto.Checksum(crypto.Checksum(receivedReqID)) // reverse ext.GetSignRequestId()? } else { if signRequestID, err = voteExtensionRequestID(height, round); err != nil { From 78eb0498b29a9db05113c8e3d78447e4bbcd7442 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 4 Jan 2024 09:36:04 +0100 Subject: [PATCH 39/55] refactor: rename SignItem.Raw -> Msg --- crypto/quorum.go | 42 +++++++++++++++++------------- crypto/quorum_test.go | 2 +- privval/dash_core_signer_client.go | 6 ++--- privval/file.go | 4 +-- types/quorum.go | 4 +-- types/quorum_sign_data_test.go | 39 ++++++++++++++++++--------- types/vote_test.go | 4 +-- 7 files changed, 60 insertions(+), 41 deletions(-) diff --git a/crypto/quorum.go b/crypto/quorum.go index e6447fdad4..543a06c4af 100644 --- a/crypto/quorum.go +++ b/crypto/quorum.go @@ -14,12 +14,14 @@ import ( // Field names are the same as in Dash Core, but the meaning is different. // See DIP-0007 type SignItem struct { - ID []byte // Request ID for quorum signing - SignHash []byte // Hash of llmqType, quorumHash, id, and msgHash - final data to sign/verify - Raw []byte // Raw data to be signed, before any transformations - RawHash []byte // Checksum of Raw LlmqType btcjson.LLMQType // Quorum type for which this sign item is created + ID []byte // Request ID for quorum signing + MsgHash []byte // Checksum of Raw QuorumHash []byte // Quorum hash for which this sign item is created + + SignHash []byte // Hash of llmqType, quorumHash, id, and msgHash - as provided to crypto sign/verify functions + + Msg []byte // Raw data to be signed, before any transformations; optional } // Validate validates prepared data for signing @@ -27,25 +29,29 @@ func (i *SignItem) Validate() error { if len(i.ID) != DefaultHashSize { return fmt.Errorf("invalid request ID size: %X", i.ID) } - if len(i.RawHash) != DefaultHashSize { - return fmt.Errorf("invalid hash size %d: %X", len(i.RawHash), i.RawHash) + if len(i.MsgHash) != DefaultHashSize { + return fmt.Errorf("invalid hash size %d: %X", len(i.MsgHash), i.MsgHash) } if len(i.QuorumHash) != DefaultHashSize { return fmt.Errorf("invalid quorum hash size %d: %X", len(i.QuorumHash), i.QuorumHash) } - if len(i.Raw) > 0 { - if !bytes.Equal(Checksum(i.Raw), i.RawHash) { - return fmt.Errorf("invalid hash %X for raw data: %X", i.RawHash, i.Raw) + // Msg is optional + if len(i.Msg) > 0 { + if !bytes.Equal(Checksum(i.Msg), i.MsgHash) { + return fmt.Errorf("invalid hash %X for raw data: %X", i.MsgHash, i.Msg) } } return nil } func (i SignItem) MarshalZerologObject(e *zerolog.Event) { - e.Hex("signBytes", i.Raw) + e.Hex("msg", i.Msg) e.Hex("signRequestID", i.ID) e.Hex("signID", i.SignHash) - e.Hex("signHash", i.RawHash) + e.Hex("msgHash", i.MsgHash) + e.Hex("quorumHash", i.QuorumHash) + e.Uint8("llmqType", uint8(i.LlmqType)) + } // NewSignItem creates a new instance of SignItem with calculating a hash for a raw and creating signID @@ -54,11 +60,11 @@ func (i SignItem) MarshalZerologObject(e *zerolog.Event) { // - quorumType: quorum type // - quorumHash: quorum hash // - reqID: sign request ID -// - raw: raw data to be signed; it will be hashed with crypto.Checksum() -func NewSignItem(quorumType btcjson.LLMQType, quorumHash, reqID, raw []byte) SignItem { - msgHash := Checksum(raw) +// - msg: raw data to be signed; it will be hashed with crypto.Checksum() +func NewSignItem(quorumType btcjson.LLMQType, quorumHash, reqID, msg []byte) SignItem { + msgHash := Checksum(msg) // FIXME: shouldn't we use sha256(sha256(raw)) here? item := NewSignItemFromHash(quorumType, quorumHash, reqID, msgHash) - item.Raw = raw + item.Msg = msg return item } @@ -67,10 +73,10 @@ func NewSignItem(quorumType btcjson.LLMQType, quorumHash, reqID, raw []byte) Sig func NewSignItemFromHash(quorumType btcjson.LLMQType, quorumHash, reqID, msgHash []byte) SignItem { item := SignItem{ ID: reqID, - RawHash: msgHash, + MsgHash: msgHash, LlmqType: quorumType, QuorumHash: quorumHash, - Raw: nil, // Raw is empty, as we don't have it + Msg: nil, // Raw is empty, as we don't have it } // By default, reverse fields when calculating SignHash @@ -90,7 +96,7 @@ func (i *SignItem) UpdateSignHash(reverse bool) { quorumHash := i.QuorumHash requestID := i.ID - messageHash := i.RawHash + messageHash := i.MsgHash if reverse { quorumHash = tmbytes.Reverse(quorumHash) diff --git a/crypto/quorum_test.go b/crypto/quorum_test.go index ad8309c68b..62186d77eb 100644 --- a/crypto/quorum_test.go +++ b/crypto/quorum_test.go @@ -13,7 +13,7 @@ func TestQuorumSignItem(t *testing.T) { si := crypto.SignItem{ ID: mustHexDecode("87cda9461081793e7e31ab1def8ffbd453775a0f9987304598398d42a78d68d4"), - RawHash: mustHexDecode("5ef9b9eecc4df7c5aee677c0a72816f4515999a539003cf4bbb6c15c39634c31"), + MsgHash: mustHexDecode("5ef9b9eecc4df7c5aee677c0a72816f4515999a539003cf4bbb6c15c39634c31"), LlmqType: 106, QuorumHash: mustHexDecode("366f07c9b80a2661563a33c09f02156720159b911186b4438ff281e537674771"), } diff --git a/privval/dash_core_signer_client.go b/privval/dash_core_signer_client.go index 68acd6ec93..f462cc7d6f 100644 --- a/privval/dash_core_signer_client.go +++ b/privval/dash_core_signer_client.go @@ -408,8 +408,8 @@ func (sc *DashCoreSignerClient) quorumSignAndVerify( "sign_hash", hex.EncodeToString(qs.signHash), "req_id", hex.EncodeToString(signItem.ID), "id", hex.EncodeToString(signItem.SignHash), - "raw", hex.EncodeToString(signItem.Raw), - "hash", hex.EncodeToString(signItem.RawHash), + "raw", hex.EncodeToString(signItem.Msg), + "hash", hex.EncodeToString(signItem.MsgHash), "quorum_sign_result", *qs.QuorumSignResult) pubKey, err := sc.GetPubKey(ctx, quorumHash) if err != nil { @@ -427,7 +427,7 @@ func (sc *DashCoreSignerClient) quorumSign( quorumHash crypto.QuorumHash, signItem crypto.SignItem, ) (*quorumSignResult, error) { - resp, err := sc.dashCoreRPCClient.QuorumSign(quorumType, signItem.ID, signItem.RawHash, quorumHash) + resp, err := sc.dashCoreRPCClient.QuorumSign(quorumType, signItem.ID, signItem.MsgHash, quorumHash) if err != nil { return nil, &RemoteSignerError{Code: 500, Description: "cannot sign vote: " + err.Error()} } diff --git a/privval/file.go b/privval/file.go index 9131e53f9b..e44a77a7af 100644 --- a/privval/file.go +++ b/privval/file.go @@ -705,7 +705,7 @@ func (pv *FilePV) signVote( // If they only differ by timestamp, use last timestamp and signature // Otherwise, return error if sameHRS { - if bytes.Equal(quorumSigns.Block.Raw, lss.BlockSignBytes) { + if bytes.Equal(quorumSigns.Block.Msg, lss.BlockSignBytes) { vote.BlockSignature = lss.BlockSignature } else { return errors.New("conflicting data") @@ -727,7 +727,7 @@ func (pv *FilePV) signVote( // sigBlock, vote) // } - err = pv.saveSigned(height, round, step, quorumSigns.Block.Raw, sigBlock) + err = pv.saveSigned(height, round, step, quorumSigns.Block.Msg, sigBlock) if err != nil { return err } diff --git a/types/quorum.go b/types/quorum.go index a24f7a3e01..46e1604572 100644 --- a/types/quorum.go +++ b/types/quorum.go @@ -120,7 +120,7 @@ func (q *QuorumSingsVerifier) verifyBlock(pubKey crypto.PubKey, signs QuorumSign if !pubKey.VerifySignatureDigest(q.Block.SignHash, signs.BlockSign) { return fmt.Errorf( "threshold block signature is invalid: (%X) signID=%X: %w", - q.Block.Raw, + q.Block.Msg, q.Block.SignHash, ErrVoteInvalidBlockSignature, ) @@ -151,7 +151,7 @@ func (q *QuorumSingsVerifier) verifyVoteExtensions( for i, sig := range thresholdSigs { if !pubKey.VerifySignatureDigest(signItems[i].SignHash, sig) { return fmt.Errorf("vote-extension %d signature is invalid: raw %X, signature %X", i, - signItems[i].Raw, sig) + signItems[i].Msg, sig) } } return nil diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index 1583cc2692..ffd123c11a 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -53,9 +53,9 @@ func TestMakeBlockSignID(t *testing.T) { for i, tc := range testCases { t.Run(fmt.Sprintf("test-case %d", i), func(t *testing.T) { signItem := MakeBlockSignItem(chainID, tc.vote.ToProto(), quorumType, tc.quorumHash) - t.Logf("hash %X id %X raw %X reqID %X", signItem.RawHash, signItem.SignHash, signItem.Raw, signItem.ID) + t.Logf("hash %X id %X raw %X reqID %X", signItem.MsgHash, signItem.SignHash, signItem.Msg, signItem.ID) require.Equal(t, tc.want, signItem, "Got ID: %X", signItem.SignHash) - require.Equal(t, tc.wantHash, signItem.RawHash) + require.Equal(t, tc.wantHash, signItem.MsgHash) }) } } @@ -114,7 +114,7 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { require.NoError(t, err) for i, sign := range signItems { - assert.Equal(t, tc.wantHash[i], sign.RawHash, "want %X, actual %X", tc.wantHash[i], sign.RawHash) + assert.Equal(t, tc.wantHash[i], sign.MsgHash, "want %X, actual %X", tc.wantHash[i], sign.MsgHash) if !assert.Equal(t, tc.want[i], sign, "Got ID(%d): %X", i, sign.SignHash) { logger.Error("invalid sign", "sign", sign, "i", i) } @@ -127,24 +127,37 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { // // Given some vote extension, llmq type, quorum hash and sign request id, sign data should match predefined test vector. func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { - t.Skip("TODO: this should use the same test vectors as dash core") + // t.Skip("TODO: this should use the same test vectors as dash core") const chainID = "some-chain" const llmqType = btcjson.LLMQType_TEST_PLATFORM - quorumHash, err := hex.DecodeString("dddabfe1c883dd8a2c71c4281a4212c3715a61f87d62a99aaed0f65a0506c053") + // threshold_vote_extensions: [VoteExtension { r#type: ThresholdRecoverRaw, + // signature: [172, 4, 13, 160, 146, 213, 36, 188, 135, 233, 210, 83, 219, 136, 137, 56, 239, 214, 169, 192, 230, 76, 12, 129, 225, 221, 226, 53, 121, 4, 208, 206, 187, 5, 189, 177, 153, 248, 113, 211, 48, 64, 106, 119, 168, 92, 231, 199, 12, 225, 210, 227, 198, 53, 89, 178, 166, 144, 35, 58, 74, 230, 154, 60, 86, 193, 197, 113, 24, 92, 119, 211, 31, 50, 175, 139, 63, 182, 1, 236, 181, 55, 183, 240, 70, 101, 152, 134, 17, 45, 17, 107, 81, 112, 101, 3], + // sign_request_id: Some([6, 112, 108, 119, 100, 116, 120, 0, 0, 0, 0, 0, 0, 0, 0]) }] } + + // TODO + // quorumHash, err := hex.DecodeString("dddabfe1c883dd8a2c71c4281a4212c3715a61f87d62a99aaed0f65a0506c053") + // assert.NoError(t, err) + // assert.Len(t, quorumHash, 32) + + // requestID, err := hex.DecodeString("922a8fc39b6e265ca761eaaf863387a5e2019f4795a42260805f5562699fd9fa") + // assert.NoError(t, err) + // assert.Len(t, requestID, 32) + + // extension, err := hex.DecodeString("7dfb2432d37f004c4eb2b9aebf601ba4ad59889b81d2e8c7029dce3e0bf8381c") + // assert.NoError(t, err) + // assert.Len(t, extension, 32) + quorumHash, err := hex.DecodeString("1cdbea29c8b947d6a35269aabbd0cccfef64245778a62116524ccdbb6e3ec919") assert.NoError(t, err) assert.Len(t, quorumHash, 32) - requestID, err := hex.DecodeString("922a8fc39b6e265ca761eaaf863387a5e2019f4795a42260805f5562699fd9fa") assert.NoError(t, err) - assert.Len(t, requestID, 32) - extension, err := hex.DecodeString("7dfb2432d37f004c4eb2b9aebf601ba4ad59889b81d2e8c7029dce3e0bf8381c") - assert.NoError(t, err) + extension := []byte{209, 226, 137, 236, 75, 102, 97, 95, 224, 61, 203, 233, 87, 62, 153, 90, 177, 26, 169, 127, 239, 22, 141, 238, 175, 198, 120, 8, 156, 150, 182, 166} assert.Len(t, extension, 32) - extension = []byte{192, 37, 45, 64, 121, 74, 111, 51, 205, 98, 131, 161, 46, 118, 67, 43, 230, 124, 152, 192, 116, 136, 97, 125, 135, 163, 168, 131, 139, 120, 59, 42} - requestID = []byte{6, 112, 108, 119, 100, 116, 120, 0, 0, 0, 0, 0, 0, 0, 0} + requestID := []byte{6, 112, 108, 119, 100, 116, 120, 0, 0, 0, 0, 0, 0, 0, 0} + signature := []byte{172, 4, 13, 160, 146, 213, 36, 188, 135, 233, 210, 83, 219, 136, 137, 56, 239, 214, 169, 192, 230, 76, 12, 129, 225, 221, 226, 53, 121, 4, 208, 206, 187, 5, 189, 177, 153, 248, 113, 211, 48, 64, 106, 119, 168, 92, 231, 199, 12, 225, 210, 227, 198, 53, 89, 178, 166, 144, 35, 58, 74, 230, 154, 60, 86, 193, 197, 113, 24, 92, 119, 211, 31, 50, 175, 139, 63, 182, 1, 236, 181, 55, 183, 240, 70, 101, 152, 134, 17, 45, 17, 107, 81, 112, 101, 3} expected, err := hex.DecodeString("B7561730665DBD53A1947265CA5B78A3556B27DA5AB9264630A8E03918915397") assert.NoError(t, err) @@ -155,7 +168,7 @@ func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { ve := VoteExtensionFromProto(tmproto.VoteExtension{ Extension: extension, - Signature: []byte{}, + Signature: signature, Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, XSignRequestId: &tmproto.VoteExtension_SignRequestId{ SignRequestId: requestID, @@ -171,7 +184,7 @@ func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { t.Logf("sign requestID: %X\n", requestID) t.Logf("quorum hash: %X\n", quorumHash) - t.Logf("RESULT: sign bytes: %X", actual) + t.Logf("RESULT: signHash: %X", actual) assert.EqualValues(t, expected, actual) } diff --git a/types/vote_test.go b/types/vote_test.go index 3283f46781..3657d45c28 100644 --- a/types/vote_test.go +++ b/types/vote_test.go @@ -674,7 +674,7 @@ func TestVoteExtensionsSignBytes(t *testing.T) { signItem, err := VoteExtensionFromProto(ve).SignItem("some-chain", 1, 2, btcjson.LLMQType_TEST_PLATFORM, crypto.RandQuorumHash()) assert.NoError(t, err) - actual := signItem.Raw + actual := signItem.Msg t.Logf("sign bytes: %x", actual) assert.EqualValues(t, expect, actual) @@ -696,7 +696,7 @@ func TestVoteExtensionsSignBytesRaw(t *testing.T) { signItem, err := VoteExtensionFromProto(ve).SignItem("some-chain", 1, 2, btcjson.LLMQType_TEST_PLATFORM, crypto.RandQuorumHash()) assert.NoError(t, err) - actual := signItem.Raw + actual := signItem.Msg t.Logf("sign bytes: %x", actual) assert.EqualValues(t, expect, actual) From 3b9f86959dee18de8c78859a61383647847b7575 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 4 Jan 2024 09:41:22 +0100 Subject: [PATCH 40/55] chore: reverse bytes in extension and require 32 bytes for RAW --- proto/tendermint/abci/types.proto | 2 ++ proto/tendermint/types/dash.go | 8 ++++++++ types/vote_extension.go | 19 ++++++++++++------- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 2e1494b2a1..2ee78dee8c 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -666,6 +666,8 @@ message ExtendVoteExtension { // The Tenderdash supports only THRESHOLD_RECOVER and THRESHOLD_RECOVER_RAW at this moment. tendermint.types.VoteExtensionType type = 1; // Deterministic or (Non-Deterministic) extension provided by the sending validator's Application. + // + // For THRESHOLD_RECOVER_RAW, it MUST be 32 bytes. bytes extension = 2; // Sign request ID that will be used to sign the vote extensions. // Only applicable for THRESHOLD_RECOVER_RAW vote extension type. diff --git a/proto/tendermint/types/dash.go b/proto/tendermint/types/dash.go index 5dd6232a96..7ac0d9939a 100644 --- a/proto/tendermint/types/dash.go +++ b/proto/tendermint/types/dash.go @@ -5,6 +5,7 @@ import ( "errors" fmt "fmt" + "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/crypto/bls12381" ) @@ -105,6 +106,13 @@ func (v *VoteExtension) Validate() error { return fmt.Errorf("vote extension type %s is not supported", v.Type.String()) } + if v.Type == VoteExtensionType_THRESHOLD_RECOVER_RAW { + if len(v.Extension) != crypto.HashSize { + return fmt.Errorf("invalid %s vote extension size: got %d, expected %d", + v.Type.String(), len(v.Extension), crypto.HashSize) + } + } + if len(v.Extension) > 0 && len(v.Signature) == 0 { return errExtensionSignEmpty } diff --git a/types/vote_extension.go b/types/vote_extension.go index 928c96620d..0c32944462 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -463,17 +463,22 @@ func (e ThresholdRawVoteExtension) SignItem(_ string, height int64, round int32, } } - // ensure signBytes is 32 bytes long - signBytes := make([]byte, crypto.DefaultHashSize) - copy(signBytes, ext.Extension) + // ensure Extension is 32 bytes long + if len(ext.Extension) != crypto.DefaultHashSize { + return crypto.SignItem{}, fmt.Errorf("invalid vote extension %s %X: extension must be %d bytes long", + ext.Type.String(), ext.Extension, crypto.DefaultHashSize) + } + + // We sign extension as it is, without any hashing, etc. + // However, as it is reversed in SignItem.UpdateSignHash, we need to reverse it also here to undo + // that reversal. + msgHash := tmbytes.Reverse(ext.Extension) - signItem, err := crypto.NewSignItemFromHash(quorumType, quorumHash, signRequestID, signBytes), nil + signItem, err := crypto.NewSignItemFromHash(quorumType, quorumHash, signRequestID, msgHash), nil if err != nil { return crypto.SignItem{}, err } - // we do not reverse fields when calculating SignHash for vote extensions - // signItem.UpdateSignHash(false) - signItem.Raw = ext.Extension + signItem.Msg = ext.Extension return signItem, nil } From 55b8327941e304a8d61f690558474a8e2b27f3c2 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 4 Jan 2024 11:08:15 +0100 Subject: [PATCH 41/55] chore: reverse generated request id --- types/vote_extension.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/vote_extension.go b/types/vote_extension.go index 0c32944462..1f06eacebb 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -457,6 +457,7 @@ func (e ThresholdRawVoteExtension) SignItem(_ string, height int64, round int32, if ext.XSignRequestId != nil && ext.XSignRequestId.Size() > 0 { receivedReqID := ext.GetSignRequestId() signRequestID = crypto.Checksum(crypto.Checksum(receivedReqID)) // reverse ext.GetSignRequestId()? + signRequestID = tmbytes.Reverse(signRequestID) } else { if signRequestID, err = voteExtensionRequestID(height, round); err != nil { return crypto.SignItem{}, err @@ -478,7 +479,7 @@ func (e ThresholdRawVoteExtension) SignItem(_ string, height int64, round int32, if err != nil { return crypto.SignItem{}, err } - signItem.Msg = ext.Extension + // signItem.Msg left empty by purpose, as we don't want hash to be checked in Verify() return signItem, nil } From 1757eccd691f14818a53285d12b653a1956523ba Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 4 Jan 2024 11:32:22 +0100 Subject: [PATCH 42/55] chore: add debug --- crypto/quorum.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crypto/quorum.go b/crypto/quorum.go index 543a06c4af..3225d860b2 100644 --- a/crypto/quorum.go +++ b/crypto/quorum.go @@ -123,6 +123,11 @@ func (i *SignItem) UpdateSignHash(reverse bool) { var blsMessageHash bls.Hash copy(blsMessageHash[:], messageHash) + fmt.Printf("LlmqType: %x + ", llmqType) + fmt.Printf("QuorumHash: %x + ", blsQuorumHash) + fmt.Printf("RequestID: %x + ", blsRequestID) + fmt.Printf("MsgHash: %x\n", blsMessageHash) + blsSignHash := bls.BuildSignHash(uint8(llmqType), blsQuorumHash, blsRequestID, blsMessageHash) signHash := make([]byte, 32) From 77eaa48f96a489aa95c12945edf9b3bc8be6dd32 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:33:52 +0100 Subject: [PATCH 43/55] test: working test vector for withdrawals --- types/quorum_sign_data_test.go | 62 ++++++++++++++-------------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index ffd123c11a..08f3da56ea 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -124,68 +124,58 @@ func TestMakeVoteExtensionSignsData(t *testing.T) { } // TestVoteExtensionsRawSignData checks signed data for a VoteExtensionType_THRESHOLD_RECOVER_RAW vote extension type. +// It uses test vectors from withdrawal processing. // // Given some vote extension, llmq type, quorum hash and sign request id, sign data should match predefined test vector. -func TestVoteExtensionsRawSignDataRawVector(t *testing.T) { - // t.Skip("TODO: this should use the same test vectors as dash core") +func TestVoteExtensionsRawSignDataRawVector_Withdrawals(t *testing.T) { + // llmqType:106 + // quorumHash:53c006055af6d0ae9aa9627df8615a71c312421a28c4712c8add83c8e1bfdadd + // requestID:922a8fc39b6e265ca761eaaf863387a5e2019f4795a42260805f5562699fd9fa + // messageHash:2a3b788b83a8a3877d618874c0987ce62b43762ea18362cd336f4a79402d25c0 + // ==== signHash:9753911839e0a8304626b95ada276b55a3785bca657294a153bd5d66301756b7 + const chainID = "some-chain" const llmqType = btcjson.LLMQType_TEST_PLATFORM - // threshold_vote_extensions: [VoteExtension { r#type: ThresholdRecoverRaw, - // signature: [172, 4, 13, 160, 146, 213, 36, 188, 135, 233, 210, 83, 219, 136, 137, 56, 239, 214, 169, 192, 230, 76, 12, 129, 225, 221, 226, 53, 121, 4, 208, 206, 187, 5, 189, 177, 153, 248, 113, 211, 48, 64, 106, 119, 168, 92, 231, 199, 12, 225, 210, 227, 198, 53, 89, 178, 166, 144, 35, 58, 74, 230, 154, 60, 86, 193, 197, 113, 24, 92, 119, 211, 31, 50, 175, 139, 63, 182, 1, 236, 181, 55, 183, 240, 70, 101, 152, 134, 17, 45, 17, 107, 81, 112, 101, 3], - // sign_request_id: Some([6, 112, 108, 119, 100, 116, 120, 0, 0, 0, 0, 0, 0, 0, 0]) }] } - - // TODO - // quorumHash, err := hex.DecodeString("dddabfe1c883dd8a2c71c4281a4212c3715a61f87d62a99aaed0f65a0506c053") - // assert.NoError(t, err) - // assert.Len(t, quorumHash, 32) - - // requestID, err := hex.DecodeString("922a8fc39b6e265ca761eaaf863387a5e2019f4795a42260805f5562699fd9fa") - // assert.NoError(t, err) - // assert.Len(t, requestID, 32) - - // extension, err := hex.DecodeString("7dfb2432d37f004c4eb2b9aebf601ba4ad59889b81d2e8c7029dce3e0bf8381c") - // assert.NoError(t, err) - // assert.Len(t, extension, 32) - quorumHash, err := hex.DecodeString("1cdbea29c8b947d6a35269aabbd0cccfef64245778a62116524ccdbb6e3ec919") + quorumHash, err := hex.DecodeString("53c006055af6d0ae9aa9627df8615a71c312421a28c4712c8add83c8e1bfdadd") assert.NoError(t, err) assert.Len(t, quorumHash, 32) - assert.NoError(t, err) - - extension := []byte{209, 226, 137, 236, 75, 102, 97, 95, 224, 61, 203, 233, 87, 62, 153, 90, 177, 26, 169, 127, 239, 22, 141, 238, 175, 198, 120, 8, 156, 150, 182, 166} - assert.Len(t, extension, 32) - + extension := []byte{192, 37, 45, 64, 121, 74, 111, 51, 205, 98, 131, 161, 46, 118, 67, 43, 230, 124, 152, 192, 116, 136, 97, 125, 135, 163, 168, 131, 139, 120, 59, 42} requestID := []byte{6, 112, 108, 119, 100, 116, 120, 0, 0, 0, 0, 0, 0, 0, 0} - signature := []byte{172, 4, 13, 160, 146, 213, 36, 188, 135, 233, 210, 83, 219, 136, 137, 56, 239, 214, 169, 192, 230, 76, 12, 129, 225, 221, 226, 53, 121, 4, 208, 206, 187, 5, 189, 177, 153, 248, 113, 211, 48, 64, 106, 119, 168, 92, 231, 199, 12, 225, 210, 227, 198, 53, 89, 178, 166, 144, 35, 58, 74, 230, 154, 60, 86, 193, 197, 113, 24, 92, 119, 211, 31, 50, 175, 139, 63, 182, 1, 236, 181, 55, 183, 240, 70, 101, 152, 134, 17, 45, 17, 107, 81, 112, 101, 3} + // assert.Len(t, requestID, 32) + + expectedSignHash, err := hex.DecodeString("9753911839e0a8304626b95ada276b55a3785bca657294a153bd5d66301756b7") + assert.NoError(t, err) + assert.Len(t, expectedSignHash, 32) + expectedSignHash = tmbytes.Reverse(expectedSignHash) - expected, err := hex.DecodeString("B7561730665DBD53A1947265CA5B78A3556B27DA5AB9264630A8E03918915397") + expectedRequestID, err := hex.DecodeString("922a8fc39b6e265ca761eaaf863387a5e2019f4795a42260805f5562699fd9fa") assert.NoError(t, err) - assert.Len(t, expected, 32) - // expected = tmbytes.Reverse(expected) + assert.Len(t, expectedRequestID, 32) // Note: MakeVoteExtensionSignItems() calls MakeSignID(), which will reverse bytes in quorumHash, requestID and extension. - ve := VoteExtensionFromProto(tmproto.VoteExtension{ + ve := tmproto.VoteExtension{ Extension: extension, - Signature: signature, + Signature: []byte{}, Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, XSignRequestId: &tmproto.VoteExtension_SignRequestId{ SignRequestId: requestID, }, - }) - - item, err := ve.SignItem(chainID, 1, 0, llmqType, quorumHash) + } + voteExtension := VoteExtensionFromProto(ve) + signItem, err := voteExtension.SignItem(chainID, 1, 0, llmqType, quorumHash) assert.NoError(t, err) - actual := item.SignHash t.Logf("LLMQ type: %s (%d)\n", llmqType.Name(), llmqType) t.Logf("extension: %X\n", extension) t.Logf("sign requestID: %X\n", requestID) t.Logf("quorum hash: %X\n", quorumHash) - t.Logf("RESULT: signHash: %X", actual) - assert.EqualValues(t, expected, actual) + t.Logf("RESULT: sign hash: %X", signItem.SignHash) + assert.EqualValues(t, expectedSignHash, signItem.SignHash) + assert.EqualValues(t, expectedRequestID, signItem.ID) } From a10c82aa3c95020ba01bab7e0f648a4b1cba3cb2 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 5 Jan 2024 12:50:02 +0100 Subject: [PATCH 44/55] test: withdrawals --- types/quorum_sign_data_test.go | 124 +---------------------- types/vote_extension_test.go | 178 +++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 123 deletions(-) diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index 08f3da56ea..be60f0b046 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -1,7 +1,6 @@ package types import ( - "encoding/hex" "fmt" "testing" @@ -11,9 +10,7 @@ import ( "github.com/dashpay/tenderdash/crypto" tmbytes "github.com/dashpay/tenderdash/libs/bytes" - "github.com/dashpay/tenderdash/libs/log" "github.com/dashpay/tenderdash/proto/tendermint/types" - tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" ) func TestBlockRequestID(t *testing.T) { @@ -22,7 +19,7 @@ func TestBlockRequestID(t *testing.T) { assert.EqualValues(t, expected, got) } -func TestMakeBlockSignID(t *testing.T) { +func TestMakeBlockSignItem(t *testing.T) { const chainID = "dash-platform" const quorumType = btcjson.LLMQType_5_60 @@ -60,125 +57,6 @@ func TestMakeBlockSignID(t *testing.T) { } } -func TestMakeVoteExtensionSignsData(t *testing.T) { - const chainID = "dash-platform" - const quorumType = btcjson.LLMQType_5_60 - - logger := log.NewTestingLogger(t) - testCases := []struct { - vote Vote - quorumHash []byte - want []crypto.SignItem - wantHash [][]byte - }{ - { - vote: Vote{ - Type: types.PrecommitType, - Height: 1001, - ValidatorProTxHash: tmbytes.MustHexDecode("9CC13F685BC3EA0FCA99B87F42ABCC934C6305AA47F62A32266A2B9D55306B7B"), - VoteExtensions: VoteExtensionsFromProto(&tmproto.VoteExtension{ - Type: tmproto.VoteExtensionType_DEFAULT, - Extension: []byte("default")}, - &tmproto.VoteExtension{ - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Extension: []byte("threshold")}, - ), - }, - quorumHash: tmbytes.MustHexDecode("6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD"), - want: []crypto.SignItem{ - newSignItem( - "FB95F2CA6530F02AC623589D7938643FF22AE79A75DD79AEA1C8871162DE675E", - "533524404D3A905F5AC9A30FCEB5A922EAD96F30DA02F979EE41C4342F540467", - "210A0764656661756C7411E903000000000000220D646173682D706C6174666F726D", - "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", - quorumType, - ), - newSignItem( - "fb95f2ca6530f02ac623589d7938643ff22ae79a75dd79aea1c8871162de675e", - "D3B7D53A0F9CA8072D47D6C18E782EE3155EF8DCDDB010087030B6CBC63978BC", - "250a097468726573686f6c6411e903000000000000220d646173682d706c6174666f726d2801", - "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", - quorumType, - ), - }, - wantHash: [][]byte{ - tmbytes.MustHexDecode("61519D79DE4C4D5AC5DD210C1BCE81AA24F76DD5581A24970E60112890C68FB7"), - tmbytes.MustHexDecode("46C72C423B74034E1AF574A99091B017C0698FEAA55C8B188BFD512FCADD3143"), - }, - }, - } - for i, tc := range testCases { - t.Run(fmt.Sprintf("test-case #%d", i), func(t *testing.T) { - signItems, err := tc.vote.VoteExtensions.SignItems(chainID, quorumType, tc.quorumHash, tc.vote.Height, tc.vote.Round) - - require.NoError(t, err) - - for i, sign := range signItems { - assert.Equal(t, tc.wantHash[i], sign.MsgHash, "want %X, actual %X", tc.wantHash[i], sign.MsgHash) - if !assert.Equal(t, tc.want[i], sign, "Got ID(%d): %X", i, sign.SignHash) { - logger.Error("invalid sign", "sign", sign, "i", i) - } - } - }) - } -} - -// TestVoteExtensionsRawSignData checks signed data for a VoteExtensionType_THRESHOLD_RECOVER_RAW vote extension type. -// It uses test vectors from withdrawal processing. -// -// Given some vote extension, llmq type, quorum hash and sign request id, sign data should match predefined test vector. -func TestVoteExtensionsRawSignDataRawVector_Withdrawals(t *testing.T) { - // llmqType:106 - // quorumHash:53c006055af6d0ae9aa9627df8615a71c312421a28c4712c8add83c8e1bfdadd - // requestID:922a8fc39b6e265ca761eaaf863387a5e2019f4795a42260805f5562699fd9fa - // messageHash:2a3b788b83a8a3877d618874c0987ce62b43762ea18362cd336f4a79402d25c0 - // ==== signHash:9753911839e0a8304626b95ada276b55a3785bca657294a153bd5d66301756b7 - - const chainID = "some-chain" - const llmqType = btcjson.LLMQType_TEST_PLATFORM - - quorumHash, err := hex.DecodeString("53c006055af6d0ae9aa9627df8615a71c312421a28c4712c8add83c8e1bfdadd") - assert.NoError(t, err) - assert.Len(t, quorumHash, 32) - - extension := []byte{192, 37, 45, 64, 121, 74, 111, 51, 205, 98, 131, 161, 46, 118, 67, 43, 230, 124, 152, 192, 116, 136, 97, 125, 135, 163, 168, 131, 139, 120, 59, 42} - requestID := []byte{6, 112, 108, 119, 100, 116, 120, 0, 0, 0, 0, 0, 0, 0, 0} - // assert.Len(t, requestID, 32) - - expectedSignHash, err := hex.DecodeString("9753911839e0a8304626b95ada276b55a3785bca657294a153bd5d66301756b7") - assert.NoError(t, err) - assert.Len(t, expectedSignHash, 32) - expectedSignHash = tmbytes.Reverse(expectedSignHash) - - expectedRequestID, err := hex.DecodeString("922a8fc39b6e265ca761eaaf863387a5e2019f4795a42260805f5562699fd9fa") - assert.NoError(t, err) - assert.Len(t, expectedRequestID, 32) - - // Note: MakeVoteExtensionSignItems() calls MakeSignID(), which will reverse bytes in quorumHash, requestID and extension. - - ve := tmproto.VoteExtension{ - Extension: extension, - Signature: []byte{}, - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, - XSignRequestId: &tmproto.VoteExtension_SignRequestId{ - SignRequestId: requestID, - }, - } - voteExtension := VoteExtensionFromProto(ve) - signItem, err := voteExtension.SignItem(chainID, 1, 0, llmqType, quorumHash) - assert.NoError(t, err) - - t.Logf("LLMQ type: %s (%d)\n", llmqType.Name(), llmqType) - t.Logf("extension: %X\n", extension) - t.Logf("sign requestID: %X\n", requestID) - t.Logf("quorum hash: %X\n", quorumHash) - - t.Logf("RESULT: sign hash: %X", signItem.SignHash) - assert.EqualValues(t, expectedSignHash, signItem.SignHash) - assert.EqualValues(t, expectedRequestID, signItem.ID) - -} - func newSignItem(reqID, signHash, raw, quorumHash string, quorumType btcjson.LLMQType) crypto.SignItem { item := crypto.NewSignItem(quorumType, tmbytes.MustHexDecode(quorumHash), tmbytes.MustHexDecode(reqID), tmbytes.MustHexDecode(raw)) item.SignHash = tmbytes.MustHexDecode(signHash) diff --git a/types/vote_extension_test.go b/types/vote_extension_test.go index 17ed25f02a..2765542408 100644 --- a/types/vote_extension_test.go +++ b/types/vote_extension_test.go @@ -1,8 +1,18 @@ package types import ( + "bytes" + "encoding/binary" + "encoding/hex" + "fmt" "testing" + "github.com/dashpay/dashd-go/btcjson" + "github.com/dashpay/tenderdash/crypto" + "github.com/dashpay/tenderdash/crypto/bls12381" + tmbytes "github.com/dashpay/tenderdash/libs/bytes" + "github.com/dashpay/tenderdash/libs/log" + "github.com/dashpay/tenderdash/proto/tendermint/types" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -22,3 +32,171 @@ func TestVoteExtensionCopySignsFromProto(t *testing.T) { require.NoError(t, err) assert.EqualValues(t, src[0].GetSignature(), dst[0].GetSignature()) } + +func TestMakeVoteExtensionsSignItems(t *testing.T) { + const chainID = "dash-platform" + const quorumType = btcjson.LLMQType_5_60 + + logger := log.NewTestingLogger(t) + testCases := []struct { + vote Vote + quorumHash []byte + want []crypto.SignItem + wantHash [][]byte + }{ + { + vote: Vote{ + Type: types.PrecommitType, + Height: 1001, + ValidatorProTxHash: tmbytes.MustHexDecode("9CC13F685BC3EA0FCA99B87F42ABCC934C6305AA47F62A32266A2B9D55306B7B"), + VoteExtensions: VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_DEFAULT, + Extension: []byte("default")}, + &tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("threshold")}, + ), + }, + quorumHash: tmbytes.MustHexDecode("6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD"), + want: []crypto.SignItem{ + newSignItem( + "FB95F2CA6530F02AC623589D7938643FF22AE79A75DD79AEA1C8871162DE675E", + "533524404D3A905F5AC9A30FCEB5A922EAD96F30DA02F979EE41C4342F540467", + "210A0764656661756C7411E903000000000000220D646173682D706C6174666F726D", + "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", + quorumType, + ), + newSignItem( + "fb95f2ca6530f02ac623589d7938643ff22ae79a75dd79aea1c8871162de675e", + "D3B7D53A0F9CA8072D47D6C18E782EE3155EF8DCDDB010087030B6CBC63978BC", + "250a097468726573686f6c6411e903000000000000220d646173682d706c6174666f726d2801", + "6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD", + quorumType, + ), + }, + wantHash: [][]byte{ + tmbytes.MustHexDecode("61519D79DE4C4D5AC5DD210C1BCE81AA24F76DD5581A24970E60112890C68FB7"), + tmbytes.MustHexDecode("46C72C423B74034E1AF574A99091B017C0698FEAA55C8B188BFD512FCADD3143"), + }, + }, + } + for i, tc := range testCases { + t.Run(fmt.Sprintf("test-case #%d", i), func(t *testing.T) { + signItems, err := tc.vote.VoteExtensions.SignItems(chainID, quorumType, tc.quorumHash, tc.vote.Height, tc.vote.Round) + + require.NoError(t, err) + + for i, sign := range signItems { + assert.Equal(t, tc.wantHash[i], sign.MsgHash, "want %X, actual %X", tc.wantHash[i], sign.MsgHash) + if !assert.Equal(t, tc.want[i], sign, "Got ID(%d): %X", i, sign.SignHash) { + logger.Error("invalid sign", "sign", sign, "i", i) + } + } + }) + } +} + +// Test vectors of THRESHOLD_RECOVER_RAW vote extensions hashing, as used by Dash Platform withdrawals mechanism. +// +// Given some vote extension, llmq type, quorum hash and sign request id, sign data should match predefined test vector. +func TestVoteExtensionsRaw_SignDataRawVector_Withdrawals(t *testing.T) { + const chainID = "some-chain" // unused but required for VoteExtension.SignItem + const llmqType = btcjson.LLMQType_TEST_PLATFORM + + testCases := []struct { + llmqType btcjson.LLMQType + quorumHash []byte + requestID []byte + extension []byte + + // optional + quorumSig []byte + quorumPubKey []byte + + expectedMsgHash []byte + expectedSignHash []byte + expectedRequestID []byte + }{ + { // llmqType:106 + // quorumHash:53c006055af6d0ae9aa9627df8615a71c312421a28c4712c8add83c8e1bfdadd + // requestID:922a8fc39b6e265ca761eaaf863387a5e2019f4795a42260805f5562699fd9fa + // messageHash:2a3b788b83a8a3877d618874c0987ce62b43762ea18362cd336f4a79402d25c0 + // ==== signHash:9753911839e0a8304626b95ada276b55a3785bca657294a153bd5d66301756b7 + llmqType: btcjson.LLMQType_TEST_PLATFORM, + + quorumHash: tmbytes.MustHexDecode("53c006055af6d0ae9aa9627df8615a71c312421a28c4712c8add83c8e1bfdadd"), + requestID: binary.LittleEndian.AppendUint64([]byte("\x06plwdtx"), 0), + extension: []byte{192, 37, 45, 64, 121, 74, 111, 51, 205, 98, 131, 161, 46, 118, 67, 43, 230, 124, 152, 192, 116, 136, 97, 125, 135, 163, 168, 131, 139, 120, 59, 42}, + expectedSignHash: tmbytes.Reverse(tmbytes.MustHexDecode("9753911839e0a8304626b95ada276b55a3785bca657294a153bd5d66301756b7")), + expectedRequestID: tmbytes.MustHexDecode("922a8fc39b6e265ca761eaaf863387a5e2019f4795a42260805f5562699fd9fa"), + }, + { // test that requestID is correct for index 102 + quorumHash: tmbytes.MustHexDecode("53c006055af6d0ae9aa9627df8615a71c312421a28c4712c8add83c8e1bfdadd"), + requestID: binary.LittleEndian.AppendUint64([]byte("\x06plwdtx"), 102), + extension: []byte{192, 37, 45, 64, 121, 74, 111, 51, 205, 98, 131, 161, 46, 118, 67, 43, 230, 124, 152, 192, 116, 136, 97, 125, 135, 163, 168, 131, 139, 120, 59, 42}, + expectedRequestID: tmbytes.MustHexDecode("7a1b17a4542f4748c6b91bd46c7daa4f26f77f67cd2d9d405c8d956c77a44764"), + }, + { + // tx = 03000900000190cff4050000000023210375aae0756e8115ea064b46705c7b0a8ffad3d79688d910ef0337239fc + // 1b3760dac000000009101650000000000000070110100db04000031707c372e1a75dab8455659a2c7757842aa80 + // 998eae146847f1372447a5d02585fe5c9e8f7985ac27d41b1ca654e783bd7eaab484882ceae3cb3511acefac0e8 + // 875b691813ec26101c3384a6e506be9133ba977ae12be89ffa1a1105968fc01c7de4e02ac8c689989a5677ceb2e + // 284a57d57f7885c40658096d7c6294f9fa7a + + llmqType: btcjson.LLMQType_TEST, + quorumHash: tmbytes.MustHexDecode("25d0a5472437f1476814ae8e9980aa427875c7a2595645b8da751a2e377c7031"), + requestID: binary.LittleEndian.AppendUint64([]byte("\x06plwdtx"), 101), + extension: tmbytes.MustHexDecode("68CA7F464880F4040AF87DBE79F725C74398C3A2001700D7A0FEDB9417FD622F"), + + // TODO: Uncomment when we have public key + // quorumSig: tmbytes.MustHexDecode("85fe5c9e8f7985ac27d41b1ca654e783bd7eaab484882ceae3cb3511acefac0e8875b691813ec26101c3384a6e506be9133ba977ae12be89ffa1a1105968fc01c7de4e02ac8c689989a5677ceb2e284a57d57f7885c40658096d7c6294f9fa7a"), + // quorumPubKey: tmbytes.MustHexDecode("210375aae0756e8115ea064b46705c7b0a8ffad3d79688d910ef0337239fc1b3760dac"), + + // expectedSignHash: tmbytes.Reverse(tmbytes.MustHexDecode("9753911839e0a8304626b95ada276b55a3785bca657294a153bd5d66301756b7")), + expectedMsgHash: tmbytes.Reverse(tmbytes.MustHexDecode("68ca7f464880f4040af87dbe79f725c74398c3a2001700d7a0fedb9417fd622f")), + expectedRequestID: tmbytes.MustHexDecode("fcc76a643c5c668244fdcef09833955d6f4b803fa6c459f7732983c2332389fd"), + }, + } + + for _, tc := range testCases { + t.Run("", func(t *testing.T) { + + ve := tmproto.VoteExtension{ + Extension: tc.extension, + Signature: []byte{}, + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, + XSignRequestId: &tmproto.VoteExtension_SignRequestId{ + SignRequestId: bytes.Clone(tc.requestID), + }, + } + voteExtension := VoteExtensionFromProto(ve) + signItem, err := voteExtension.SignItem(chainID, 1, 0, llmqType, tc.quorumHash) + require.NoError(t, err) + + // t.Logf("LLMQ type: %s (%d)\n", llmqType.Name(), llmqType) + // t.Logf("extension: %X\n", extension) + // t.Logf("sign requestID: %X\n", requestID) + // t.Logf("quorum hash: %X\n", quorumHash) + + t.Logf("RESULT: sign hash: %X", signItem.SignHash) + if len(tc.expectedSignHash) > 0 { + assert.EqualValues(t, tc.expectedSignHash, signItem.SignHash, "sign hash mismatch") + } + if len(tc.expectedRequestID) > 0 { + t.Logf("requestID: %s", hex.EncodeToString(tc.requestID)) + assert.EqualValues(t, tc.expectedRequestID, signItem.ID, "sign request id mismatch") + } + if len(tc.expectedMsgHash) > 0 { + assert.EqualValues(t, tc.expectedMsgHash, signItem.MsgHash, "msg hash mismatch") + } + + if len(tc.quorumSig) > 0 { + require.Len(t, tc.quorumPubKey, bls12381.PubKeySize) + pubKey := bls12381.PubKey(tc.quorumPubKey) + require.NoError(t, pubKey.Validate(), "invalid public key") + assert.True(t, pubKey.VerifySignatureDigest(signItem.SignHash, tc.quorumSig), "signature verification failed") + } + }) + } + +} From 638d475c606ac59ee719a7c183cd954289eecf8c Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 29 Jan 2024 10:00:27 +0100 Subject: [PATCH 45/55] test: vote extension test fix --- crypto/quorum.go | 18 ++++-------------- types/vote_extension.go | 3 +++ types/vote_test.go | 23 +++++++++++++++-------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/crypto/quorum.go b/crypto/quorum.go index 3225d860b2..bc9cccc07b 100644 --- a/crypto/quorum.go +++ b/crypto/quorum.go @@ -104,16 +104,6 @@ func (i *SignItem) UpdateSignHash(reverse bool) { messageHash = tmbytes.Reverse(messageHash) } - // if testing.Testing() { - // fmt.Printf("generating sign ID using bls.BuildSignHash for %d %X %X %X\n", llmqType, quorumHash, requestID, messageHash) - // out := append([]byte{byte(llmqType)}, quorumHash...) - // out = append(out, requestID...) - // out = append(out, messageHash...) - - // fmt.Printf("data before sha256: %X\n", out) - // fmt.Printf("sha256(sha256(data)): %X\n", crypto.Checksum((crypto.Checksum(out)))) - // } - var blsQuorumHash bls.Hash copy(blsQuorumHash[:], quorumHash) @@ -123,10 +113,10 @@ func (i *SignItem) UpdateSignHash(reverse bool) { var blsMessageHash bls.Hash copy(blsMessageHash[:], messageHash) - fmt.Printf("LlmqType: %x + ", llmqType) - fmt.Printf("QuorumHash: %x + ", blsQuorumHash) - fmt.Printf("RequestID: %x + ", blsRequestID) - fmt.Printf("MsgHash: %x\n", blsMessageHash) + // fmt.Printf("LlmqType: %x + ", llmqType) + // fmt.Printf("QuorumHash: %x + ", blsQuorumHash) + // fmt.Printf("RequestID: %x + ", blsRequestID) + // fmt.Printf("MsgHash: %x\n", blsMessageHash) blsSignHash := bls.BuildSignHash(uint8(llmqType), blsQuorumHash, blsRequestID, blsMessageHash) diff --git a/types/vote_extension.go b/types/vote_extension.go index 1f06eacebb..8266c83493 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -448,6 +448,9 @@ func (e ThresholdRawVoteExtension) Copy() VoteExtensionIf { return &ThresholdRawVoteExtension{ThresholdVoteExtension: *inner} } +// SignItem creates a SignItem for a threshold raw vote extension +// +// Note: signItem.Msg left empty by purpose, as we don't want hash to be checked in Verify() func (e ThresholdRawVoteExtension) SignItem(_ string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) { var signRequestID []byte var err error diff --git a/types/vote_test.go b/types/vote_test.go index 3657d45c28..1dd1847440 100644 --- a/types/vote_test.go +++ b/types/vote_test.go @@ -345,7 +345,7 @@ func TestVoteExtension(t *testing.T) { XSignRequestId: &tmproto.VoteExtension_SignRequestId{ SignRequestId: []byte("\x06plwdtx"), }, - Extension: []byte("extension")}), + Extension: bytes.Repeat([]byte("extensio"), 4)}), // must be 32 bytes includeSignature: true, expectError: false, }, @@ -356,7 +356,7 @@ func TestVoteExtension(t *testing.T) { XSignRequestId: &tmproto.VoteExtension_SignRequestId{ SignRequestId: []byte("dpevote"), }, - Extension: []byte("extension")}), + Extension: bytes.Repeat([]byte("extensio"), 4)}), // must be 32 bytes includeSignature: true, expectError: false, }, @@ -684,22 +684,29 @@ func TestVoteExtensionsSignBytes(t *testing.T) { // // Given some vote extension, SignBytes or THRESHOLD_RECOVER_RAW returns that extension. func TestVoteExtensionsSignBytesRaw(t *testing.T) { - expect := []byte{1, 2, 3, 4, 5, 6, 7, 8} + extension := bytes.Repeat([]byte{1, 2, 3, 4, 5, 6, 7, 8}, 4) + quorumHash := bytes.Repeat([]byte{8, 7, 6, 5, 4, 3, 2, 1}, 4) + expectedSignHash := []byte{0xe, 0x88, 0x8d, 0xa8, 0x97, 0xf1, 0xc0, 0xfd, 0x6a, 0xe8, 0x3b, 0x77, 0x9b, 0x5, 0xdd, + 0x28, 0xc, 0xe2, 0x58, 0xf6, 0x4c, 0x86, 0x1, 0x34, 0xfa, 0x4, 0x27, 0xe1, 0xaa, 0xab, 0x1a, 0xde} + + assert.Len(t, extension, 32) + ve := tmproto.VoteExtension{ - Extension: expect, + Extension: extension, Signature: []byte{}, Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, XSignRequestId: &tmproto.VoteExtension_SignRequestId{ SignRequestId: []byte("dpevote-someSignRequestID"), }, } - signItem, err := VoteExtensionFromProto(ve).SignItem("some-chain", 1, 2, btcjson.LLMQType_TEST_PLATFORM, crypto.RandQuorumHash()) + + signItem, err := VoteExtensionFromProto(ve).SignItem("some-chain", 1, 2, btcjson.LLMQType_TEST_PLATFORM, quorumHash) assert.NoError(t, err) - actual := signItem.Msg + actual := signItem.SignHash - t.Logf("sign bytes: %x", actual) - assert.EqualValues(t, expect, actual) + t.Logf("sign hash: %x", actual) + assert.EqualValues(t, expectedSignHash, actual) } func TestVoteProtobuf(t *testing.T) { From 8bdd48d0e44aba21a205631643417f63125af5ee Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 29 Jan 2024 15:20:45 +0100 Subject: [PATCH 46/55] =?UTF-8?q?test(consensus):=20fix=C2=A0vote=20extens?= =?UTF-8?q?ion=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/consensus/common_test.go | 5 - internal/consensus/state_test.go | 153 ++++++++++++------------- internal/consensus/vote_signer_test.go | 8 +- types/evidence_test.go | 2 +- types/quorum.go | 9 +- types/signs_recoverer.go | 4 +- types/vote_extension.go | 13 ++- 7 files changed, 95 insertions(+), 99 deletions(-) diff --git a/internal/consensus/common_test.go b/internal/consensus/common_test.go index f1f3c5ed3d..37d0364d01 100644 --- a/internal/consensus/common_test.go +++ b/internal/consensus/common_test.go @@ -158,11 +158,6 @@ func signVote( quorumType btcjson.LLMQType, quorumHash crypto.QuorumHash) *types.Vote { exts := make(types.VoteExtensions, 0) - if voteType == tmproto.PrecommitType && !blockID.IsNil() { - exts.Add(tmproto.VoteExtension{ - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Extension: []byte("extension")}) - } v, err := vs.signVote(ctx, voteType, chainID, blockID, quorumType, quorumHash, exts) require.NoError(t, err, "failed to sign vote") diff --git a/internal/consensus/state_test.go b/internal/consensus/state_test.go index 7473f7220b..3f29c386d7 100644 --- a/internal/consensus/state_test.go +++ b/internal/consensus/state_test.go @@ -3,6 +3,7 @@ package consensus import ( "bytes" "context" + "fmt" "reflect" "strconv" "testing" @@ -2141,12 +2142,10 @@ func TestExtendVote(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - voteExtensions := []*abci.ExtendVoteExtension{ - { - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Extension: []byte("extension"), - }, - } + voteExtensions := types.VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("extension"), + }) m := abcimocks.NewApplication(t) m.On("ProcessProposal", mock.Anything, mock.Anything).Return(&abci.ResponseProcessProposal{ @@ -2200,14 +2199,14 @@ func TestExtendVote(t *testing.T) { assert.Equal(t, req.Round, round) }) m.On("ExtendVote", mock.Anything, reqExtendVoteFunc).Return(&abci.ResponseExtendVote{ - VoteExtensions: voteExtensions, + VoteExtensions: voteExtensions.ToExtendProto(), }, nil) reqVerifyVoteExtFunc := mock.MatchedBy(func(req *abci.RequestVerifyVoteExtension) bool { _, ok := proTxHashMap[types.ProTxHash(req.ValidatorProTxHash).String()] - return assert.Equal(t, req.Hash, blockID.Hash.Bytes()) && - assert.Equal(t, req.Height, height) && - assert.Equal(t, req.Round, round) && - assert.Equal(t, req.VoteExtensions, voteExtensions) && + return assert.Equal(t, blockID.Hash.Bytes(), req.Hash) && + assert.Equal(t, height, req.Height) && + assert.Equal(t, round, req.Round) && + assert.Equal(t, voteExtensions.ToExtendProto(), req.VoteExtensions) && assert.True(t, ok) }) m.On("VerifyVoteExtension", mock.Anything, reqVerifyVoteExtFunc). @@ -2218,7 +2217,7 @@ func TestExtendVote(t *testing.T) { ensurePrevoteMatch(t, voteCh, height, round, blockID.Hash) ensurePrecommit(t, voteCh, height, round) - signAddVotes(ctx, t, cs1, tmproto.PrecommitType, config.ChainID(), blockID, vss[1:]...) + signAddPrecommitsWithExtension(ctx, t, cs1, config.ChainID(), blockID, voteExtensions, vss[1:]...) ensureNewRound(t, newRoundCh, height+1, 0) m.AssertExpectations(t) mock.AssertExpectationsForObjects(t, m) @@ -2302,12 +2301,11 @@ func TestVerifyVoteExtensionNotCalledOnAbsentPrecommit(t *testing.T) { config := configSetup(t) ctx, cancel := context.WithCancel(context.Background()) defer cancel() - voteExtensions := []*abci.ExtendVoteExtension{ - { - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Extension: []byte("extension"), - }, - } + voteExtensions := types.VoteExtensionsFromProto(&tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("extension"), + }) + m := abcimocks.NewApplication(t) m.On("ProcessProposal", mock.Anything, mock.Anything).Return(&abci.ResponseProcessProposal{ AppHash: make([]byte, crypto.DefaultAppHashSize), @@ -2317,7 +2315,7 @@ func TestVerifyVoteExtensionNotCalledOnAbsentPrecommit(t *testing.T) { AppHash: make([]byte, crypto.DefaultAppHashSize), }, nil) m.On("ExtendVote", mock.Anything, mock.Anything).Return(&abci.ResponseExtendVote{ - VoteExtensions: voteExtensions, + VoteExtensions: voteExtensions.ToExtendProto(), }, nil) m.On("FinalizeBlock", mock.Anything, mock.Anything).Return(&abci.ResponseFinalizeBlock{}, nil).Maybe() cs1, vss := makeState(ctx, t, makeStateArgs{config: config, application: m}) @@ -2355,10 +2353,10 @@ func TestVerifyVoteExtensionNotCalledOnAbsentPrecommit(t *testing.T) { }) reqVerifyVoteExtFunc := mock.MatchedBy(func(req *abci.RequestVerifyVoteExtension) bool { _, ok := proTxHashMap[types.ProTxHash(req.ValidatorProTxHash).String()] - return assert.Equal(t, req.Hash, blockID.Hash.Bytes()) && - assert.Equal(t, req.Height, height) && - assert.Equal(t, req.Round, round) && - assert.Equal(t, req.VoteExtensions, voteExtensions) && + return assert.Equal(t, blockID.Hash.Bytes(), req.Hash) && + assert.Equal(t, height, req.Height) && + assert.Equal(t, round, req.Round) && + assert.Equal(t, voteExtensions.ToExtendProto(), req.VoteExtensions) && assert.True(t, ok) }) m.On("VerifyVoteExtension", mock.Anything, reqVerifyVoteExtFunc). @@ -2366,7 +2364,7 @@ func TestVerifyVoteExtensionNotCalledOnAbsentPrecommit(t *testing.T) { Status: abci.ResponseVerifyVoteExtension_ACCEPT, }, nil) - signAddVotes(ctx, t, cs1, tmproto.PrecommitType, config.ChainID(), blockID, vss[2:]...) + signAddPrecommitsWithExtension(ctx, t, cs1, config.ChainID(), blockID, voteExtensions, vss[2:]...) ensureNewRound(t, newRoundCh, height+1, 0) m.AssertExpectations(t) @@ -2392,7 +2390,7 @@ func TestVerifyVoteExtensionNotCalledOnAbsentPrecommit(t *testing.T) { // TestPrepareProposalReceivesVoteExtensions tests that the PrepareProposal method // is called with the vote extensions from the previous height. The test functions // be completing a consensus height with a mock application as the proposer. The -// test then proceeds to fail sever rounds of consensus until the mock application +// test then proceeds to fail several rounds of consensus until the mock application // is the proposer again and ensures that the mock application receives the set of // vote extensions from the previous consensus instance. func TestPrepareProposalReceivesVoteExtensions(t *testing.T) { @@ -2401,53 +2399,56 @@ func TestPrepareProposalReceivesVoteExtensions(t *testing.T) { config := configSetup(t) + voteExtensions := types.VoteExtensionsFromProto( + &tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, + Extension: crypto.Checksum([]byte("extension-raw")), + }, &tmproto.VoteExtension{ + Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, + Extension: []byte("deterministic"), + }, + ) + m := &abcimocks.Application{} m.On("ExtendVote", mock.Anything, mock.Anything).Return(&abci.ResponseExtendVote{ - VoteExtensions: []*abci.ExtendVoteExtension{ - { - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, - Extension: crypto.Checksum([]byte("extension-raw")), - }, - { - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Extension: []byte("deterministic"), - }, - }, + VoteExtensions: voteExtensions.ToExtendProto(), }, nil) m.On("ProcessProposal", mock.Anything, mock.Anything).Return(&abci.ResponseProcessProposal{ AppHash: make([]byte, crypto.DefaultAppHashSize), Status: abci.ResponseProcessProposal_ACCEPT, }, nil) - // capture the prepare proposal request. - rpp := &abci.RequestPrepareProposal{} + // matcher for prepare proposal request m.On("PrepareProposal", mock.Anything, mock.MatchedBy(func(r *abci.RequestPrepareProposal) bool { - rpp = r - return true + if r.Height == 1 { + return assert.Empty(t, r.GetLocalLastCommit().ThresholdVoteExtensions, "no vote extensions should be present on the first height") + } + + // at height 2, we expect the vote extensions from the previous height to be present. + extensions := make([][]byte, 0) + for _, ext := range r.GetLocalLastCommit().ThresholdVoteExtensions { + extensions = append(extensions, ext.Extension) + } + return assert.EqualValues(t, 2, r.Height) && + assert.EqualValues(t, 3, r.Round) && + assert.Len(t, r.GetLocalLastCommit().ThresholdVoteExtensions, 2, "expected 2 vote extensions at height %d", r.Height) && + assert.EqualValues(t, voteExtensions.GetExtensions(), extensions) + })).Return(&abci.ResponsePrepareProposal{ AppHash: make([]byte, crypto.DefaultAppHashSize), }, nil) - m.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{AppHash: make([]byte, crypto.DefaultAppHashSize)}, nil).Once() m.On("VerifyVoteExtension", mock.Anything, mock.Anything).Return(&abci.ResponseVerifyVoteExtension{Status: abci.ResponseVerifyVoteExtension_ACCEPT}, nil) - // no vote extensions are present - m.On("FinalizeBlock", mock.Anything, mock.MatchedBy(func(r *abci.RequestFinalizeBlock) bool { - return len(r.Commit.ThresholdVoteExtensions) == 0 - })).Return(&abci.ResponseFinalizeBlock{}, nil) - - // we expect 2 threshold-recovered vote extensions + // We expect 2 threshold-recovered vote extensions in current Commit m.On("FinalizeBlock", mock.Anything, mock.MatchedBy(func(r *abci.RequestFinalizeBlock) bool { - if len(r.Commit.ThresholdVoteExtensions) != 0 { - return false - } - t.Logf("FinalizeBlock with %d vote extensions", len(r.Commit.ThresholdVoteExtensions)) - + assert.Len(t, r.Commit.ThresholdVoteExtensions, 2) vexts := r.Commit.ThresholdVoteExtensions - return bytes.Equal(vexts[0].Extension, []byte("deterministic")) && - bytes.Equal(vexts[1].Extension, crypto.Checksum([]byte("raw"))) - })).Return(&abci.ResponseFinalizeBlock{}, nil).Once() + return bytes.Equal(vexts[0].Extension, voteExtensions[0].GetExtension()) && + bytes.Equal(vexts[1].Extension, voteExtensions[1].GetExtension()) + + })).Return(&abci.ResponseFinalizeBlock{}, nil) cs1, vss := makeState(ctx, t, makeStateArgs{config: config, application: m}) stateData := cs1.GetStateData() @@ -2469,24 +2470,7 @@ func TestPrepareProposalReceivesVoteExtensions(t *testing.T) { signAddVotes(ctx, t, cs1, tmproto.PrevoteType, config.ChainID(), blockID, vss[1:]...) // create a precommit for each validator with the associated vote extension. - for _, vs := range vss[1:] { - voteExtensions := tmproto.VoteExtensions{ - { - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Extension: []byte("extension"), - }, - { - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER, - Extension: []byte("deterministic"), - }, - { - Type: tmproto.VoteExtensionType_THRESHOLD_RECOVER_RAW, - Extension: crypto.Checksum([]byte("raw")), - }, - } - - signAddPrecommitWithExtension(ctx, t, cs1, config.ChainID(), blockID, types.VoteExtensionsFromProto(voteExtensions...), vs) - } + signAddPrecommitsWithExtension(ctx, t, cs1, config.ChainID(), blockID, voteExtensions, vss[1:]...) ensurePrevote(t, voteCh, height, round) @@ -2506,9 +2490,6 @@ func TestPrepareProposalReceivesVoteExtensions(t *testing.T) { ensureNewRound(t, newRoundCh, height, round) ensureNewProposal(t, proposalCh, height, round) - // ensure that the proposer received the list of vote extensions from the - // previous height. - require.Len(t, rpp.LocalLastCommit.ThresholdVoteExtensions, 1) m.AssertExpectations(t) } @@ -3307,18 +3288,28 @@ func subscribe( return ch } -func signAddPrecommitWithExtension(ctx context.Context, +func signAddPrecommitsWithExtension(ctx context.Context, t *testing.T, cs *State, chainID string, blockID types.BlockID, extensions types.VoteExtensions, - stub *validatorStub) { + vss ...*validatorStub) { _, valSet := cs.GetValidatorSet() - v, err := stub.signVote(ctx, tmproto.PrecommitType, chainID, blockID, valSet.QuorumType, - valSet.QuorumHash, extensions) - require.NoError(t, err, "failed to sign vote") - addVotes(cs, v) + votes := make([]*types.Vote, 0, len(vss)) + + for _, vs := range vss { + v, err := vs.signVote(ctx, tmproto.PrecommitType, chainID, blockID, valSet.QuorumType, + valSet.QuorumHash, extensions.Copy()) + require.NoError(t, err, "failed to sign vote") + vs.lastVote = v + votes = append(votes, v) + + protx, _ := vs.GetProTxHash(ctx) + q, _ := vs.GetPubKey(ctx, valSet.QuorumHash) + fmt.Printf("signAddPrecommitsWithExtension: pubkey: %X, sigs %X, val protxhash(%d): %X\n", q.Bytes(), v.VoteExtensions.GetSignatures(), vs.Index, protx) + } + addVotes(cs, votes...) } // mockProposerApplicationCalls configures mock Application `m` to support calls executed for each round on the proposer. diff --git a/internal/consensus/vote_signer_test.go b/internal/consensus/vote_signer_test.go index c21b18e1fb..614352da39 100644 --- a/internal/consensus/vote_signer_test.go +++ b/internal/consensus/vote_signer_test.go @@ -87,25 +87,25 @@ func TestVoteSigner_signAddVote(t *testing.T) { { msgType: tmproto.PrevoteType, blockID: blockID, - wantBlockSign: "8400E1599EB8E954C7DBE069B14941B71E010D92F4999B4A64752AF1969EE9AF140F953A40F212F0E63C4EF92C5F9BDA1930D753B1522183C7EA46EC847C9053FE4AFAEA17B60C263F015380497B64F4CE2480D01CB4DE9A64F9C8E048472CF2", + wantBlockSign: "8B52677D4D455125808EDEE715D2A999695A6701E477C1F44CEDCCE3FC62FB88698D0B6B3CA0429E17EDA9DBCEA932720C189E21F5A6FB31B2C244152F0CD7988598AD572E5D605164554C80880BDC130E23C9DBEF20CF315D05F8C13B6C92CC", }, { msgType: tmproto.PrecommitType, - wantBlockSign: "88AB6D08FC3E9D258A1CB78288EF00E49F245A4E9AF5CAFF0DBEBDB31CB0098D7B4A93424681F1747686163938CE6647023424C47E7ED5656F33693D112853D6483CE795F788ED3A657F74B58C2215CA056324EC33DF6C44608DA65B13563224", + wantBlockSign: "97CCF337D8FCA05E600EAAF769D73BE9A0D1466CAE85374E9E0EF4C3DD1759131E1D2C8B9E8D8D28EBEF27074669D46C0820DF4DA337DFFA6B3EB5BEEA4B78CA8EA131ED584609D227025DB96990C732C2D04A693BC0402B8A19229ED32A51B8", }, { msgType: tmproto.PrecommitType, blockID: blockID, voteExtensions: nil, mockFn: mockFn, - wantBlockSign: "B89D8AB4B59B4285A05C59C7C2641EF64DBB1A68C99F55FB2716EE25CDA264A0F87D02767EEBA7124E926325CE36D96D157674633C229D8BFCD8CB039889700D87A2041CF9D44A3D0BC2F231E64EB3815199DCB70184BCDC8CAC593AF3C3FE5F", + wantBlockSign: "9755FA9803D98C344CB16A43B782D2A93ED9A7E7E1C8437482F42781D5EF802EC82442C14C44429737A7355B1F9D87CB139EB2CF193A1CF7C812E38B99221ADF4DAA60CE16550ED6509A9C467A3D4492D77038505235796968465337A1E14B3E", }, { msgType: tmproto.PrecommitType, blockID: blockID, voteExtensions: types.VoteExtensionsFromProto(voteExtensions...), mockFn: mockFn, - wantBlockSign: "B89D8AB4B59B4285A05C59C7C2641EF64DBB1A68C99F55FB2716EE25CDA264A0F87D02767EEBA7124E926325CE36D96D157674633C229D8BFCD8CB039889700D87A2041CF9D44A3D0BC2F231E64EB3815199DCB70184BCDC8CAC593AF3C3FE5F", + wantBlockSign: "9755FA9803D98C344CB16A43B782D2A93ED9A7E7E1C8437482F42781D5EF802EC82442C14C44429737A7355B1F9D87CB139EB2CF193A1CF7C812E38B99221ADF4DAA60CE16550ED6509A9C467A3D4492D77038505235796968465337A1E14B3E", }, } for i, tc := range testCases { diff --git a/types/evidence_test.go b/types/evidence_test.go index 7b6c007078..edee9d7248 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -302,7 +302,7 @@ func TestEvidenceVectors(t *testing.T) { }{ {"duplicateVoteEvidence", EvidenceList{&DuplicateVoteEvidence{VoteA: v2, VoteB: v}}, - "c031e2c89a40678572c2353a302d7823b968e0470384471481e0aadd95e4f8c0", + "87904f3525bfdb8474a18bc44fcadf76f63f0e7cabc3063f5eae8dcf0eb11d79", }, } diff --git a/types/quorum.go b/types/quorum.go index 46e1604572..367e28f9e2 100644 --- a/types/quorum.go +++ b/types/quorum.go @@ -150,8 +150,13 @@ func (q *QuorumSingsVerifier) verifyVoteExtensions( for i, sig := range thresholdSigs { if !pubKey.VerifySignatureDigest(signItems[i].SignHash, sig) { - return fmt.Errorf("vote-extension %d signature is invalid: raw %X, signature %X", i, - signItems[i].Msg, sig) + return fmt.Errorf("vote-extension %d signature is invalid: raw %X, signature %X, pubkey %X, sigHash: %X", + i, + signItems[i].Msg, + sig, + pubKey.Bytes(), + signItems[i].SignHash, + ) } } return nil diff --git a/types/signs_recoverer.go b/types/signs_recoverer.go index ec8db95476..f84e9e1edc 100644 --- a/types/signs_recoverer.go +++ b/types/signs_recoverer.go @@ -116,7 +116,8 @@ func (v *SignsRecoverer) addVoteExtensionSigs(vote *Vote) { } if len(vote.VoteExtensions) != len(v.voteExtensions) { - panic(fmt.Sprintf("received vote extensions with different length: current %d, new %d", len(v.voteExtensions), len(v.voteExtensions))) + panic(fmt.Sprintf("received vote extensions with different length: current %d, received %d", + len(v.voteExtensions), len(vote.VoteExtensions))) } // append signatures from this vote to each extension @@ -125,6 +126,7 @@ func (v *SignsRecoverer) addVoteExtensionSigs(vote *Vote) { if err := recoverable.AddThresholdSignature(vote.ValidatorProTxHash, ext.GetSignature()); err != nil { panic(fmt.Errorf("failed to add vote %s to recover vote extension threshold sig: %w", vote.String(), err)) } + v.voteExtensions[i] = recoverable } } } diff --git a/types/vote_extension.go b/types/vote_extension.go index 8266c83493..b59497e0d7 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -118,10 +118,6 @@ func (e VoteExtensions) ToExtendProto() []*abci.ExtendVoteExtension { proto := make([]*abci.ExtendVoteExtension, 0, e.Len()) for _, ext := range e { - if err := ext.Validate(); err != nil { - panic(fmt.Errorf("invalid vote extension %v: %w", ext, err)) - } - pb := ext.ToProto() eve := &abci.ExtendVoteExtension{ Type: pb.Type, @@ -164,6 +160,10 @@ func (e VoteExtensions) Fingerprint() []byte { // IsSameWithProto compares the current state of the vote-extension with the same in VoteExtensions's protobuf // checks only the value of extensions func (e VoteExtensions) IsSameWithProto(right tmproto.VoteExtensions) bool { + if len(e) != len(right) { + return false + } + for t, ext := range e { pb := ext.ToProto() other := right[t] @@ -278,6 +278,8 @@ type VoteExtensionIf interface { ToProto() tmproto.VoteExtension SignItem(chainID string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) IsThresholdRecoverable() bool + // Validate returns error if a vote-extension is invalid. + // It should not modify the state of the vote-extension. Validate() error SetSignature(sig []byte) @@ -409,6 +411,7 @@ func (e *ThresholdVoteExtension) AddThresholdSignature(validator ProTxHash, sig return nil } +// ThresholdRecover recovers threshold signature from collected signatures func (e *ThresholdVoteExtension) ThresholdRecover() ([]byte, error) { proTxHashes := make([][]byte, 0, len(e.thresholdSignatures)) signatures := make([][]byte, 0, len(e.thresholdSignatures)) @@ -416,7 +419,7 @@ func (e *ThresholdVoteExtension) ThresholdRecover() ([]byte, error) { // collect signatures and proTxHashes for proTxHash, signature := range e.thresholdSignatures { if len(signature) != bls12381.SignatureSize { - return nil, fmt.Errorf("invalid vote extension signature from validator %s: got %d, expected %d", + return nil, fmt.Errorf("invalid vote extension signature len from validator %s: got %d, expected %d", proTxHash, len(signature), bls12381.SignatureSize) } From e0c9d56a77c8df2b5666f6ec592f849353d4f644 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 29 Jan 2024 15:25:13 +0100 Subject: [PATCH 47/55] chore: update protobuf --- abci/types/types.pb.go | 2 + spec/abci++/api.md | 183 ++++++++++++++++------------------------- 2 files changed, 75 insertions(+), 110 deletions(-) diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 7ed1b1a00e..9d6b484742 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -3073,6 +3073,8 @@ type ExtendVoteExtension struct { // The Tenderdash supports only THRESHOLD_RECOVER and THRESHOLD_RECOVER_RAW at this moment. Type types1.VoteExtensionType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.types.VoteExtensionType" json:"type,omitempty"` // Deterministic or (Non-Deterministic) extension provided by the sending validator's Application. + // + // For THRESHOLD_RECOVER_RAW, it MUST be 32 bytes. Extension []byte `protobuf:"bytes,2,opt,name=extension,proto3" json:"extension,omitempty"` // Types that are valid to be assigned to XSignRequestId: // diff --git a/spec/abci++/api.md b/spec/abci++/api.md index 6c8579af66..19b0f4945f 100644 --- a/spec/abci++/api.md +++ b/spec/abci++/api.md @@ -1,78 +1,70 @@ # Protocol Documentation - ## Table of Contents -1. [Table of Contents](#table-of-contents) -2. [tendermint/abci/types.proto](#tendermintabcitypesproto) - 1. [CommitInfo](#commitinfo) - 2. [Event](#event) - 3. [EventAttribute](#eventattribute) - 4. [ExecTxResult](#exectxresult) - 5. [ExtendVoteExtension](#extendvoteextension) - 6. [ExtendedVoteInfo](#extendedvoteinfo) - 7. [Misbehavior](#misbehavior) - 8. [QuorumHashUpdate](#quorumhashupdate) - 9. [Request](#request) - 10. [RequestApplySnapshotChunk](#requestapplysnapshotchunk) - 11. [RequestCheckTx](#requestchecktx) - 12. [RequestEcho](#requestecho) - 13. [RequestExtendVote](#requestextendvote) - 1. [Usage](#usage) - 2. [When does Tenderdash call it?](#when-does-tenderdash-call-it) - 14. [RequestFinalizeBlock](#requestfinalizeblock) - 1. [Usage](#usage-1) - 15. [RequestFlush](#requestflush) - 16. [RequestInfo](#requestinfo) - 17. [RequestInitChain](#requestinitchain) - 18. [RequestListSnapshots](#requestlistsnapshots) - 19. [RequestLoadSnapshotChunk](#requestloadsnapshotchunk) - 20. [RequestOfferSnapshot](#requestoffersnapshot) - 21. [RequestPrepareProposal](#requestprepareproposal) - 1. [Usage](#usage-2) - 2. [When does Tenderdash call it?](#when-does-tenderdash-call-it-1) - 22. [RequestProcessProposal](#requestprocessproposal) - 1. [Usage](#usage-3) - 2. [When does Tenderdash call it?](#when-does-tenderdash-call-it-2) - 23. [RequestQuery](#requestquery) - 24. [RequestVerifyVoteExtension](#requestverifyvoteextension) - 1. [Usage](#usage-4) - 2. [When does Tenderdash call it?](#when-does-tenderdash-call-it-3) - 25. [Response](#response) - 26. [ResponseApplySnapshotChunk](#responseapplysnapshotchunk) - 27. [ResponseCheckTx](#responsechecktx) - 28. [ResponseEcho](#responseecho) - 29. [ResponseException](#responseexception) - 30. [ResponseExtendVote](#responseextendvote) - 31. [ResponseFinalizeBlock](#responsefinalizeblock) - 32. [ResponseFlush](#responseflush) - 33. [ResponseInfo](#responseinfo) - 34. [ResponseInitChain](#responseinitchain) - 35. [ResponseListSnapshots](#responselistsnapshots) - 36. [ResponseLoadSnapshotChunk](#responseloadsnapshotchunk) - 37. [ResponseOfferSnapshot](#responseoffersnapshot) - 38. [ResponsePrepareProposal](#responseprepareproposal) - 39. [ResponseProcessProposal](#responseprocessproposal) - 40. [ResponseQuery](#responsequery) - 41. [ResponseVerifyVoteExtension](#responseverifyvoteextension) - 42. [Snapshot](#snapshot) - 43. [ThresholdPublicKeyUpdate](#thresholdpublickeyupdate) - 44. [TxRecord](#txrecord) - 45. [TxResult](#txresult) - 46. [Validator](#validator) - 47. [ValidatorSetUpdate](#validatorsetupdate) - 48. [ValidatorUpdate](#validatorupdate) - 49. [VoteInfo](#voteinfo) - 50. [CheckTxType](#checktxtype) - 51. [MisbehaviorType](#misbehaviortype) - 52. [ResponseApplySnapshotChunk.Result](#responseapplysnapshotchunkresult) - 53. [ResponseOfferSnapshot.Result](#responseoffersnapshotresult) - 54. [ResponseProcessProposal.ProposalStatus](#responseprocessproposalproposalstatus) - 55. [ResponseVerifyVoteExtension.VerifyStatus](#responseverifyvoteextensionverifystatus) - 56. [TxRecord.TxAction](#txrecordtxaction) - 57. [ABCIApplication](#abciapplication) -3. [Scalar Value Types](#scalar-value-types) +- [tendermint/abci/types.proto](#tendermint_abci_types-proto) + - [CommitInfo](#tendermint-abci-CommitInfo) + - [Event](#tendermint-abci-Event) + - [EventAttribute](#tendermint-abci-EventAttribute) + - [ExecTxResult](#tendermint-abci-ExecTxResult) + - [ExtendVoteExtension](#tendermint-abci-ExtendVoteExtension) + - [ExtendedVoteInfo](#tendermint-abci-ExtendedVoteInfo) + - [Misbehavior](#tendermint-abci-Misbehavior) + - [QuorumHashUpdate](#tendermint-abci-QuorumHashUpdate) + - [Request](#tendermint-abci-Request) + - [RequestApplySnapshotChunk](#tendermint-abci-RequestApplySnapshotChunk) + - [RequestCheckTx](#tendermint-abci-RequestCheckTx) + - [RequestEcho](#tendermint-abci-RequestEcho) + - [RequestExtendVote](#tendermint-abci-RequestExtendVote) + - [RequestFinalizeBlock](#tendermint-abci-RequestFinalizeBlock) + - [RequestFlush](#tendermint-abci-RequestFlush) + - [RequestInfo](#tendermint-abci-RequestInfo) + - [RequestInitChain](#tendermint-abci-RequestInitChain) + - [RequestListSnapshots](#tendermint-abci-RequestListSnapshots) + - [RequestLoadSnapshotChunk](#tendermint-abci-RequestLoadSnapshotChunk) + - [RequestOfferSnapshot](#tendermint-abci-RequestOfferSnapshot) + - [RequestPrepareProposal](#tendermint-abci-RequestPrepareProposal) + - [RequestProcessProposal](#tendermint-abci-RequestProcessProposal) + - [RequestQuery](#tendermint-abci-RequestQuery) + - [RequestVerifyVoteExtension](#tendermint-abci-RequestVerifyVoteExtension) + - [Response](#tendermint-abci-Response) + - [ResponseApplySnapshotChunk](#tendermint-abci-ResponseApplySnapshotChunk) + - [ResponseCheckTx](#tendermint-abci-ResponseCheckTx) + - [ResponseEcho](#tendermint-abci-ResponseEcho) + - [ResponseException](#tendermint-abci-ResponseException) + - [ResponseExtendVote](#tendermint-abci-ResponseExtendVote) + - [ResponseFinalizeBlock](#tendermint-abci-ResponseFinalizeBlock) + - [ResponseFlush](#tendermint-abci-ResponseFlush) + - [ResponseInfo](#tendermint-abci-ResponseInfo) + - [ResponseInitChain](#tendermint-abci-ResponseInitChain) + - [ResponseListSnapshots](#tendermint-abci-ResponseListSnapshots) + - [ResponseLoadSnapshotChunk](#tendermint-abci-ResponseLoadSnapshotChunk) + - [ResponseOfferSnapshot](#tendermint-abci-ResponseOfferSnapshot) + - [ResponsePrepareProposal](#tendermint-abci-ResponsePrepareProposal) + - [ResponseProcessProposal](#tendermint-abci-ResponseProcessProposal) + - [ResponseQuery](#tendermint-abci-ResponseQuery) + - [ResponseVerifyVoteExtension](#tendermint-abci-ResponseVerifyVoteExtension) + - [Snapshot](#tendermint-abci-Snapshot) + - [ThresholdPublicKeyUpdate](#tendermint-abci-ThresholdPublicKeyUpdate) + - [TxRecord](#tendermint-abci-TxRecord) + - [TxResult](#tendermint-abci-TxResult) + - [Validator](#tendermint-abci-Validator) + - [ValidatorSetUpdate](#tendermint-abci-ValidatorSetUpdate) + - [ValidatorUpdate](#tendermint-abci-ValidatorUpdate) + - [VoteInfo](#tendermint-abci-VoteInfo) + + - [CheckTxType](#tendermint-abci-CheckTxType) + - [MisbehaviorType](#tendermint-abci-MisbehaviorType) + - [ResponseApplySnapshotChunk.Result](#tendermint-abci-ResponseApplySnapshotChunk-Result) + - [ResponseOfferSnapshot.Result](#tendermint-abci-ResponseOfferSnapshot-Result) + - [ResponseProcessProposal.ProposalStatus](#tendermint-abci-ResponseProcessProposal-ProposalStatus) + - [ResponseVerifyVoteExtension.VerifyStatus](#tendermint-abci-ResponseVerifyVoteExtension-VerifyStatus) + - [TxRecord.TxAction](#tendermint-abci-TxRecord-TxAction) + + - [ABCIApplication](#tendermint-abci-ABCIApplication) + +- [Scalar Value Types](#scalar-value-types) @@ -104,7 +96,6 @@ ### Event - Event allows application developers to attach additional information to ResponseCheckTx, ResponsePrepareProposal, ResponseProcessProposal and ResponseFinalizeBlock. @@ -125,7 +116,6 @@ Later, transactions may be queried using these events. ### EventAttribute - EventAttribute is a single key-value pair, associated with an event. @@ -143,7 +133,6 @@ EventAttribute is a single key-value pair, associated with an event. ### ExecTxResult - ExecTxResult contains results of executing one individual transaction. @@ -166,7 +155,6 @@ ExecTxResult contains results of executing one individual transaction. ### ExtendVoteExtension - Provides a vote extension for signing. `type` and `extension` fields are mandatory for filling @@ -175,12 +163,14 @@ Provides a vote extension for signing. `type` and `extension` fields are mandato | type | [tendermint.types.VoteExtensionType](#tendermint-types-VoteExtensionType) | | Vote extension type can be either DEFAULT, THRESHOLD_RECOVER or THRESHOLD_RECOVER_RAW. The Tenderdash supports only THRESHOLD_RECOVER and THRESHOLD_RECOVER_RAW at this moment. | | extension | [bytes](#bytes) | | Deterministic or (Non-Deterministic) extension provided by the sending validator's Application. +For THRESHOLD_RECOVER_RAW, it MUST be 32 bytes. + Sign request ID that will be used to sign the vote extensions. Only applicable for THRESHOLD_RECOVER_RAW vote extension type. Tenderdash will use SHA256 checksum of `sign_request_id` when generating quorum signatures of THRESHOLD_RECOVER_RAW vote extensions. It MUST NOT be set for any other vote extension types. | | sign_request_id | [bytes](#bytes) | optional | If not set, Tenderdash will generate it based on height and round. -If set, it SHOULD be unique per voting round, and it MUST start with `\x06dpevote` or `plwdtx` string. +If set, it SHOULD be unique per voting round, and it MUST start with `dpevote` or `\x06plwdtx` prefix. Use with caution - it can have severe security consequences. | @@ -192,7 +182,6 @@ Use with caution - it can have severe security consequences. | ### ExtendedVoteInfo - ExtendedVoteInfo @@ -219,7 +208,7 @@ ExtendedVoteInfo | validator | [Validator](#tendermint-abci-Validator) | | The offending validator | | height | [int64](#int64) | | The height when the offense occurred | | time | [google.protobuf.Timestamp](#google-protobuf-Timestamp) | | The corresponding time where the offense occurred | -| total_voting_power | [int64](#int64) | | Total voting power of the validator set in case the ABCI application does not store historical validators. | +| total_voting_power | [int64](#int64) | | Total voting power of the validator set in case the ABCI application does not store historical validators. https://github.com/tendermint/tendermint/issues/4581 | @@ -244,7 +233,6 @@ ExtendedVoteInfo ### Request - Request types @@ -274,7 +262,6 @@ Request types ### RequestApplySnapshotChunk - Applies a snapshot chunk. - The application can choose to refetch chunks and/or ban P2P peers as appropriate. @@ -303,7 +290,6 @@ Applies a snapshot chunk. ### RequestCheckTx - Check if transaction is valid. - Technically optional - not involved in processing blocks. @@ -329,7 +315,6 @@ Check if transaction is valid. ### RequestEcho - Echo a string to test an abci client/server implementation @@ -345,7 +330,6 @@ Echo a string to test an abci client/server implementation ### RequestExtendVote - Extends a vote with application-side injection #### Usage @@ -397,7 +381,6 @@ a [CanonicalVoteExtension](#canonicalvoteextension) field in the `precommit nil` ### RequestFinalizeBlock - Finalize newly decided block. #### Usage @@ -444,7 +427,6 @@ Finalize newly decided block. ### RequestFlush - Signals that messages queued on the client should be flushed to the server. It is called periodically by the client implementation to ensure asynchronous requests are actually sent, and is called immediately to make a synchronous request, @@ -458,7 +440,6 @@ which returns when the Flush response comes back. ### RequestInfo - Return information about the application state. Used to sync Tenderdash with the application during a handshake that happens on startup. @@ -482,7 +463,6 @@ ensuring that Commit is never called twice for the same block height. ### RequestInitChain - Called once upon genesis. - If ResponseInitChain.Validators is empty, the initial validator set will be the RequestInitChain.Validators @@ -511,7 +491,6 @@ Called once upon genesis. ### RequestListSnapshots - Lists available snapshots - Used during state sync to discover available snapshots on peers. @@ -525,7 +504,6 @@ Lists available snapshots ### RequestLoadSnapshotChunk - Used during state sync to retrieve snapshot chunks from peers. @@ -543,7 +521,6 @@ Used during state sync to retrieve snapshot chunks from peers. ### RequestOfferSnapshot - Offers a snapshot to the application. - OfferSnapshot is called when bootstrapping a node using state sync. The application may accept or reject snapshots @@ -569,7 +546,6 @@ Offers a snapshot to the application. ### RequestPrepareProposal - Prepare new block proposal, potentially altering list of transactions. #### Usage @@ -678,7 +654,6 @@ Note that, if _p_ has a non-`nil` _validValue_, Tenderdash will use it as propos ### RequestProcessProposal - Process prepared proposal. #### Usage @@ -749,7 +724,6 @@ When a validator _p_ enters Tenderdash consensus round _r_, height _h_, in which ### RequestQuery - Query for data from the application at current or past height. - Optionally return Merkle proof. @@ -771,7 +745,6 @@ Query for data from the application at current or past height. ### RequestVerifyVoteExtension - Verify the vote extension #### Usage @@ -795,17 +768,14 @@ When a validator _p_ is in Tenderdash consensus round _r_, height _h_, state _pr from this condition, but not sure), and _p_ receives a Precommit message for round _r_, height _h_ from _q_: 1. If the Precommit message does not contain a vote extensions with a valid signature, Tenderdash discards the message as invalid. - -- a 0-length vote extensions is valid as long as its accompanying signature is also valid. - + - a 0-length vote extensions is valid as long as its accompanying signature is also valid. 2. Else, _p_'s Tenderdash calls `RequestVerifyVoteExtension`. 3. The Application returns _accept_ or _reject_ via `ResponseVerifyVoteExtension.status`. 4. If the Application returns - -- _accept_, _p_'s Tenderdash will keep the received vote, together with its corresponding + - _accept_, _p_'s Tenderdash will keep the received vote, together with its corresponding vote extension in its internal data structures. It will be used to populate the [ExtendedCommitInfo](#extendedcommitinfo) structure in calls to `RequestPrepareProposal`, in rounds of height _h + 1_ where _p_ is the proposer. -- _reject_, _p_'s Tenderdash will deem the Precommit message invalid and discard it. + - _reject_, _p_'s Tenderdash will deem the Precommit message invalid and discard it. | Field | Type | Label | Description | @@ -908,7 +878,6 @@ from this condition, but not sure), and _p_ receives a Precommit message for rou ### ResponseException - nondeterministic @@ -1174,7 +1143,6 @@ nondeterministic ### TxResult - TxResult contains results of executing the transaction. One usage is indexing transaction results. @@ -1195,7 +1163,6 @@ One usage is indexing transaction results. ### Validator - Validator @@ -1229,7 +1196,6 @@ Validator ### ValidatorUpdate - ValidatorUpdate @@ -1248,7 +1214,6 @@ ValidatorUpdate ### VoteInfo - VoteInfo @@ -1261,13 +1226,12 @@ VoteInfo - + ### CheckTxType - Type of transaction check | Name | Number | Description | @@ -1352,7 +1316,6 @@ Type of transaction check ### TxRecord.TxAction - TxAction contains App-provided information on what to do with a transaction that is part of a raw proposal | Name | Number | Description | @@ -1364,9 +1327,9 @@ TxAction contains App-provided information on what to do with a transaction that | DELAYED | 4 | The Application wants this transaction removed from the proposal but not the mempool. | + - - + @@ -1392,7 +1355,7 @@ TxAction contains App-provided information on what to do with a transaction that | VerifyVoteExtension | [RequestVerifyVoteExtension](#tendermint-abci-RequestVerifyVoteExtension) | [ResponseVerifyVoteExtension](#tendermint-abci-ResponseVerifyVoteExtension) | | | FinalizeBlock | [RequestFinalizeBlock](#tendermint-abci-RequestFinalizeBlock) | [ResponseFinalizeBlock](#tendermint-abci-ResponseFinalizeBlock) | | - + From b6f4ca90d80387139c30ea25253561178480a4f5 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 29 Jan 2024 17:45:08 +0100 Subject: [PATCH 48/55] revert: move SignItem back to types --- abci/example/kvstore/verify.go | 7 +- crypto/quorum.go | 127 -------------------- crypto/quorum_test.go | 33 ------ dash/core/mock.go | 4 +- internal/consensus/state_test.go | 3 +- internal/consensus/vote_signer.go | 2 +- privval/dash_consensus_key.go | 4 +- privval/dash_core_signer_client.go | 8 +- test/e2e/pkg/mockcoreserver/core_server.go | 5 +- types/proposal.go | 5 +- types/quorum_sign_data.go | 129 ++++++++++++++++++++- types/quorum_sign_data_test.go | 31 ++++- types/vote_extension.go | 22 ++-- types/vote_extension_test.go | 5 +- 14 files changed, 182 insertions(+), 203 deletions(-) delete mode 100644 crypto/quorum.go delete mode 100644 crypto/quorum_test.go diff --git a/abci/example/kvstore/verify.go b/abci/example/kvstore/verify.go index 444dbab82e..e52116b5eb 100644 --- a/abci/example/kvstore/verify.go +++ b/abci/example/kvstore/verify.go @@ -7,7 +7,6 @@ import ( "github.com/dashpay/dashd-go/btcjson" abci "github.com/dashpay/tenderdash/abci/types" - "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/crypto/encoding" tmbytes "github.com/dashpay/tenderdash/libs/bytes" "github.com/dashpay/tenderdash/types" @@ -39,7 +38,7 @@ func makeBlockSignItem( req *abci.RequestFinalizeBlock, quorumType btcjson.LLMQType, quorumHash []byte, -) crypto.SignItem { +) types.SignItem { reqID := types.BlockRequestID(req.Height, req.Round) cv, err := req.ToCanonicalVote() if err != nil { @@ -49,14 +48,14 @@ func makeBlockSignItem( if err != nil { panic(fmt.Errorf("block sign item: %w", err)) } - return crypto.NewSignItem(quorumType, quorumHash, reqID, raw) + return types.NewSignItem(quorumType, quorumHash, reqID, raw) } func makeVoteExtensionSignItems( req *abci.RequestFinalizeBlock, quorumType btcjson.LLMQType, quorumHash []byte, -) []crypto.SignItem { +) []types.SignItem { extensions := types.VoteExtensionsFromProto(req.Commit.ThresholdVoteExtensions...) chainID := req.Block.Header.ChainID diff --git a/crypto/quorum.go b/crypto/quorum.go deleted file mode 100644 index bc9cccc07b..0000000000 --- a/crypto/quorum.go +++ /dev/null @@ -1,127 +0,0 @@ -package crypto - -import ( - "bytes" - "fmt" - - bls "github.com/dashpay/bls-signatures/go-bindings" - "github.com/dashpay/dashd-go/btcjson" - tmbytes "github.com/dashpay/tenderdash/libs/bytes" - "github.com/rs/zerolog" -) - -// SignItem represents signing session data (in field SignItem.ID) that will be signed to get threshold signature share. -// Field names are the same as in Dash Core, but the meaning is different. -// See DIP-0007 -type SignItem struct { - LlmqType btcjson.LLMQType // Quorum type for which this sign item is created - ID []byte // Request ID for quorum signing - MsgHash []byte // Checksum of Raw - QuorumHash []byte // Quorum hash for which this sign item is created - - SignHash []byte // Hash of llmqType, quorumHash, id, and msgHash - as provided to crypto sign/verify functions - - Msg []byte // Raw data to be signed, before any transformations; optional -} - -// Validate validates prepared data for signing -func (i *SignItem) Validate() error { - if len(i.ID) != DefaultHashSize { - return fmt.Errorf("invalid request ID size: %X", i.ID) - } - if len(i.MsgHash) != DefaultHashSize { - return fmt.Errorf("invalid hash size %d: %X", len(i.MsgHash), i.MsgHash) - } - if len(i.QuorumHash) != DefaultHashSize { - return fmt.Errorf("invalid quorum hash size %d: %X", len(i.QuorumHash), i.QuorumHash) - } - // Msg is optional - if len(i.Msg) > 0 { - if !bytes.Equal(Checksum(i.Msg), i.MsgHash) { - return fmt.Errorf("invalid hash %X for raw data: %X", i.MsgHash, i.Msg) - } - } - return nil -} - -func (i SignItem) MarshalZerologObject(e *zerolog.Event) { - e.Hex("msg", i.Msg) - e.Hex("signRequestID", i.ID) - e.Hex("signID", i.SignHash) - e.Hex("msgHash", i.MsgHash) - e.Hex("quorumHash", i.QuorumHash) - e.Uint8("llmqType", uint8(i.LlmqType)) - -} - -// NewSignItem creates a new instance of SignItem with calculating a hash for a raw and creating signID -// -// Arguments: -// - quorumType: quorum type -// - quorumHash: quorum hash -// - reqID: sign request ID -// - msg: raw data to be signed; it will be hashed with crypto.Checksum() -func NewSignItem(quorumType btcjson.LLMQType, quorumHash, reqID, msg []byte) SignItem { - msgHash := Checksum(msg) // FIXME: shouldn't we use sha256(sha256(raw)) here? - item := NewSignItemFromHash(quorumType, quorumHash, reqID, msgHash) - item.Msg = msg - - return item -} - -// Create a new sign item without raw value, using provided hash. -func NewSignItemFromHash(quorumType btcjson.LLMQType, quorumHash, reqID, msgHash []byte) SignItem { - item := SignItem{ - ID: reqID, - MsgHash: msgHash, - LlmqType: quorumType, - QuorumHash: quorumHash, - Msg: nil, // Raw is empty, as we don't have it - } - - // By default, reverse fields when calculating SignHash - item.UpdateSignHash(true) - - return item -} - -// UpdateSignHash recalculates signHash field -// If reverse is true, then all []byte elements will be reversed before -// calculating signID -func (i *SignItem) UpdateSignHash(reverse bool) { - if err := i.Validate(); err != nil { - panic("invalid sign item: " + err.Error()) - } - llmqType := i.LlmqType - - quorumHash := i.QuorumHash - requestID := i.ID - messageHash := i.MsgHash - - if reverse { - quorumHash = tmbytes.Reverse(quorumHash) - requestID = tmbytes.Reverse(requestID) - messageHash = tmbytes.Reverse(messageHash) - } - - var blsQuorumHash bls.Hash - copy(blsQuorumHash[:], quorumHash) - - var blsRequestID bls.Hash - copy(blsRequestID[:], requestID) - - var blsMessageHash bls.Hash - copy(blsMessageHash[:], messageHash) - - // fmt.Printf("LlmqType: %x + ", llmqType) - // fmt.Printf("QuorumHash: %x + ", blsQuorumHash) - // fmt.Printf("RequestID: %x + ", blsRequestID) - // fmt.Printf("MsgHash: %x\n", blsMessageHash) - - blsSignHash := bls.BuildSignHash(uint8(llmqType), blsQuorumHash, blsRequestID, blsMessageHash) - - signHash := make([]byte, 32) - copy(signHash, blsSignHash[:]) - - i.SignHash = signHash -} diff --git a/crypto/quorum_test.go b/crypto/quorum_test.go deleted file mode 100644 index 62186d77eb..0000000000 --- a/crypto/quorum_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package crypto_test - -import ( - "encoding/hex" - "testing" - - "github.com/dashpay/tenderdash/crypto" - tmbytes "github.com/dashpay/tenderdash/libs/bytes" - "github.com/stretchr/testify/assert" -) - -func TestQuorumSignItem(t *testing.T) { - - si := crypto.SignItem{ - ID: mustHexDecode("87cda9461081793e7e31ab1def8ffbd453775a0f9987304598398d42a78d68d4"), - MsgHash: mustHexDecode("5ef9b9eecc4df7c5aee677c0a72816f4515999a539003cf4bbb6c15c39634c31"), - LlmqType: 106, - QuorumHash: mustHexDecode("366f07c9b80a2661563a33c09f02156720159b911186b4438ff281e537674771"), - } - si.UpdateSignHash(true) - - expectID := tmbytes.Reverse(mustHexDecode("94635358f4c75a1d0b38314619d1c5d9a16f12961b5314d857e04f2eb61d78d2")) - - assert.EqualValues(t, expectID, si.SignHash) -} - -func mustHexDecode(s string) []byte { - b, err := hex.DecodeString(s) - if err != nil { - panic(err) - } - return b -} diff --git a/dash/core/mock.go b/dash/core/mock.go index e36e1f8d56..ec75950582 100644 --- a/dash/core/mock.go +++ b/dash/core/mock.go @@ -152,7 +152,7 @@ func (mc *MockClient) QuorumSign( if !mc.canSign { return nil, errors.New("dash core mock client not set up for signing") } - signID := crypto.NewSignItemFromHash(quorumType, quorumHash, requestID, messageHash).SignHash + signID := types.NewSignItemFromHash(quorumType, quorumHash, requestID, messageHash).SignHash privateKey, err := mc.localPV.GetPrivateKey(context.Background(), quorumHash) if err != nil { @@ -186,7 +186,7 @@ func (mc *MockClient) QuorumVerify( return false, err } - signID := crypto.NewSignItemFromHash(quorumType, quorumHash, requestID, messageHash).SignHash + signID := types.NewSignItemFromHash(quorumType, quorumHash, requestID, messageHash).SignHash thresholdPublicKey, err := mc.localPV.GetThresholdPublicKey(context.Background(), quorumHash) if err != nil { diff --git a/internal/consensus/state_test.go b/internal/consensus/state_test.go index 3f29c386d7..6f350c9a39 100644 --- a/internal/consensus/state_test.go +++ b/internal/consensus/state_test.go @@ -3,7 +3,6 @@ package consensus import ( "bytes" "context" - "fmt" "reflect" "strconv" "testing" @@ -3307,7 +3306,7 @@ func signAddPrecommitsWithExtension(ctx context.Context, protx, _ := vs.GetProTxHash(ctx) q, _ := vs.GetPubKey(ctx, valSet.QuorumHash) - fmt.Printf("signAddPrecommitsWithExtension: pubkey: %X, sigs %X, val protxhash(%d): %X\n", q.Bytes(), v.VoteExtensions.GetSignatures(), vs.Index, protx) + t.Logf("signAddPrecommitsWithExtension: pubkey: %X, sigs %X, val protxhash(%d): %X\n", q.Bytes(), v.VoteExtensions.GetSignatures(), vs.Index, protx) } addVotes(cs, votes...) } diff --git a/internal/consensus/vote_signer.go b/internal/consensus/vote_signer.go index a921b45615..365e1ffa48 100644 --- a/internal/consensus/vote_signer.go +++ b/internal/consensus/vote_signer.go @@ -108,7 +108,7 @@ func (s *voteSigner) signVote( if err != nil { return nil, err } - s.logger.Debug("signed Vote", "vote", vote, "signature", vote.BlockSignature.String()) + s.logger.Trace("signed Vote", "vote", vote, "signature", vote.BlockSignature.String()) return vote, nil } diff --git a/privval/dash_consensus_key.go b/privval/dash_consensus_key.go index 427b6f4f32..60a976c8bb 100644 --- a/privval/dash_consensus_key.go +++ b/privval/dash_consensus_key.go @@ -8,8 +8,8 @@ import ( "github.com/dashpay/dashd-go/btcjson" - "github.com/dashpay/tenderdash/crypto" tmcrypto "github.com/dashpay/tenderdash/crypto" + "github.com/dashpay/tenderdash/types" ) type dashConsensusPrivateKey struct { @@ -105,7 +105,7 @@ func (pub DashConsensusPublicKey) VerifySignature(msg []byte, sig []byte) bool { return pub.VerifySignatureDigest(hash, sig) } func (pub DashConsensusPublicKey) VerifySignatureDigest(hash []byte, sig []byte) bool { - signID := crypto.NewSignItemFromHash(pub.quorumType, pub.quorumHash, hash, hash).SignHash + signID := types.NewSignItemFromHash(pub.quorumType, pub.quorumHash, hash, hash).SignHash return pub.PubKey.VerifySignatureDigest(signID, sig) } diff --git a/privval/dash_core_signer_client.go b/privval/dash_core_signer_client.go index f462cc7d6f..eca97df82f 100644 --- a/privval/dash_core_signer_client.go +++ b/privval/dash_core_signer_client.go @@ -292,7 +292,7 @@ func (sc *DashCoreSignerClient) SignVote( func (sc *DashCoreSignerClient) SignProposal( ctx context.Context, chainID string, quorumType btcjson.LLMQType, quorumHash crypto.QuorumHash, proposalProto *tmproto.Proposal, ) (tmbytes.HexBytes, error) { - signItem := crypto.NewSignItem( + signItem := types.NewSignItem( quorumType, quorumHash, types.ProposalRequestIDProto(proposalProto), @@ -314,7 +314,7 @@ func (sc *DashCoreSignerClient) QuorumSign( quorumType btcjson.LLMQType, quorumHash crypto.QuorumHash, ) ([]byte, []byte, error) { - signItem := crypto.NewSignItemFromHash(quorumType, quorumHash, requestIDHash, msgHash) + signItem := types.NewSignItemFromHash(quorumType, quorumHash, requestIDHash, msgHash) qs, err := sc.quorumSignAndVerify(ctx, quorumType, quorumHash, signItem) if err != nil { @@ -397,7 +397,7 @@ func (sc *DashCoreSignerClient) quorumSignAndVerify( ctx context.Context, quorumType btcjson.LLMQType, quorumHash crypto.QuorumHash, - signItem crypto.SignItem, + signItem types.SignItem, ) (*quorumSignResult, error) { qs, err := sc.quorumSign(quorumType, quorumHash, signItem) if err != nil { @@ -425,7 +425,7 @@ func (sc *DashCoreSignerClient) quorumSignAndVerify( func (sc *DashCoreSignerClient) quorumSign( quorumType btcjson.LLMQType, quorumHash crypto.QuorumHash, - signItem crypto.SignItem, + signItem types.SignItem, ) (*quorumSignResult, error) { resp, err := sc.dashCoreRPCClient.QuorumSign(quorumType, signItem.ID, signItem.MsgHash, quorumHash) if err != nil { diff --git a/test/e2e/pkg/mockcoreserver/core_server.go b/test/e2e/pkg/mockcoreserver/core_server.go index 71a85805c8..ca66585123 100644 --- a/test/e2e/pkg/mockcoreserver/core_server.go +++ b/test/e2e/pkg/mockcoreserver/core_server.go @@ -10,6 +10,7 @@ import ( "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/privval" + "github.com/dashpay/tenderdash/types" ) // CoreServer is an interface of a mock core-server @@ -92,7 +93,7 @@ func (c *MockCoreServer) QuorumSign(ctx context.Context, cmd btcjson.QuorumCmd) panic(err) } quorumHash := crypto.QuorumHash(quorumHashBytes) - signID := crypto.NewSignItemFromHash(*cmd.LLMQType, quorumHash, reqID, msgHash).SignHash + signID := types.NewSignItemFromHash(*cmd.LLMQType, quorumHash, reqID, msgHash).SignHash privateKey, err := c.FilePV.GetPrivateKey(ctx, quorumHash) if err != nil { @@ -136,7 +137,7 @@ func (c *MockCoreServer) QuorumVerify(ctx context.Context, cmd btcjson.QuorumCmd if err != nil { panic(err) } - signID := crypto.NewSignItemFromHash(*cmd.LLMQType, quorumHash, reqID, msgHash).SignHash + signID := types.NewSignItemFromHash(*cmd.LLMQType, quorumHash, reqID, msgHash).SignHash thresholdPublicKey, err := c.FilePV.GetThresholdPublicKey(ctx, quorumHash) if err != nil { diff --git a/types/proposal.go b/types/proposal.go index ca7814fc0e..7dad0b55c2 100644 --- a/types/proposal.go +++ b/types/proposal.go @@ -9,13 +9,12 @@ import ( "time" "github.com/dashpay/dashd-go/btcjson" - "github.com/rs/zerolog" - "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/internal/libs/protoio" tmbytes "github.com/dashpay/tenderdash/libs/bytes" tmtime "github.com/dashpay/tenderdash/libs/time" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" + "github.com/rs/zerolog" ) var ( @@ -182,7 +181,7 @@ func ProposalBlockSignID( proposalRequestID := ProposalRequestIDProto(p) - signID := crypto.NewSignItemFromHash(quorumType, quorumHash, proposalRequestID, proposalMessageHash[:]).SignHash + signID := NewSignItemFromHash(quorumType, quorumHash, proposalRequestID, proposalMessageHash[:]).SignHash return signID } diff --git a/types/quorum_sign_data.go b/types/quorum_sign_data.go index 65267bc35b..af7db79477 100644 --- a/types/quorum_sign_data.go +++ b/types/quorum_sign_data.go @@ -1,18 +1,21 @@ package types import ( + "bytes" "fmt" + bls "github.com/dashpay/bls-signatures/go-bindings" "github.com/dashpay/dashd-go/btcjson" - "github.com/dashpay/tenderdash/crypto" + tmbytes "github.com/dashpay/tenderdash/libs/bytes" "github.com/dashpay/tenderdash/proto/tendermint/types" + "github.com/rs/zerolog" ) // QuorumSignData holds data which is necessary for signing and verification block, state, and each vote-extension in a list type QuorumSignData struct { - Block crypto.SignItem - VoteExtensionSignItems []crypto.SignItem + Block SignItem + VoteExtensionSignItems []SignItem } // Signs items inside QuorumSignData using a given private key. @@ -77,16 +80,132 @@ func MakeQuorumSigns( } // MakeBlockSignItem creates SignItem struct for a block -func MakeBlockSignItem(chainID string, vote *types.Vote, quorumType btcjson.LLMQType, quorumHash []byte) crypto.SignItem { +func MakeBlockSignItem(chainID string, vote *types.Vote, quorumType btcjson.LLMQType, quorumHash []byte) SignItem { reqID := BlockRequestID(vote.Height, vote.Round) raw, err := vote.SignBytes(chainID) if err != nil { panic(fmt.Errorf("block sign item: %w", err)) } - return crypto.NewSignItem(quorumType, quorumHash, reqID, raw) + return NewSignItem(quorumType, quorumHash, reqID, raw) } // BlockRequestID returns a block request ID func BlockRequestID(height int64, round int32) []byte { return heightRoundRequestID("dpbvote", height, round) } + +// SignItem represents signing session data (in field SignItem.ID) that will be signed to get threshold signature share. +// Field names are the same as in Dash Core, but the meaning is different. +// See DIP-0007 +type SignItem struct { + LlmqType btcjson.LLMQType // Quorum type for which this sign item is created + ID []byte // Request ID for quorum signing + MsgHash []byte // Checksum of Raw + QuorumHash []byte // Quorum hash for which this sign item is created + + SignHash []byte // Hash of llmqType, quorumHash, id, and msgHash - as provided to crypto sign/verify functions + + Msg []byte // Raw data to be signed, before any transformations; optional +} + +// Validate validates prepared data for signing +func (i *SignItem) Validate() error { + if len(i.ID) != crypto.DefaultHashSize { + return fmt.Errorf("invalid request ID size: %X", i.ID) + } + if len(i.MsgHash) != crypto.DefaultHashSize { + return fmt.Errorf("invalid hash size %d: %X", len(i.MsgHash), i.MsgHash) + } + if len(i.QuorumHash) != crypto.DefaultHashSize { + return fmt.Errorf("invalid quorum hash size %d: %X", len(i.QuorumHash), i.QuorumHash) + } + // Msg is optional + if len(i.Msg) > 0 { + if !bytes.Equal(crypto.Checksum(i.Msg), i.MsgHash) { + return fmt.Errorf("invalid hash %X for raw data: %X", i.MsgHash, i.Msg) + } + } + return nil +} + +func (i SignItem) MarshalZerologObject(e *zerolog.Event) { + e.Hex("msg", i.Msg) + e.Hex("signRequestID", i.ID) + e.Hex("signID", i.SignHash) + e.Hex("msgHash", i.MsgHash) + e.Hex("quorumHash", i.QuorumHash) + e.Uint8("llmqType", uint8(i.LlmqType)) + +} + +// NewSignItem creates a new instance of SignItem with calculating a hash for a raw and creating signID +// +// Arguments: +// - quorumType: quorum type +// - quorumHash: quorum hash +// - reqID: sign request ID +// - msg: raw data to be signed; it will be hashed with crypto.Checksum() +func NewSignItem(quorumType btcjson.LLMQType, quorumHash, reqID, msg []byte) SignItem { + msgHash := crypto.Checksum(msg) // FIXME: shouldn't we use sha256(sha256(raw)) here? + item := NewSignItemFromHash(quorumType, quorumHash, reqID, msgHash) + item.Msg = msg + + return item +} + +// Create a new sign item without raw value, using provided hash. +func NewSignItemFromHash(quorumType btcjson.LLMQType, quorumHash, reqID, msgHash []byte) SignItem { + item := SignItem{ + ID: reqID, + MsgHash: msgHash, + LlmqType: quorumType, + QuorumHash: quorumHash, + Msg: nil, // Raw is empty, as we don't have it + } + + // By default, reverse fields when calculating SignHash + item.UpdateSignHash(true) + + return item +} + +// UpdateSignHash recalculates signHash field +// If reverse is true, then all []byte elements will be reversed before +// calculating signID +func (i *SignItem) UpdateSignHash(reverse bool) { + if err := i.Validate(); err != nil { + panic("invalid sign item: " + err.Error()) + } + llmqType := i.LlmqType + + quorumHash := i.QuorumHash + requestID := i.ID + messageHash := i.MsgHash + + if reverse { + quorumHash = tmbytes.Reverse(quorumHash) + requestID = tmbytes.Reverse(requestID) + messageHash = tmbytes.Reverse(messageHash) + } + + var blsQuorumHash bls.Hash + copy(blsQuorumHash[:], quorumHash) + + var blsRequestID bls.Hash + copy(blsRequestID[:], requestID) + + var blsMessageHash bls.Hash + copy(blsMessageHash[:], messageHash) + + // fmt.Printf("LlmqType: %x + ", llmqType) + // fmt.Printf("QuorumHash: %x + ", blsQuorumHash) + // fmt.Printf("RequestID: %x + ", blsRequestID) + // fmt.Printf("MsgHash: %x\n", blsMessageHash) + + blsSignHash := bls.BuildSignHash(uint8(llmqType), blsQuorumHash, blsRequestID, blsMessageHash) + + signHash := make([]byte, 32) + copy(signHash, blsSignHash[:]) + + i.SignHash = signHash +} diff --git a/types/quorum_sign_data_test.go b/types/quorum_sign_data_test.go index be60f0b046..422c3d96a5 100644 --- a/types/quorum_sign_data_test.go +++ b/types/quorum_sign_data_test.go @@ -1,6 +1,7 @@ package types import ( + "encoding/hex" "fmt" "testing" @@ -8,7 +9,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/dashpay/tenderdash/crypto" tmbytes "github.com/dashpay/tenderdash/libs/bytes" "github.com/dashpay/tenderdash/proto/tendermint/types" ) @@ -26,7 +26,7 @@ func TestMakeBlockSignItem(t *testing.T) { testCases := []struct { vote Vote quorumHash []byte - want crypto.SignItem + want SignItem wantHash []byte }{ { @@ -57,8 +57,31 @@ func TestMakeBlockSignItem(t *testing.T) { } } -func newSignItem(reqID, signHash, raw, quorumHash string, quorumType btcjson.LLMQType) crypto.SignItem { - item := crypto.NewSignItem(quorumType, tmbytes.MustHexDecode(quorumHash), tmbytes.MustHexDecode(reqID), tmbytes.MustHexDecode(raw)) +func newSignItem(reqID, signHash, raw, quorumHash string, quorumType btcjson.LLMQType) SignItem { + item := NewSignItem(quorumType, tmbytes.MustHexDecode(quorumHash), tmbytes.MustHexDecode(reqID), tmbytes.MustHexDecode(raw)) item.SignHash = tmbytes.MustHexDecode(signHash) return item } + +func TestQuorumSignItem(t *testing.T) { + + si := SignItem{ + ID: mustHexDecode("87cda9461081793e7e31ab1def8ffbd453775a0f9987304598398d42a78d68d4"), + MsgHash: mustHexDecode("5ef9b9eecc4df7c5aee677c0a72816f4515999a539003cf4bbb6c15c39634c31"), + LlmqType: 106, + QuorumHash: mustHexDecode("366f07c9b80a2661563a33c09f02156720159b911186b4438ff281e537674771"), + } + si.UpdateSignHash(true) + + expectID := tmbytes.Reverse(mustHexDecode("94635358f4c75a1d0b38314619d1c5d9a16f12961b5314d857e04f2eb61d78d2")) + + assert.EqualValues(t, expectID, si.SignHash) +} + +func mustHexDecode(s string) []byte { + b, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return b +} diff --git a/types/vote_extension.go b/types/vote_extension.go index b59497e0d7..888e64d0a8 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -48,9 +48,9 @@ func (e VoteExtensions) SignItems( quorumHash []byte, height int64, round int32, -) ([]crypto.SignItem, error) { +) ([]SignItem, error) { - items := make([]crypto.SignItem, 0, e.Len()) + items := make([]SignItem, 0, e.Len()) for _, ext := range e { item, err := ext.SignItem(chainID, height, round, quorumType, quorumHash) @@ -276,7 +276,7 @@ type VoteExtensionIf interface { // It should prioritize performance and can do a shallow copy of the vote-extension, // so the returned object should not be modified. ToProto() tmproto.VoteExtension - SignItem(chainID string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) + SignItem(chainID string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (SignItem, error) IsThresholdRecoverable() bool // Validate returns error if a vote-extension is invalid. // It should not modify the state of the vote-extension. @@ -331,10 +331,10 @@ func (e GenericVoteExtension) ToProto() tmproto.VoteExtension { return e.VoteExtension.Clone() } -func (e GenericVoteExtension) SignItem(chainID string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) { +func (e GenericVoteExtension) SignItem(chainID string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (SignItem, error) { requestID, err := voteExtensionRequestID(height, round) if err != nil { - return crypto.SignItem{}, err + return SignItem{}, err } canonical, err := CanonicalizeVoteExtension(chainID, &e.VoteExtension, height, round) if err != nil { @@ -346,7 +346,7 @@ func (e GenericVoteExtension) SignItem(chainID string, height int64, round int32 panic(err) } - si := crypto.NewSignItem(quorumType, quorumHash, requestID, signBytes) + si := NewSignItem(quorumType, quorumHash, requestID, signBytes) // we do not reverse fields when calculating SignHash for vote extensions // si.UpdateSignHash(false) return si, nil @@ -454,7 +454,7 @@ func (e ThresholdRawVoteExtension) Copy() VoteExtensionIf { // SignItem creates a SignItem for a threshold raw vote extension // // Note: signItem.Msg left empty by purpose, as we don't want hash to be checked in Verify() -func (e ThresholdRawVoteExtension) SignItem(_ string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (crypto.SignItem, error) { +func (e ThresholdRawVoteExtension) SignItem(_ string, height int64, round int32, quorumType btcjson.LLMQType, quorumHash []byte) (SignItem, error) { var signRequestID []byte var err error @@ -466,13 +466,13 @@ func (e ThresholdRawVoteExtension) SignItem(_ string, height int64, round int32, signRequestID = tmbytes.Reverse(signRequestID) } else { if signRequestID, err = voteExtensionRequestID(height, round); err != nil { - return crypto.SignItem{}, err + return SignItem{}, err } } // ensure Extension is 32 bytes long if len(ext.Extension) != crypto.DefaultHashSize { - return crypto.SignItem{}, fmt.Errorf("invalid vote extension %s %X: extension must be %d bytes long", + return SignItem{}, fmt.Errorf("invalid vote extension %s %X: extension must be %d bytes long", ext.Type.String(), ext.Extension, crypto.DefaultHashSize) } @@ -481,9 +481,9 @@ func (e ThresholdRawVoteExtension) SignItem(_ string, height int64, round int32, // that reversal. msgHash := tmbytes.Reverse(ext.Extension) - signItem, err := crypto.NewSignItemFromHash(quorumType, quorumHash, signRequestID, msgHash), nil + signItem, err := NewSignItemFromHash(quorumType, quorumHash, signRequestID, msgHash), nil if err != nil { - return crypto.SignItem{}, err + return SignItem{}, err } // signItem.Msg left empty by purpose, as we don't want hash to be checked in Verify() diff --git a/types/vote_extension_test.go b/types/vote_extension_test.go index 2765542408..735c2306ed 100644 --- a/types/vote_extension_test.go +++ b/types/vote_extension_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/dashpay/dashd-go/btcjson" - "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/crypto/bls12381" tmbytes "github.com/dashpay/tenderdash/libs/bytes" "github.com/dashpay/tenderdash/libs/log" @@ -41,7 +40,7 @@ func TestMakeVoteExtensionsSignItems(t *testing.T) { testCases := []struct { vote Vote quorumHash []byte - want []crypto.SignItem + want []SignItem wantHash [][]byte }{ { @@ -58,7 +57,7 @@ func TestMakeVoteExtensionsSignItems(t *testing.T) { ), }, quorumHash: tmbytes.MustHexDecode("6A12D9CF7091D69072E254B297AEF15997093E480FDE295E09A7DE73B31CEEDD"), - want: []crypto.SignItem{ + want: []SignItem{ newSignItem( "FB95F2CA6530F02AC623589D7938643FF22AE79A75DD79AEA1C8871162DE675E", "533524404D3A905F5AC9A30FCEB5A922EAD96F30DA02F979EE41C4342F540467", From a6c5cf0b783610f68778d3134613c071f7bdd5f1 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 30 Jan 2024 09:18:06 +0100 Subject: [PATCH 49/55] chore: remove log --- internal/consensus/vote_signer.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/consensus/vote_signer.go b/internal/consensus/vote_signer.go index 365e1ffa48..62ef6cee30 100644 --- a/internal/consensus/vote_signer.go +++ b/internal/consensus/vote_signer.go @@ -103,12 +103,10 @@ func (s *voteSigner) signVote( if err != nil { return nil, err } - err = vote.PopulateSignsFromProto(protoVote) if err != nil { return nil, err } - s.logger.Trace("signed Vote", "vote", vote, "signature", vote.BlockSignature.String()) return vote, nil } From e3810d8c5a5db37a95d678a4dcfa0e17343f4b15 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 31 Jan 2024 08:45:09 +0100 Subject: [PATCH 50/55] build: update golangci-lint 1.55.0 to 1.55.2 --- go.mod | 12 ++++++------ go.sum | 32 ++++++++++++++++---------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/go.mod b/go.mod index 80cfbd2544..b607624ccf 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/gogo/protobuf v1.3.2 github.com/golang/protobuf v1.5.2 github.com/golang/snappy v0.0.4 // indirect - github.com/golangci/golangci-lint v1.55.0 + github.com/golangci/golangci-lint v1.55.2 github.com/google/btree v1.1.2 // indirect github.com/google/gopacket v1.1.19 github.com/google/orderedcode v0.0.1 @@ -51,7 +51,7 @@ require ( github.com/creachadair/atomicfile v0.2.6 github.com/creachadair/taskgroup v0.3.2 github.com/go-pkgz/jrpc v0.2.0 - github.com/google/go-cmp v0.5.9 + github.com/google/go-cmp v0.6.0 github.com/vektra/mockery/v2 v2.33.2 gotest.tools v2.2.0+incompatible ) @@ -98,7 +98,7 @@ require ( github.com/moby/buildkit v0.10.3 // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/morikuni/aec v1.0.0 // indirect - github.com/nunnatsa/ginkgolinter v0.14.0 // indirect + github.com/nunnatsa/ginkgolinter v0.14.1 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect @@ -138,7 +138,7 @@ require ( github.com/bombsimon/wsl/v3 v3.4.0 // indirect github.com/breml/bidichk v0.2.7 // indirect github.com/breml/errchkjson v0.3.6 // indirect - github.com/butuzov/ireturn v0.2.1 // indirect + github.com/butuzov/ireturn v0.2.2 // 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 @@ -181,7 +181,7 @@ require ( 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.4.1 // indirect - github.com/golangci/revgrep v0.5.0 // indirect + github.com/golangci/revgrep v0.5.2 // indirect github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect github.com/gordonklaus/ineffassign v0.0.0-20230610083614-0e73809eb601 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect @@ -248,7 +248,7 @@ require ( github.com/ryancurrah/gomodguard v1.3.0 // indirect github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect - github.com/securego/gosec/v2 v2.18.1 // indirect + github.com/securego/gosec/v2 v2.18.2 // indirect github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sivchari/containedctx v1.0.3 // indirect diff --git a/go.sum b/go.sum index fde04e281f..cde3e72466 100644 --- a/go.sum +++ b/go.sum @@ -144,8 +144,8 @@ github.com/bufbuild/buf v1.7.0 h1:uWRjhIXcrWkzIkA5TqXGyJbF51VW54QJsQZ3nwaes5Q= github.com/bufbuild/buf v1.7.0/go.mod h1:Go40fMAF46PnPLC7jJgTQhAI95pmC0+VtxFKVC0qLq0= github.com/bufbuild/connect-go v0.2.0 h1:WuMI/jLiJIhysHWvLWlxRozV67mGjCOUuDSl/lkDVic= github.com/bufbuild/connect-go v0.2.0/go.mod h1:4efZ2eXFENwd4p7tuLaL9m0qtTsCOzuBvrohvRGevDM= -github.com/butuzov/ireturn v0.2.1 h1:w5Ks4tnfeFDZskGJ2x1GAkx5gaQV+kdU3NKNr3NEBzY= -github.com/butuzov/ireturn v0.2.1/go.mod h1:RfGHUvvAuFFxoHKf4Z8Yxuh6OjlCw1KvR2zM1NFHeBk= +github.com/butuzov/ireturn v0.2.2 h1:jWI36dxXwVrI+RnXDwux2IZOewpmfv930OuIRfaBUJ0= +github.com/butuzov/ireturn v0.2.2/go.mod h1:RfGHUvvAuFFxoHKf4Z8Yxuh6OjlCw1KvR2zM1NFHeBk= github.com/butuzov/mirror v1.1.0 h1:ZqX54gBVMXu78QLoiqdwpl2mgmoOJTk7s4p4o+0avZI= github.com/butuzov/mirror v1.1.0/go.mod h1:8Q0BdQU6rC6WILDiBM60DBfvV78OLJmMmixe7GF45AE= github.com/catenacyber/perfsprint v0.2.0 h1:azOocHLscPjqXVJ7Mf14Zjlkn4uNua0+Hcg1wTR6vUo= @@ -410,16 +410,16 @@ github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe h1:6RGUuS7EGotKx6 github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e h1:ULcKCDV1LOZPFxGZaA6TlQbiM3J2GCPnkx/bGF6sX/g= github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e/go.mod h1:Pm5KhLPA8gSnQwrQ6ukebRcapGb/BG9iUkdaiCcGHJM= -github.com/golangci/golangci-lint v1.55.0 h1:ePpc6YhM1ZV8kHU8dwmHDHAdeedZHdK8cmTXlkkRdi8= -github.com/golangci/golangci-lint v1.55.0/go.mod h1:Z/OawFQ4yqFo2/plDYlIjoZlJeVYkRcqS9dW55p0FXg= +github.com/golangci/golangci-lint v1.55.2 h1:yllEIsSJ7MtlDBwDJ9IMBkyEUz2fYE0b5B8IUgO1oP8= +github.com/golangci/golangci-lint v1.55.2/go.mod h1:H60CZ0fuqoTwlTvnbyjhpZPWp7KmsjwV2yupIMiMXbM= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= github.com/golangci/misspell v0.4.1 h1:+y73iSicVy2PqyX7kmUefHusENlrP9YwuHZHPLGQj/g= github.com/golangci/misspell v0.4.1/go.mod h1:9mAN1quEo3DlpbaIKKyEvRxK1pwqR9s/Sea1bJCtlNI= -github.com/golangci/revgrep v0.5.0 h1:GGBqHFtFOeHiSUQtFVZXPJtVZYOGB4iVlAjaoFRBQvY= -github.com/golangci/revgrep v0.5.0/go.mod h1:bjAMA+Sh/QUfTDcHzxfyHxr4xKvllVr/0sCv2e7jJHA= +github.com/golangci/revgrep v0.5.2 h1:EndcWoRhcnfj2NHQ+28hyuXpLMF+dQmCN+YaeeIl4FU= +github.com/golangci/revgrep v0.5.2/go.mod h1:bjAMA+Sh/QUfTDcHzxfyHxr4xKvllVr/0sCv2e7jJHA= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -439,8 +439,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= @@ -660,8 +660,8 @@ github.com/nishanths/exhaustive v0.11.0 h1:T3I8nUGhl/Cwu5Z2hfc92l0e04D2GEW6e0l8p github.com/nishanths/exhaustive v0.11.0/go.mod h1:RqwDsZ1xY0dNdqHho2z6X+bgzizwbLYOWnZbbl2wLB4= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= -github.com/nunnatsa/ginkgolinter v0.14.0 h1:XQPNmw+kZz5cC/HbFK3mQutpjzAQv1dHregRA+4CGGg= -github.com/nunnatsa/ginkgolinter v0.14.0/go.mod h1:cm2xaqCUCRd7qcP4DqbVvpcyEMkuLM9CF0wY6VASohk= +github.com/nunnatsa/ginkgolinter v0.14.1 h1:khx0CqR5U4ghsscjJ+lZVthp3zjIFytRXPTaQ/TMiyA= +github.com/nunnatsa/ginkgolinter v0.14.1/go.mod h1:nY0pafUSst7v7F637e7fymaMlQqI9c0Wka2fGsDkzWg= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -677,13 +677,13 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA= -github.com/onsi/ginkgo/v2 v2.12.1/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= +github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.28.0 h1:i2rg/p9n/UqIDAMFUJ6qIUUMcsqOuUHgbpbu235Vr1c= -github.com/onsi/gomega v1.28.0/go.mod h1:A1H2JE76sI14WIP57LMKj7FVfCHx3g3BcZVjJG8bjX8= +github.com/onsi/gomega v1.28.1 h1:MijcGUbfYuznzK/5R4CPNoUP/9Xvuo20sXfEm6XxoTA= +github.com/onsi/gomega v1.28.1/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= @@ -781,8 +781,8 @@ github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84d github.com/sashamelentyev/usestdlibvars v1.24.0 h1:MKNzmXtGh5N0y74Z/CIaJh4GlB364l0K1RUT08WSWAc= github.com/sashamelentyev/usestdlibvars v1.24.0/go.mod h1:9cYkq+gYJ+a5W2RPdhfaSCnTVUC1OQP/bSiiBhq3OZE= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= -github.com/securego/gosec/v2 v2.18.1 h1:xnnehWg7dIW8qrRPGm8ykY21zp2MueKyC99Vlcuj96I= -github.com/securego/gosec/v2 v2.18.1/go.mod h1:ZUTcKD9gAFip1lLGHWCjkoBQJyaEzePTNzjwlL2HHoE= +github.com/securego/gosec/v2 v2.18.2 h1:DkDt3wCiOtAHf1XkiXZBhQ6m6mK/b9T/wD257R3/c+I= +github.com/securego/gosec/v2 v2.18.2/go.mod h1:xUuqSF6i0So56Y2wwohWAmB07EdBkUN6crbLlHwbyJs= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= From 62af8fc35449adf8324701f635ec686ce6a58490 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 31 Jan 2024 08:45:44 +0100 Subject: [PATCH 51/55] chore: apply linter comments --- internal/state/validation_test.go | 2 +- types/vote_extension.go | 7 ++++--- types/vote_extension_test.go | 8 ++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/internal/state/validation_test.go b/internal/state/validation_test.go index be1c3abb96..d3bab08967 100644 --- a/internal/state/validation_test.go +++ b/internal/state/validation_test.go @@ -386,7 +386,7 @@ func TestValidateBlockEvidence(t *testing.T) { blockStore, eventBus, ) - lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil,nil) + lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil, nil) for height := int64(1); height < validationTestsStopHeight; height++ { proposerProTxHash := state.Validators.GetProposer().ProTxHash diff --git a/types/vote_extension.go b/types/vote_extension.go index 888e64d0a8..784da379a5 100644 --- a/types/vote_extension.go +++ b/types/vote_extension.go @@ -8,14 +8,15 @@ import ( "math/big" "github.com/dashpay/dashd-go/btcjson" + "github.com/hashicorp/go-multierror" + "github.com/rs/zerolog" + abci "github.com/dashpay/tenderdash/abci/types" "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/crypto/bls12381" "github.com/dashpay/tenderdash/internal/libs/protoio" tmbytes "github.com/dashpay/tenderdash/libs/bytes" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" - "github.com/hashicorp/go-multierror" - "github.com/rs/zerolog" ) var ( @@ -367,7 +368,7 @@ func (e GenericVoteExtension) MarshalZerologObject(o *zerolog.Event) { o.Hex("sign_request_id", e.GetSignRequestId()) } -//nolint:revive,stylecheck // name is the same as in protobuf-generated code +//nolint:stylecheck // name is the same as in protobuf-generated code func (e GenericVoteExtension) GetSignRequestId() []byte { if e.XSignRequestId == nil { return nil diff --git a/types/vote_extension_test.go b/types/vote_extension_test.go index 735c2306ed..0bf6cdb779 100644 --- a/types/vote_extension_test.go +++ b/types/vote_extension_test.go @@ -8,13 +8,13 @@ import ( "testing" "github.com/dashpay/dashd-go/btcjson" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/dashpay/tenderdash/crypto/bls12381" tmbytes "github.com/dashpay/tenderdash/libs/bytes" "github.com/dashpay/tenderdash/libs/log" - "github.com/dashpay/tenderdash/proto/tendermint/types" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestVoteExtensionCopySignsFromProto(t *testing.T) { @@ -45,7 +45,7 @@ func TestMakeVoteExtensionsSignItems(t *testing.T) { }{ { vote: Vote{ - Type: types.PrecommitType, + Type: tmproto.PrecommitType, Height: 1001, ValidatorProTxHash: tmbytes.MustHexDecode("9CC13F685BC3EA0FCA99B87F42ABCC934C6305AA47F62A32266A2B9D55306B7B"), VoteExtensions: VoteExtensionsFromProto(&tmproto.VoteExtension{ From b05298356d5bd885dd31c05b2257cb8f98da9b89 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 31 Jan 2024 10:27:46 +0100 Subject: [PATCH 52/55] chore: decrease logs size --- test/e2e/tests/app_test.go | 11 ++++++++++- types/block.go | 25 +++++++++++++++++++++++++ types/tx.go | 8 ++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/test/e2e/tests/app_test.go b/test/e2e/tests/app_test.go index ac9b3566f5..8e00b429e0 100644 --- a/test/e2e/tests/app_test.go +++ b/test/e2e/tests/app_test.go @@ -250,7 +250,16 @@ func TestApp_TxTooBig(t *testing.T) { assert.NoError(t, err, "first tx should be committed before second") assert.EqualValues(t, firstTxHash, firstTxResp.Tx.Hash()) - t.Logf("first tx in block %d, last tx in block %d", firstTxResp.Height, lastTxResp.Height) + firstTxBlock, err := client.Header(ctx, &firstTxResp.Height) + assert.NoError(t, err) + lastTxBlock, err := client.Header(ctx, &lastTxResp.Height) + assert.NoError(t, err) + + t.Logf("first tx in block %d, last tx in block %d, took %s", + firstTxResp.Height, + lastTxResp.Height, + lastTxBlock.Header.Time.Sub(firstTxBlock.Header.Time).String(), + ) assert.Less(t, firstTxResp.Height, lastTxResp.Height, "first tx should in block before last tx") return true diff --git a/types/block.go b/types/block.go index 4d98c855f7..434c1a3fae 100644 --- a/types/block.go +++ b/types/block.go @@ -294,6 +294,20 @@ func (b *Block) ToProto() (*tmproto.Block, error) { return pb, nil } +func (b *Block) MarshalZerologObject(e *zerolog.Event) { + if b == nil { + e.Bool("nil", true) + return + } + e.Bool("nil", false) + + e.Interface("header", b.Header) + e.Interface("core_chain_lock", b.CoreChainLock) + e.Interface("data", b.Data) + e.Interface("evidence", b.Evidence) + e.Interface("last_commit", b.LastCommit) +} + // FromProto sets a protobuf Block to the given pointer. // It returns an error if the block is invalid. func BlockFromProto(bp *tmproto.Block) (*Block, error) { @@ -1039,6 +1053,17 @@ func (data *Data) ToProto() tmproto.Data { return *tp } +func (data *Data) MarshalZerologObject(e *zerolog.Event) { + if data == nil { + e.Bool("nil", true) + return + } + e.Bool("nil", false) + + e.Array("txs", data.Txs) + e.Hex("hash", data.Hash()) +} + // DataFromProto takes a protobuf representation of Data & // returns the native type. func DataFromProto(dp *tmproto.Data) (Data, error) { diff --git a/types/tx.go b/types/tx.go index 9080ad564b..ec1c89c7ca 100644 --- a/types/tx.go +++ b/types/tx.go @@ -7,6 +7,8 @@ import ( "fmt" "sort" + "github.com/rs/zerolog" + abci "github.com/dashpay/tenderdash/abci/types" "github.com/dashpay/tenderdash/crypto" "github.com/dashpay/tenderdash/crypto/merkle" @@ -103,6 +105,12 @@ func (txs Txs) ToSliceOfBytes() [][]byte { return txBzs } +func (txs Txs) MarshalZerologArray(e *zerolog.Array) { + for _, tx := range txs { + e.Hex(tx.Hash()) + } +} + // TxRecordSet contains indexes into an underlying set of transactions. // These indexes are useful for validating and working with a list of TxRecords // from the PrepareProposal response. From 3731326ffa80523c488bf606f307821a6b9f079c Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 31 Jan 2024 10:37:00 +0100 Subject: [PATCH 53/55] test(e2e): increase e2e test timeout --- .github/workflows/e2e.yml | 2 +- test/e2e/runner/test.go | 2 +- test/e2e/tests/app_test.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index ace70b7d85..72788c0a6b 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -20,7 +20,7 @@ jobs: fail-fast: true matrix: testnet: ["dashcore", "rotate"] - timeout-minutes: 25 + timeout-minutes: 30 env: FULLNODE_PUBKEY_KEEP: false CGO_LDFLAGS: "-L/usr/local/lib -ldashbls -lrelic_s -lmimalloc-secure -lgmp" diff --git a/test/e2e/runner/test.go b/test/e2e/runner/test.go index c44f58acd4..79886fd3ea 100644 --- a/test/e2e/runner/test.go +++ b/test/e2e/runner/test.go @@ -15,5 +15,5 @@ func Test(ctx context.Context, testnet *e2e.Testnet) error { return err } - return exec.CommandVerbose(ctx, "./build/tests", "-test.count=1", "-test.v", "-test.timeout=5m") + return exec.CommandVerbose(ctx, "./build/tests", "-test.count=1", "-test.v", "-test.timeout=10m") } diff --git a/test/e2e/tests/app_test.go b/test/e2e/tests/app_test.go index 8e00b429e0..cc80d19d9a 100644 --- a/test/e2e/tests/app_test.go +++ b/test/e2e/tests/app_test.go @@ -195,7 +195,7 @@ func TestApp_Tx(t *testing.T) { // when I submit them to the node, // then the first transaction should be committed before the last one. func TestApp_TxTooBig(t *testing.T) { - const timeout = 10 * time.Second + const timeout = 30 * time.Second testNode(t, func(ctx context.Context, t *testing.T, node e2e.Node) { session := rand.Int63() From 61eb29a2a27c6a8e812fbacaed2ee1a88d8b2bfe Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 31 Jan 2024 10:46:26 +0100 Subject: [PATCH 54/55] chore: text --- test/e2e/tests/app_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/tests/app_test.go b/test/e2e/tests/app_test.go index cc80d19d9a..f3e4523c07 100644 --- a/test/e2e/tests/app_test.go +++ b/test/e2e/tests/app_test.go @@ -255,7 +255,7 @@ func TestApp_TxTooBig(t *testing.T) { lastTxBlock, err := client.Header(ctx, &lastTxResp.Height) assert.NoError(t, err) - t.Logf("first tx in block %d, last tx in block %d, took %s", + t.Logf("first tx in block %d, last tx in block %d, time diff %s", firstTxResp.Height, lastTxResp.Height, lastTxBlock.Header.Time.Sub(firstTxBlock.Header.Time).String(), From 1ba6448d8ec344dc6d32a48a5abc9c260a52b77f Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 31 Jan 2024 10:57:32 +0100 Subject: [PATCH 55/55] test(e2e): increase timeout --- test/e2e/tests/app_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/tests/app_test.go b/test/e2e/tests/app_test.go index f3e4523c07..d302242c1f 100644 --- a/test/e2e/tests/app_test.go +++ b/test/e2e/tests/app_test.go @@ -195,7 +195,7 @@ func TestApp_Tx(t *testing.T) { // when I submit them to the node, // then the first transaction should be committed before the last one. func TestApp_TxTooBig(t *testing.T) { - const timeout = 30 * time.Second + const timeout = 60 * time.Second testNode(t, func(ctx context.Context, t *testing.T, node e2e.Node) { session := rand.Int63()