From 827e65649ef380f1ecbba65a79963be5ab7ad797 Mon Sep 17 00:00:00 2001 From: Ian Shim <100327837+ian-shim@users.noreply.github.com> Date: Thu, 7 Nov 2024 09:31:51 -0800 Subject: [PATCH] [v2] Attestation Interface & Metadata Store (#868) --- api/grpc/disperser/v2/disperser_v2.pb.go | 270 ++++++------------ api/proto/disperser/v2/disperser_v2.proto | 22 +- core/v2/types.go | 17 ++ .../v2/blobstore/dynamo_metadata_store.go | 139 +++++++++ .../blobstore/dynamo_metadata_store_test.go | 65 +++++ 5 files changed, 317 insertions(+), 196 deletions(-) diff --git a/api/grpc/disperser/v2/disperser_v2.pb.go b/api/grpc/disperser/v2/disperser_v2.pb.go index 1ddcf05c56..7955aa3016 100644 --- a/api/grpc/disperser/v2/disperser_v2.pb.go +++ b/api/grpc/disperser/v2/disperser_v2.pb.go @@ -552,14 +552,16 @@ type Attestation struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - NonSignerQuorumBitmapIndices []uint32 `protobuf:"varint,1,rep,packed,name=nonSignerQuorumBitmapIndices,proto3" json:"nonSignerQuorumBitmapIndices,omitempty"` - NonSignerPubkeys [][]byte `protobuf:"bytes,2,rep,name=nonSignerPubkeys,proto3" json:"nonSignerPubkeys,omitempty"` - QuorumApks [][]byte `protobuf:"bytes,3,rep,name=quorumApks,proto3" json:"quorumApks,omitempty"` - ApkG2 []byte `protobuf:"bytes,4,opt,name=apkG2,proto3" json:"apkG2,omitempty"` - Sigma []byte `protobuf:"bytes,5,opt,name=sigma,proto3" json:"sigma,omitempty"` - QuorumApkIndices []uint32 `protobuf:"varint,6,rep,packed,name=quorumApkIndices,proto3" json:"quorumApkIndices,omitempty"` - TotalStakeIndices []uint32 `protobuf:"varint,7,rep,packed,name=totalStakeIndices,proto3" json:"totalStakeIndices,omitempty"` - NonSignerStakeIndices []*NonSignerStakeIndicesForQuorum `protobuf:"bytes,8,rep,name=nonSignerStakeIndices,proto3" json:"nonSignerStakeIndices,omitempty"` + // Serialized bytes of non signer public keys (G1 points) + NonSignerPubkeys [][]byte `protobuf:"bytes,1,rep,name=non_signer_pubkeys,json=nonSignerPubkeys,proto3" json:"non_signer_pubkeys,omitempty"` + // Serialized bytes of G2 point that represents aggregate public key of all signers + ApkG2 []byte `protobuf:"bytes,2,opt,name=apk_g2,json=apkG2,proto3" json:"apk_g2,omitempty"` + // Serialized bytes of aggregate public keys (G1 points) from all nodes for each quorum + QuorumApks [][]byte `protobuf:"bytes,3,rep,name=quorum_apks,json=quorumApks,proto3" json:"quorum_apks,omitempty"` + // Serialized bytes of aggregate signature + Sigma []byte `protobuf:"bytes,4,opt,name=sigma,proto3" json:"sigma,omitempty"` + // Relevant quorum numbers for the attestation + QuorumNumbers []uint32 `protobuf:"varint,5,rep,packed,name=quorum_numbers,json=quorumNumbers,proto3" json:"quorum_numbers,omitempty"` } func (x *Attestation) Reset() { @@ -594,13 +596,6 @@ func (*Attestation) Descriptor() ([]byte, []int) { return file_disperser_v2_disperser_v2_proto_rawDescGZIP(), []int{8} } -func (x *Attestation) GetNonSignerQuorumBitmapIndices() []uint32 { - if x != nil { - return x.NonSignerQuorumBitmapIndices - } - return nil -} - func (x *Attestation) GetNonSignerPubkeys() [][]byte { if x != nil { return x.NonSignerPubkeys @@ -608,13 +603,6 @@ func (x *Attestation) GetNonSignerPubkeys() [][]byte { return nil } -func (x *Attestation) GetQuorumApks() [][]byte { - if x != nil { - return x.QuorumApks - } - return nil -} - func (x *Attestation) GetApkG2() []byte { if x != nil { return x.ApkG2 @@ -622,77 +610,23 @@ func (x *Attestation) GetApkG2() []byte { return nil } -func (x *Attestation) GetSigma() []byte { - if x != nil { - return x.Sigma - } - return nil -} - -func (x *Attestation) GetQuorumApkIndices() []uint32 { - if x != nil { - return x.QuorumApkIndices - } - return nil -} - -func (x *Attestation) GetTotalStakeIndices() []uint32 { +func (x *Attestation) GetQuorumApks() [][]byte { if x != nil { - return x.TotalStakeIndices + return x.QuorumApks } return nil } -func (x *Attestation) GetNonSignerStakeIndices() []*NonSignerStakeIndicesForQuorum { +func (x *Attestation) GetSigma() []byte { if x != nil { - return x.NonSignerStakeIndices + return x.Sigma } return nil } -type NonSignerStakeIndicesForQuorum struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Indices []uint32 `protobuf:"varint,1,rep,packed,name=indices,proto3" json:"indices,omitempty"` -} - -func (x *NonSignerStakeIndicesForQuorum) Reset() { - *x = NonSignerStakeIndicesForQuorum{} - if protoimpl.UnsafeEnabled { - mi := &file_disperser_v2_disperser_v2_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NonSignerStakeIndicesForQuorum) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NonSignerStakeIndicesForQuorum) ProtoMessage() {} - -func (x *NonSignerStakeIndicesForQuorum) ProtoReflect() protoreflect.Message { - mi := &file_disperser_v2_disperser_v2_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NonSignerStakeIndicesForQuorum.ProtoReflect.Descriptor instead. -func (*NonSignerStakeIndicesForQuorum) Descriptor() ([]byte, []int) { - return file_disperser_v2_disperser_v2_proto_rawDescGZIP(), []int{9} -} - -func (x *NonSignerStakeIndicesForQuorum) GetIndices() []uint32 { +func (x *Attestation) GetQuorumNumbers() []uint32 { if x != nil { - return x.Indices + return x.QuorumNumbers } return nil } @@ -763,64 +697,46 @@ var file_disperser_v2_disperser_v2_proto_rawDesc = []byte{ 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, - 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x87, 0x03, - 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x42, 0x0a, - 0x1c, 0x6e, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, - 0x42, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0d, 0x52, 0x1c, 0x6e, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x51, 0x75, - 0x6f, 0x72, 0x75, 0x6d, 0x42, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, - 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6e, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x50, 0x75, - 0x62, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x10, 0x6e, 0x6f, 0x6e, - 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x1e, 0x0a, - 0x0a, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x41, 0x70, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0c, 0x52, 0x0a, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x41, 0x70, 0x6b, 0x73, 0x12, 0x14, 0x0a, - 0x05, 0x61, 0x70, 0x6b, 0x47, 0x32, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x61, 0x70, - 0x6b, 0x47, 0x32, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x69, 0x67, 0x6d, 0x61, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x73, 0x69, 0x67, 0x6d, 0x61, 0x12, 0x2a, 0x0a, 0x10, 0x71, 0x75, 0x6f, - 0x72, 0x75, 0x6d, 0x41, 0x70, 0x6b, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x18, 0x06, 0x20, - 0x03, 0x28, 0x0d, 0x52, 0x10, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x41, 0x70, 0x6b, 0x49, 0x6e, - 0x64, 0x69, 0x63, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x53, 0x74, - 0x61, 0x6b, 0x65, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0d, - 0x52, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x49, 0x6e, 0x64, 0x69, - 0x63, 0x65, 0x73, 0x12, 0x62, 0x0a, 0x15, 0x6e, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, - 0x53, 0x74, 0x61, 0x6b, 0x65, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, - 0x32, 0x2e, 0x4e, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x53, 0x74, 0x61, 0x6b, 0x65, - 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x46, 0x6f, 0x72, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, - 0x52, 0x15, 0x6e, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x53, 0x74, 0x61, 0x6b, 0x65, - 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x22, 0x3a, 0x0a, 0x1e, 0x4e, 0x6f, 0x6e, 0x53, 0x69, - 0x67, 0x6e, 0x65, 0x72, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, - 0x46, 0x6f, 0x72, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6e, 0x64, - 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x07, 0x69, 0x6e, 0x64, 0x69, - 0x63, 0x65, 0x73, 0x2a, 0x6a, 0x0a, 0x0a, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, - 0x0a, 0x06, 0x51, 0x55, 0x45, 0x55, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, - 0x43, 0x4f, 0x44, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x45, 0x52, 0x54, 0x49, - 0x46, 0x49, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, - 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, - 0x4e, 0x54, 0x5f, 0x53, 0x49, 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x53, 0x10, 0x05, 0x32, - 0x93, 0x02, 0x0a, 0x09, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x12, 0x54, 0x0a, - 0x0c, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x21, 0x2e, + 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xb0, 0x01, + 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, + 0x12, 0x6e, 0x6f, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6b, + 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x10, 0x6e, 0x6f, 0x6e, 0x53, 0x69, + 0x67, 0x6e, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x61, + 0x70, 0x6b, 0x5f, 0x67, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x61, 0x70, 0x6b, + 0x47, 0x32, 0x12, 0x1f, 0x0a, 0x0b, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x61, 0x70, 0x6b, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x41, + 0x70, 0x6b, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x69, 0x67, 0x6d, 0x61, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x05, 0x73, 0x69, 0x67, 0x6d, 0x61, 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, + 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x0d, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x2a, 0x6a, 0x0a, 0x0a, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, + 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x51, + 0x55, 0x45, 0x55, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, 0x43, 0x4f, 0x44, + 0x45, 0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, + 0x1b, 0x0a, 0x17, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x53, 0x49, 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x53, 0x10, 0x05, 0x32, 0x93, 0x02, 0x0a, + 0x09, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x12, 0x54, 0x0a, 0x0c, 0x44, 0x69, + 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x21, 0x2e, 0x64, 0x69, 0x73, + 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, + 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x69, 0x73, - 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, - 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, - 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, - 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x62, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x64, 0x69, - 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x43, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x21, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, - 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x4c, 0x61, 0x79, 0x72, 0x2d, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x65, 0x69, - 0x67, 0x65, 0x6e, 0x64, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x64, - 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, + 0x12, 0x51, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, + 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, + 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, + 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, + 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, + 0x62, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x00, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x4c, 0x61, 0x79, 0x72, 0x2d, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x65, 0x69, 0x67, 0x65, 0x6e, + 0x64, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x64, 0x69, 0x73, 0x70, + 0x65, 0x72, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -836,46 +752,44 @@ func file_disperser_v2_disperser_v2_proto_rawDescGZIP() []byte { } var file_disperser_v2_disperser_v2_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_disperser_v2_disperser_v2_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_disperser_v2_disperser_v2_proto_msgTypes = make([]protoimpl.MessageInfo, 9) var file_disperser_v2_disperser_v2_proto_goTypes = []interface{}{ - (BlobStatus)(0), // 0: disperser.v2.BlobStatus - (*DisperseBlobRequest)(nil), // 1: disperser.v2.DisperseBlobRequest - (*DisperseBlobReply)(nil), // 2: disperser.v2.DisperseBlobReply - (*BlobStatusRequest)(nil), // 3: disperser.v2.BlobStatusRequest - (*BlobStatusReply)(nil), // 4: disperser.v2.BlobStatusReply - (*BlobCommitmentRequest)(nil), // 5: disperser.v2.BlobCommitmentRequest - (*BlobCommitmentReply)(nil), // 6: disperser.v2.BlobCommitmentReply - (*SignedBatch)(nil), // 7: disperser.v2.SignedBatch - (*BlobVerificationInfo)(nil), // 8: disperser.v2.BlobVerificationInfo - (*Attestation)(nil), // 9: disperser.v2.Attestation - (*NonSignerStakeIndicesForQuorum)(nil), // 10: disperser.v2.NonSignerStakeIndicesForQuorum - (*v2.BlobHeader)(nil), // 11: common.v2.BlobHeader - (*common.BlobCommitment)(nil), // 12: common.BlobCommitment - (*v2.BatchHeader)(nil), // 13: common.v2.BatchHeader - (*v2.BlobCertificate)(nil), // 14: common.v2.BlobCertificate + (BlobStatus)(0), // 0: disperser.v2.BlobStatus + (*DisperseBlobRequest)(nil), // 1: disperser.v2.DisperseBlobRequest + (*DisperseBlobReply)(nil), // 2: disperser.v2.DisperseBlobReply + (*BlobStatusRequest)(nil), // 3: disperser.v2.BlobStatusRequest + (*BlobStatusReply)(nil), // 4: disperser.v2.BlobStatusReply + (*BlobCommitmentRequest)(nil), // 5: disperser.v2.BlobCommitmentRequest + (*BlobCommitmentReply)(nil), // 6: disperser.v2.BlobCommitmentReply + (*SignedBatch)(nil), // 7: disperser.v2.SignedBatch + (*BlobVerificationInfo)(nil), // 8: disperser.v2.BlobVerificationInfo + (*Attestation)(nil), // 9: disperser.v2.Attestation + (*v2.BlobHeader)(nil), // 10: common.v2.BlobHeader + (*common.BlobCommitment)(nil), // 11: common.BlobCommitment + (*v2.BatchHeader)(nil), // 12: common.v2.BatchHeader + (*v2.BlobCertificate)(nil), // 13: common.v2.BlobCertificate } var file_disperser_v2_disperser_v2_proto_depIdxs = []int32{ - 11, // 0: disperser.v2.DisperseBlobRequest.blob_header:type_name -> common.v2.BlobHeader + 10, // 0: disperser.v2.DisperseBlobRequest.blob_header:type_name -> common.v2.BlobHeader 0, // 1: disperser.v2.DisperseBlobReply.result:type_name -> disperser.v2.BlobStatus 0, // 2: disperser.v2.BlobStatusReply.status:type_name -> disperser.v2.BlobStatus 7, // 3: disperser.v2.BlobStatusReply.signed_batch:type_name -> disperser.v2.SignedBatch 8, // 4: disperser.v2.BlobStatusReply.blob_verification_info:type_name -> disperser.v2.BlobVerificationInfo - 12, // 5: disperser.v2.BlobCommitmentReply.blob_commitment:type_name -> common.BlobCommitment - 13, // 6: disperser.v2.SignedBatch.header:type_name -> common.v2.BatchHeader + 11, // 5: disperser.v2.BlobCommitmentReply.blob_commitment:type_name -> common.BlobCommitment + 12, // 6: disperser.v2.SignedBatch.header:type_name -> common.v2.BatchHeader 9, // 7: disperser.v2.SignedBatch.non_signer_stakes_and_signature:type_name -> disperser.v2.Attestation - 14, // 8: disperser.v2.BlobVerificationInfo.blob_certificate:type_name -> common.v2.BlobCertificate - 10, // 9: disperser.v2.Attestation.nonSignerStakeIndices:type_name -> disperser.v2.NonSignerStakeIndicesForQuorum - 1, // 10: disperser.v2.Disperser.DisperseBlob:input_type -> disperser.v2.DisperseBlobRequest - 3, // 11: disperser.v2.Disperser.GetBlobStatus:input_type -> disperser.v2.BlobStatusRequest - 5, // 12: disperser.v2.Disperser.GetBlobCommitment:input_type -> disperser.v2.BlobCommitmentRequest - 2, // 13: disperser.v2.Disperser.DisperseBlob:output_type -> disperser.v2.DisperseBlobReply - 4, // 14: disperser.v2.Disperser.GetBlobStatus:output_type -> disperser.v2.BlobStatusReply - 6, // 15: disperser.v2.Disperser.GetBlobCommitment:output_type -> disperser.v2.BlobCommitmentReply - 13, // [13:16] is the sub-list for method output_type - 10, // [10:13] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 13, // 8: disperser.v2.BlobVerificationInfo.blob_certificate:type_name -> common.v2.BlobCertificate + 1, // 9: disperser.v2.Disperser.DisperseBlob:input_type -> disperser.v2.DisperseBlobRequest + 3, // 10: disperser.v2.Disperser.GetBlobStatus:input_type -> disperser.v2.BlobStatusRequest + 5, // 11: disperser.v2.Disperser.GetBlobCommitment:input_type -> disperser.v2.BlobCommitmentRequest + 2, // 12: disperser.v2.Disperser.DisperseBlob:output_type -> disperser.v2.DisperseBlobReply + 4, // 13: disperser.v2.Disperser.GetBlobStatus:output_type -> disperser.v2.BlobStatusReply + 6, // 14: disperser.v2.Disperser.GetBlobCommitment:output_type -> disperser.v2.BlobCommitmentReply + 12, // [12:15] is the sub-list for method output_type + 9, // [9:12] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_disperser_v2_disperser_v2_proto_init() } @@ -992,18 +906,6 @@ func file_disperser_v2_disperser_v2_proto_init() { return nil } } - file_disperser_v2_disperser_v2_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NonSignerStakeIndicesForQuorum); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } } type x struct{} out := protoimpl.TypeBuilder{ @@ -1011,7 +913,7 @@ func file_disperser_v2_disperser_v2_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_disperser_v2_disperser_v2_proto_rawDesc, NumEnums: 1, - NumMessages: 10, + NumMessages: 9, NumExtensions: 0, NumServices: 1, }, diff --git a/api/proto/disperser/v2/disperser_v2.proto b/api/proto/disperser/v2/disperser_v2.proto index 900e49a417..b597b7e28f 100644 --- a/api/proto/disperser/v2/disperser_v2.proto +++ b/api/proto/disperser/v2/disperser_v2.proto @@ -114,16 +114,14 @@ message BlobVerificationInfo { } message Attestation { - repeated uint32 nonSignerQuorumBitmapIndices = 1; - repeated bytes nonSignerPubkeys = 2; - repeated bytes quorumApks = 3; - bytes apkG2 = 4; - bytes sigma = 5; - repeated uint32 quorumApkIndices = 6; - repeated uint32 totalStakeIndices = 7; - repeated NonSignerStakeIndicesForQuorum nonSignerStakeIndices = 8; -} - -message NonSignerStakeIndicesForQuorum { - repeated uint32 indices = 1; + // Serialized bytes of non signer public keys (G1 points) + repeated bytes non_signer_pubkeys = 1; + // Serialized bytes of G2 point that represents aggregate public key of all signers + bytes apk_g2 = 2; + // Serialized bytes of aggregate public keys (G1 points) from all nodes for each quorum + repeated bytes quorum_apks = 3; + // Serialized bytes of aggregate signature + bytes sigma = 4; + // Relevant quorum numbers for the attestation + repeated uint32 quorum_numbers = 5; } diff --git a/core/v2/types.go b/core/v2/types.go index e26f2669a9..dde552cc5c 100644 --- a/core/v2/types.go +++ b/core/v2/types.go @@ -395,6 +395,23 @@ type Batch struct { BlobCertificates []*BlobCertificate } +type Attestation struct { + *BatchHeader + + // AttestedAt is the time the attestation was made + AttestedAt uint64 + // NonSignerPubKeys are the public keys of the operators that did not sign the blob + NonSignerPubKeys []*core.G1Point + // APKG2 is the aggregate public key of all signers + APKG2 *core.G2Point + // QuorumAPKs is the aggregate public keys of all operators in each quorum + QuorumAPKs map[core.QuorumID]*core.G1Point + // Sigma is the aggregate signature of all signers + Sigma *core.Signature + // QuorumNumbers contains the quorums relevant for the attestation + QuorumNumbers []core.QuorumID +} + type BlobVerificationInfo struct { BlobCertificate *BlobCertificate BlobIndex uint32 diff --git a/disperser/common/v2/blobstore/dynamo_metadata_store.go b/disperser/common/v2/blobstore/dynamo_metadata_store.go index 96b471f0e8..621462d78c 100644 --- a/disperser/common/v2/blobstore/dynamo_metadata_store.go +++ b/disperser/common/v2/blobstore/dynamo_metadata_store.go @@ -30,10 +30,13 @@ const ( blobKeyPrefix = "BlobKey#" dispersalKeyPrefix = "Dispersal#" + batchHeaderKeyPrefix = "BatchHeader#" blobMetadataSK = "BlobMetadata" blobCertSK = "BlobCertificate" dispersalRequestSKPrefix = "DispersalRequest#" dispersalResponseSKPrefix = "DispersalResponse#" + batchHeaderSK = "BatchHeader" + attestationSK = "Attestation" ) var ( @@ -339,6 +342,86 @@ func (s *BlobMetadataStore) GetDispersalResponse(ctx context.Context, batchHeade return res, nil } +func (s *BlobMetadataStore) PutBatchHeader(ctx context.Context, batchHeader *corev2.BatchHeader) error { + item, err := MarshalBatchHeader(batchHeader) + if err != nil { + return err + } + + err = s.dynamoDBClient.PutItemWithCondition(ctx, s.tableName, item, "attribute_not_exists(PK) AND attribute_not_exists(SK)", nil, nil) + if errors.Is(err, commondynamodb.ErrConditionFailed) { + return common.ErrAlreadyExists + } + + return err +} + +func (s *BlobMetadataStore) GetBatchHeader(ctx context.Context, batchHeaderHash [32]byte) (*corev2.BatchHeader, error) { + item, err := s.dynamoDBClient.GetItem(ctx, s.tableName, map[string]types.AttributeValue{ + "PK": &types.AttributeValueMemberS{ + Value: batchHeaderKeyPrefix + hex.EncodeToString(batchHeaderHash[:]), + }, + "SK": &types.AttributeValueMemberS{ + Value: batchHeaderSK, + }, + }) + + if err != nil { + return nil, err + } + + if item == nil { + return nil, fmt.Errorf("%w: batch header not found for hash %x", common.ErrMetadataNotFound, batchHeaderHash) + } + + header, err := UnmarshalBatchHeader(item) + if err != nil { + return nil, err + } + + return header, nil +} + +func (s *BlobMetadataStore) PutAttestation(ctx context.Context, attestation *corev2.Attestation) error { + item, err := MarshalAttestation(attestation) + if err != nil { + return err + } + + err = s.dynamoDBClient.PutItemWithCondition(ctx, s.tableName, item, "attribute_not_exists(PK) AND attribute_not_exists(SK)", nil, nil) + if errors.Is(err, commondynamodb.ErrConditionFailed) { + return common.ErrAlreadyExists + } + + return err +} + +func (s *BlobMetadataStore) GetAttestation(ctx context.Context, batchHeaderHash [32]byte) (*corev2.Attestation, error) { + item, err := s.dynamoDBClient.GetItem(ctx, s.tableName, map[string]types.AttributeValue{ + "PK": &types.AttributeValueMemberS{ + Value: batchHeaderKeyPrefix + hex.EncodeToString(batchHeaderHash[:]), + }, + "SK": &types.AttributeValueMemberS{ + Value: attestationSK, + }, + }) + + if err != nil { + return nil, err + } + + if item == nil { + return nil, fmt.Errorf("%w: attestation not found for hash %x", common.ErrMetadataNotFound, batchHeaderHash) + } + + attestation, err := UnmarshalAttestation(item) + if err != nil { + return nil, err + } + + return attestation, nil +} + func GenerateTableSchema(tableName string, readCapacityUnits int64, writeCapacityUnits int64) *dynamodb.CreateTableInput { return &dynamodb.CreateTableInput{ AttributeDefinitions: []types.AttributeDefinition{ @@ -638,6 +721,62 @@ func UnmarshalDispersalResponse(item commondynamodb.Item) (*corev2.DispersalResp return &res, nil } +func MarshalBatchHeader(batchHeader *corev2.BatchHeader) (commondynamodb.Item, error) { + fields, err := attributevalue.MarshalMap(batchHeader) + if err != nil { + return nil, fmt.Errorf("failed to marshal batch header: %w", err) + } + + hash, err := batchHeader.Hash() + if err != nil { + return nil, fmt.Errorf("failed to hash batch header: %w", err) + } + hashstr := hex.EncodeToString(hash[:]) + + fields["PK"] = &types.AttributeValueMemberS{Value: batchHeaderKeyPrefix + hashstr} + fields["SK"] = &types.AttributeValueMemberS{Value: batchHeaderSK} + + return fields, nil +} + +func UnmarshalBatchHeader(item commondynamodb.Item) (*corev2.BatchHeader, error) { + header := corev2.BatchHeader{} + err := attributevalue.UnmarshalMap(item, &header) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal batch header: %w", err) + } + + return &header, nil +} + +func MarshalAttestation(attestation *corev2.Attestation) (commondynamodb.Item, error) { + fields, err := attributevalue.MarshalMap(attestation) + if err != nil { + return nil, fmt.Errorf("failed to marshal attestation: %w", err) + } + + hash, err := attestation.BatchHeader.Hash() + if err != nil { + return nil, fmt.Errorf("failed to hash batch header: %w", err) + } + hashstr := hex.EncodeToString(hash[:]) + + fields["PK"] = &types.AttributeValueMemberS{Value: batchHeaderKeyPrefix + hashstr} + fields["SK"] = &types.AttributeValueMemberS{Value: attestationSK} + + return fields, nil +} + +func UnmarshalAttestation(item commondynamodb.Item) (*corev2.Attestation, error) { + attestation := corev2.Attestation{} + err := attributevalue.UnmarshalMap(item, &attestation) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal attestation: %w", err) + } + + return &attestation, nil +} + func hexToHash(h string) ([32]byte, error) { s := strings.TrimPrefix(h, "0x") s = strings.TrimPrefix(s, "0X") diff --git a/disperser/common/v2/blobstore/dynamo_metadata_store_test.go b/disperser/common/v2/blobstore/dynamo_metadata_store_test.go index 71c14f1be7..89f5585b8f 100644 --- a/disperser/common/v2/blobstore/dynamo_metadata_store_test.go +++ b/disperser/common/v2/blobstore/dynamo_metadata_store_test.go @@ -276,6 +276,71 @@ func TestBlobMetadataStoreDispersals(t *testing.T) { }) } +func TestBlobMetadataStoreBatchAttestation(t *testing.T) { + ctx := context.Background() + h := &corev2.BatchHeader{ + BatchRoot: [32]byte{1, 2, 3}, + ReferenceBlockNumber: 100, + } + bhh, err := h.Hash() + assert.NoError(t, err) + + err = blobMetadataStore.PutBatchHeader(ctx, h) + assert.NoError(t, err) + + fetchedHeader, err := blobMetadataStore.GetBatchHeader(ctx, bhh) + assert.NoError(t, err) + assert.Equal(t, h, fetchedHeader) + + // attempt to put batch header with the same key should fail + err = blobMetadataStore.PutBatchHeader(ctx, h) + assert.ErrorIs(t, err, common.ErrAlreadyExists) + + keyPair, err := core.GenRandomBlsKeys() + assert.NoError(t, err) + + apk := keyPair.GetPubKeyG2() + attestation := &corev2.Attestation{ + BatchHeader: h, + AttestedAt: uint64(time.Now().UnixNano()), + NonSignerPubKeys: []*core.G1Point{ + core.NewG1Point(big.NewInt(1), big.NewInt(2)), + core.NewG1Point(big.NewInt(3), big.NewInt(4)), + }, + APKG2: apk, + QuorumAPKs: map[uint8]*core.G1Point{ + 0: core.NewG1Point(big.NewInt(5), big.NewInt(6)), + 1: core.NewG1Point(big.NewInt(7), big.NewInt(8)), + }, + Sigma: &core.Signature{ + G1Point: core.NewG1Point(big.NewInt(9), big.NewInt(10)), + }, + QuorumNumbers: []core.QuorumID{0, 1}, + } + + err = blobMetadataStore.PutAttestation(ctx, attestation) + assert.NoError(t, err) + + fetchedAttestation, err := blobMetadataStore.GetAttestation(ctx, bhh) + assert.NoError(t, err) + assert.Equal(t, attestation, fetchedAttestation) + + // attempt to put attestation with the same key should fail + err = blobMetadataStore.PutAttestation(ctx, attestation) + assert.ErrorIs(t, err, common.ErrAlreadyExists) + + deleteItems(t, []commondynamodb.Key{ + { + "PK": &types.AttributeValueMemberS{Value: "BatchHeader#" + hex.EncodeToString(bhh[:])}, + "SK": &types.AttributeValueMemberS{Value: "BatchHeader"}, + }, + { + "PK": &types.AttributeValueMemberS{Value: "BatchHeader#" + hex.EncodeToString(bhh[:])}, + "SK": &types.AttributeValueMemberS{Value: "Attestation"}, + }, + }) +} + func deleteItems(t *testing.T, keys []commondynamodb.Key) { failed, err := dynamoClient.DeleteItems(context.Background(), metadataTableName, keys) assert.NoError(t, err)