From 00bdade1c21f9a3289630f50cc8f82ab9390756c Mon Sep 17 00:00:00 2001 From: Jian Xiao <99709935+jianoaix@users.noreply.github.com> Date: Wed, 17 Jul 2024 09:42:51 -0700 Subject: [PATCH] [5/N] Chunk encoding optimization: Add support of new encoding at Node (#636) --- api/grpc/node/node.pb.go | 319 +++++++++++++++++++------------------- api/proto/node/node.proto | 18 ++- core/data.go | 18 ++- core/data_test.go | 4 +- node/grpc/server.go | 4 +- node/grpc/utils.go | 23 ++- node/store.go | 154 ++++++++++++++---- node/store_test.go | 138 ++++++++++++++--- node/utils.go | 16 ++ 9 files changed, 463 insertions(+), 231 deletions(-) diff --git a/api/grpc/node/node.pb.go b/api/grpc/node/node.pb.go index 06c625e61..5a61d3e79 100644 --- a/api/grpc/node/node.pb.go +++ b/api/grpc/node/node.pb.go @@ -21,54 +21,55 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// Describes how the chunks above are encoded. -type RetrieveChunksReply_ChunkEncoding int32 +// This describes the chunks returned in RetrieveChunksReply are encoded. +// Used to facilitate the decoding of chunks. +type ChunkEncoding int32 const ( - RetrieveChunksReply_UNKNOWN RetrieveChunksReply_ChunkEncoding = 0 - RetrieveChunksReply_GNARK RetrieveChunksReply_ChunkEncoding = 1 - RetrieveChunksReply_GOB RetrieveChunksReply_ChunkEncoding = 2 + ChunkEncoding_UNKNOWN ChunkEncoding = 0 + ChunkEncoding_GNARK ChunkEncoding = 1 + ChunkEncoding_GOB ChunkEncoding = 2 ) -// Enum value maps for RetrieveChunksReply_ChunkEncoding. +// Enum value maps for ChunkEncoding. var ( - RetrieveChunksReply_ChunkEncoding_name = map[int32]string{ + ChunkEncoding_name = map[int32]string{ 0: "UNKNOWN", 1: "GNARK", 2: "GOB", } - RetrieveChunksReply_ChunkEncoding_value = map[string]int32{ + ChunkEncoding_value = map[string]int32{ "UNKNOWN": 0, "GNARK": 1, "GOB": 2, } ) -func (x RetrieveChunksReply_ChunkEncoding) Enum() *RetrieveChunksReply_ChunkEncoding { - p := new(RetrieveChunksReply_ChunkEncoding) +func (x ChunkEncoding) Enum() *ChunkEncoding { + p := new(ChunkEncoding) *p = x return p } -func (x RetrieveChunksReply_ChunkEncoding) String() string { +func (x ChunkEncoding) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (RetrieveChunksReply_ChunkEncoding) Descriptor() protoreflect.EnumDescriptor { +func (ChunkEncoding) Descriptor() protoreflect.EnumDescriptor { return file_node_node_proto_enumTypes[0].Descriptor() } -func (RetrieveChunksReply_ChunkEncoding) Type() protoreflect.EnumType { +func (ChunkEncoding) Type() protoreflect.EnumType { return &file_node_node_proto_enumTypes[0] } -func (x RetrieveChunksReply_ChunkEncoding) Number() protoreflect.EnumNumber { +func (x ChunkEncoding) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } -// Deprecated: Use RetrieveChunksReply_ChunkEncoding.Descriptor instead. -func (RetrieveChunksReply_ChunkEncoding) EnumDescriptor() ([]byte, []int) { - return file_node_node_proto_rawDescGZIP(), []int{3, 0} +// Deprecated: Use ChunkEncoding.Descriptor instead. +func (ChunkEncoding) EnumDescriptor() ([]byte, []int) { + return file_node_node_proto_rawDescGZIP(), []int{0} } type StoreChunksRequest struct { @@ -253,8 +254,9 @@ type RetrieveChunksReply struct { unknownFields protoimpl.UnknownFields // All chunks the Node is storing for the requested blob per RetrieveChunksRequest. - Chunks [][]byte `protobuf:"bytes,1,rep,name=chunks,proto3" json:"chunks,omitempty"` - Encoding RetrieveChunksReply_ChunkEncoding `protobuf:"varint,2,opt,name=encoding,proto3,enum=node.RetrieveChunksReply_ChunkEncoding" json:"encoding,omitempty"` + Chunks [][]byte `protobuf:"bytes,1,rep,name=chunks,proto3" json:"chunks,omitempty"` + // How the above chunks encoded. + Encoding ChunkEncoding `protobuf:"varint,2,opt,name=encoding,proto3,enum=node.ChunkEncoding" json:"encoding,omitempty"` } func (x *RetrieveChunksReply) Reset() { @@ -296,11 +298,11 @@ func (x *RetrieveChunksReply) GetChunks() [][]byte { return nil } -func (x *RetrieveChunksReply) GetEncoding() RetrieveChunksReply_ChunkEncoding { +func (x *RetrieveChunksReply) GetEncoding() ChunkEncoding { if x != nil { return x.Encoding } - return RetrieveChunksReply_UNKNOWN + return ChunkEncoding_UNKNOWN } // See RetrieveChunksRequest for documentation of each parameter of GetBlobHeaderRequest. @@ -1062,126 +1064,125 @@ var file_node_node_proto_rawDesc = []byte{ 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1b, 0x0a, 0x09, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x08, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x49, 0x64, 0x22, 0xa4, 0x01, - 0x0a, 0x13, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x12, 0x43, 0x0a, - 0x08, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x27, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x43, - 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, - 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, - 0x6e, 0x67, 0x22, 0x30, 0x0a, 0x0d, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x45, 0x6e, 0x63, 0x6f, 0x64, - 0x69, 0x6e, 0x67, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, - 0x12, 0x09, 0x0a, 0x05, 0x47, 0x4e, 0x41, 0x52, 0x4b, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x47, - 0x4f, 0x42, 0x10, 0x02, 0x22, 0x7e, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x11, - 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x68, 0x61, 0x73, - 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x62, 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x62, - 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x62, 0x6c, - 0x6f, 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1b, 0x0a, 0x09, 0x71, 0x75, 0x6f, 0x72, 0x75, - 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x71, 0x75, 0x6f, 0x72, - 0x75, 0x6d, 0x49, 0x64, 0x22, 0x70, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x62, 0x6c, - 0x6f, 0x62, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x10, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x27, 0x0a, - 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, - 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x3b, 0x0a, 0x0b, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, - 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x14, 0x0a, - 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x22, 0x58, 0x0a, 0x04, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x28, 0x0a, 0x06, 0x68, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x07, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x42, 0x75, - 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x07, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x22, 0x38, 0x0a, - 0x06, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x68, 0x75, 0x6e, 0x6b, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x12, - 0x16, 0x0a, 0x06, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x06, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x5a, 0x0a, 0x0c, 0x47, 0x32, 0x43, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x11, 0x0a, 0x04, 0x78, 0x5f, 0x61, 0x30, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x78, 0x41, 0x30, 0x12, 0x11, 0x0a, 0x04, 0x78, 0x5f, - 0x61, 0x31, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x78, 0x41, 0x31, 0x12, 0x11, 0x0a, - 0x04, 0x79, 0x5f, 0x61, 0x30, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x79, 0x41, 0x30, - 0x12, 0x11, 0x0a, 0x04, 0x79, 0x5f, 0x61, 0x31, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, - 0x79, 0x41, 0x31, 0x22, 0xae, 0x02, 0x0a, 0x0a, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x47, 0x31, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0a, 0x63, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x3f, 0x0a, 0x11, 0x6c, 0x65, 0x6e, 0x67, - 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x47, 0x32, 0x43, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x10, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x43, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x0c, 0x6c, 0x65, 0x6e, - 0x67, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x12, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x47, 0x32, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, - 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x6f, 0x66, - 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x3b, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, - 0x75, 0x6d, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x14, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, 0x72, - 0x75, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x49, 0x64, 0x22, 0xd6, 0x01, 0x0a, 0x0e, 0x42, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, - 0x72, 0x75, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, 0x71, 0x75, 0x6f, 0x72, 0x75, - 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x71, 0x75, 0x6f, 0x72, - 0x75, 0x6d, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x13, 0x61, 0x64, 0x76, 0x65, 0x72, 0x73, 0x61, 0x72, - 0x79, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x12, 0x61, 0x64, 0x76, 0x65, 0x72, 0x73, 0x61, 0x72, 0x79, 0x54, 0x68, 0x72, 0x65, - 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x35, 0x0a, 0x16, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x15, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x21, 0x0a, 0x0c, - 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, - 0x1c, 0x0a, 0x09, 0x72, 0x61, 0x74, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x09, 0x72, 0x61, 0x74, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x62, 0x0a, - 0x0b, 0x42, 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, - 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x09, 0x62, 0x61, 0x74, 0x63, 0x68, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x34, 0x0a, 0x16, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x22, 0x11, 0x0a, 0x0f, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x22, 0x81, 0x01, 0x0a, 0x0d, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6d, 0x76, 0x65, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x6d, 0x76, 0x65, 0x72, 0x12, 0x12, - 0x0a, 0x04, 0x61, 0x72, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, - 0x63, 0x68, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x6f, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x70, 0x75, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x43, 0x70, 0x75, 0x12, 0x1b, 0x0a, 0x09, 0x6d, - 0x65, 0x6d, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, - 0x6d, 0x65, 0x6d, 0x42, 0x79, 0x74, 0x65, 0x73, 0x32, 0x88, 0x01, 0x0a, 0x09, 0x44, 0x69, 0x73, - 0x70, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x12, 0x41, 0x0a, 0x0b, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x43, - 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x12, 0x18, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x6f, - 0x72, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x16, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x75, 0x6e, - 0x6b, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x08, 0x4e, 0x6f, 0x64, - 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x15, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4e, 0x6f, 0x64, - 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x22, 0x00, 0x32, 0xda, 0x01, 0x0a, 0x09, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, - 0x6c, 0x12, 0x4a, 0x0a, 0x0e, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x43, 0x68, 0x75, - 0x6e, 0x6b, 0x73, 0x12, 0x1b, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x52, 0x65, 0x74, 0x72, 0x69, - 0x65, 0x76, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x19, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, - 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x47, 0x0a, - 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1a, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x08, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x15, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, - 0x42, 0x2c, 0x5a, 0x2a, 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, 0x6e, 0x6f, 0x64, 0x65, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x01, 0x28, 0x0d, 0x52, 0x08, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x49, 0x64, 0x22, 0x5e, 0x0a, + 0x13, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x12, 0x2f, 0x0a, 0x08, + 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x45, 0x6e, 0x63, 0x6f, 0x64, + 0x69, 0x6e, 0x67, 0x52, 0x08, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x7e, 0x0a, + 0x14, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x68, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0f, 0x62, 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x61, 0x73, + 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x12, 0x1b, 0x0a, 0x09, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x08, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x49, 0x64, 0x22, 0x70, 0x0a, + 0x12, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x68, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x62, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x27, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4d, 0x65, 0x72, + 0x6b, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, + 0x3b, 0x0a, 0x0b, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x16, + 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, + 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x58, 0x0a, 0x04, + 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x28, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x62, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x26, + 0x0a, 0x07, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x0c, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x07, 0x62, + 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x22, 0x38, 0x0a, 0x06, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, + 0x52, 0x06, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x6e, 0x64, + 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, + 0x22, 0x5a, 0x0a, 0x0c, 0x47, 0x32, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x12, 0x11, 0x0a, 0x04, 0x78, 0x5f, 0x61, 0x30, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, + 0x78, 0x41, 0x30, 0x12, 0x11, 0x0a, 0x04, 0x78, 0x5f, 0x61, 0x31, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x03, 0x78, 0x41, 0x31, 0x12, 0x11, 0x0a, 0x04, 0x79, 0x5f, 0x61, 0x30, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x79, 0x41, 0x30, 0x12, 0x11, 0x0a, 0x04, 0x79, 0x5f, 0x61, + 0x31, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x79, 0x41, 0x31, 0x22, 0xae, 0x02, 0x0a, + 0x0a, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x34, 0x0a, 0x0a, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x31, 0x43, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, + 0x74, 0x12, 0x3f, 0x0a, 0x11, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x47, 0x32, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x52, 0x10, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, + 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x0c, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, + 0x6f, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x47, 0x32, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x6c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x12, 0x3b, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x68, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x0d, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x1d, + 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x22, 0xd6, 0x01, + 0x0a, 0x0e, 0x42, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x1b, 0x0a, 0x09, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x08, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x49, 0x64, 0x12, 0x2f, 0x0a, + 0x13, 0x61, 0x64, 0x76, 0x65, 0x72, 0x73, 0x61, 0x72, 0x79, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, + 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x61, 0x64, 0x76, 0x65, + 0x72, 0x73, 0x61, 0x72, 0x79, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x35, + 0x0a, 0x16, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, + 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x15, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x68, 0x72, 0x65, + 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x6c, + 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x68, 0x75, + 0x6e, 0x6b, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x61, 0x74, 0x65, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, 0x61, 0x74, + 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x62, 0x0a, 0x0b, 0x42, 0x61, 0x74, 0x63, 0x68, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x72, + 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x61, 0x74, 0x63, 0x68, + 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x11, 0x0a, 0x0f, 0x4e, 0x6f, + 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x81, 0x01, + 0x0a, 0x0d, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6d, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x73, 0x65, 0x6d, 0x76, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x63, 0x68, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x63, 0x68, 0x12, 0x0e, 0x0a, 0x02, 0x6f, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x6f, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x6e, + 0x75, 0x6d, 0x5f, 0x63, 0x70, 0x75, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6e, 0x75, + 0x6d, 0x43, 0x70, 0x75, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x5f, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x42, 0x79, 0x74, 0x65, + 0x73, 0x2a, 0x30, 0x0a, 0x0d, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, + 0x6e, 0x67, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, + 0x09, 0x0a, 0x05, 0x47, 0x4e, 0x41, 0x52, 0x4b, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x4f, + 0x42, 0x10, 0x02, 0x32, 0x88, 0x01, 0x0a, 0x09, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x61, + 0x6c, 0x12, 0x41, 0x0a, 0x0b, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, + 0x12, 0x18, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x75, + 0x6e, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x08, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x15, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4e, + 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x32, 0xda, + 0x01, 0x0a, 0x09, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, 0x6c, 0x12, 0x4a, 0x0a, 0x0e, + 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x12, 0x1b, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x43, 0x68, + 0x75, 0x6e, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, + 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, + 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, + 0x00, 0x12, 0x38, 0x0a, 0x08, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x15, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4e, 0x6f, 0x64, 0x65, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x2c, 0x5a, 0x2a, 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, 0x6e, 0x6f, 0x64, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -1199,28 +1200,28 @@ func file_node_node_proto_rawDescGZIP() []byte { var file_node_node_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_node_node_proto_msgTypes = make([]protoimpl.MessageInfo, 15) var file_node_node_proto_goTypes = []interface{}{ - (RetrieveChunksReply_ChunkEncoding)(0), // 0: node.RetrieveChunksReply.ChunkEncoding - (*StoreChunksRequest)(nil), // 1: node.StoreChunksRequest - (*StoreChunksReply)(nil), // 2: node.StoreChunksReply - (*RetrieveChunksRequest)(nil), // 3: node.RetrieveChunksRequest - (*RetrieveChunksReply)(nil), // 4: node.RetrieveChunksReply - (*GetBlobHeaderRequest)(nil), // 5: node.GetBlobHeaderRequest - (*GetBlobHeaderReply)(nil), // 6: node.GetBlobHeaderReply - (*MerkleProof)(nil), // 7: node.MerkleProof - (*Blob)(nil), // 8: node.Blob - (*Bundle)(nil), // 9: node.Bundle - (*G2Commitment)(nil), // 10: node.G2Commitment - (*BlobHeader)(nil), // 11: node.BlobHeader - (*BlobQuorumInfo)(nil), // 12: node.BlobQuorumInfo - (*BatchHeader)(nil), // 13: node.BatchHeader - (*NodeInfoRequest)(nil), // 14: node.NodeInfoRequest - (*NodeInfoReply)(nil), // 15: node.NodeInfoReply - (*common.G1Commitment)(nil), // 16: common.G1Commitment + (ChunkEncoding)(0), // 0: node.ChunkEncoding + (*StoreChunksRequest)(nil), // 1: node.StoreChunksRequest + (*StoreChunksReply)(nil), // 2: node.StoreChunksReply + (*RetrieveChunksRequest)(nil), // 3: node.RetrieveChunksRequest + (*RetrieveChunksReply)(nil), // 4: node.RetrieveChunksReply + (*GetBlobHeaderRequest)(nil), // 5: node.GetBlobHeaderRequest + (*GetBlobHeaderReply)(nil), // 6: node.GetBlobHeaderReply + (*MerkleProof)(nil), // 7: node.MerkleProof + (*Blob)(nil), // 8: node.Blob + (*Bundle)(nil), // 9: node.Bundle + (*G2Commitment)(nil), // 10: node.G2Commitment + (*BlobHeader)(nil), // 11: node.BlobHeader + (*BlobQuorumInfo)(nil), // 12: node.BlobQuorumInfo + (*BatchHeader)(nil), // 13: node.BatchHeader + (*NodeInfoRequest)(nil), // 14: node.NodeInfoRequest + (*NodeInfoReply)(nil), // 15: node.NodeInfoReply + (*common.G1Commitment)(nil), // 16: common.G1Commitment } var file_node_node_proto_depIdxs = []int32{ 13, // 0: node.StoreChunksRequest.batch_header:type_name -> node.BatchHeader 8, // 1: node.StoreChunksRequest.blobs:type_name -> node.Blob - 0, // 2: node.RetrieveChunksReply.encoding:type_name -> node.RetrieveChunksReply.ChunkEncoding + 0, // 2: node.RetrieveChunksReply.encoding:type_name -> node.ChunkEncoding 11, // 3: node.GetBlobHeaderReply.blob_header:type_name -> node.BlobHeader 7, // 4: node.GetBlobHeaderReply.proof:type_name -> node.MerkleProof 11, // 5: node.Blob.header:type_name -> node.BlobHeader diff --git a/api/proto/node/node.proto b/api/proto/node/node.proto index 65128bb0f..932135caf 100644 --- a/api/proto/node/node.proto +++ b/api/proto/node/node.proto @@ -55,19 +55,21 @@ message RetrieveChunksRequest { uint32 quorum_id = 3; } +// This describes how the chunks returned in RetrieveChunksReply are encoded. +// Used to facilitate the decoding of chunks. +enum ChunkEncoding { + UNKNOWN = 0; + GNARK = 1; + GOB = 2; +} + message RetrieveChunksReply { // All chunks the Node is storing for the requested blob per RetrieveChunksRequest. repeated bytes chunks = 1; - // Describes how the chunks above are encoded. - enum ChunkEncoding { - UNKNOWN = 0; - GNARK = 1; - GOB = 2; - } + // How the above chunks encoded. ChunkEncoding encoding = 2; } - // See RetrieveChunksRequest for documentation of each parameter of GetBlobHeaderRequest. message GetBlobHeaderRequest { bytes batch_header_hash = 1; @@ -177,5 +179,5 @@ message NodeInfoReply { string arch = 2; string os = 3; uint32 num_cpu = 4; - uint64 mem_bytes = 5; + uint64 mem_bytes = 5; } diff --git a/core/data.go b/core/data.go index ca1ad1397..f5966bec6 100644 --- a/core/data.go +++ b/core/data.go @@ -30,13 +30,23 @@ type SecurityParam struct { QuorumRate common.RateParam } +type BundleEncodingFormat = uint8 + const ( // We use uint8 to count the number of quorums, so we can have at most 255 quorums, // which means the max ID can not be larger than 254 (from 0 to 254, there are 255 // different IDs). MaxQuorumID = 254 - GnarkBundleEncodingFormat = 1 + // How many bits for the bundle's header. + NumBundleHeaderBits = 64 + // How many bits (out of header) for representing the bundle's encoding format. + NumBundleEncodingFormatBits = 8 + + // The list of supported encoding formats for bundle. + // Values must be in range [0, 255]. + GobBundleEncodingFormat BundleEncodingFormat = 0 + GnarkBundleEncodingFormat BundleEncodingFormat = 1 ) func (s *SecurityParam) String() string { @@ -198,7 +208,7 @@ func (b Bundle) Serialize() ([]byte, error) { } result := make([]byte, size+8) buf := result - metadata := uint64(GnarkBundleEncodingFormat) | (uint64(len(b[0].Coeffs)) << 8) + metadata := (uint64(GnarkBundleEncodingFormat) << (NumBundleHeaderBits - NumBundleEncodingFormatBits)) | uint64(len(b[0].Coeffs)) binary.LittleEndian.PutUint64(buf, metadata) buf = buf[8:] for _, f := range b { @@ -218,10 +228,10 @@ func (b Bundle) Deserialize(data []byte) (Bundle, error) { } // Parse metadata meta := binary.LittleEndian.Uint64(data) - if (meta & 0xFF) != GnarkBundleEncodingFormat { + if (meta >> (NumBundleHeaderBits - NumBundleEncodingFormatBits)) != uint64(GnarkBundleEncodingFormat) { return nil, errors.New("invalid bundle data encoding format") } - chunkLen := meta >> 8 + chunkLen := (meta << NumBundleEncodingFormatBits) >> NumBundleEncodingFormatBits if chunkLen == 0 { return nil, errors.New("chunk length must be greater than zero") } diff --git a/core/data_test.go b/core/data_test.go index 184866b6e..9cbb9da8a 100644 --- a/core/data_test.go +++ b/core/data_test.go @@ -58,19 +58,19 @@ func TestInvalidBundleDeser(t *testing.T) { assert.EqualError(t, err, "invalid bundle data encoding format") invliadChunkLen := make([]byte, 0, 8) - invliadChunkLen = append(invliadChunkLen, byte(1)) for i := 0; i < 7; i++ { invliadChunkLen = append(invliadChunkLen, byte(0)) } + invliadChunkLen = append(invliadChunkLen, byte(1)) _, err = new(core.Bundle).Deserialize(invliadChunkLen) assert.EqualError(t, err, "chunk length must be greater than zero") data := make([]byte, 0, 9) - data = append(data, byte(1)) for i := 0; i < 6; i++ { data = append(data, byte(0)) } data = append(data, byte(0b00100000)) + data = append(data, byte(1)) data = append(data, byte(5)) data = append(data, byte(0b01000000)) _, err = new(core.Bundle).Deserialize(data) diff --git a/node/grpc/server.go b/node/grpc/server.go index b6dbae008..598386f9f 100644 --- a/node/grpc/server.go +++ b/node/grpc/server.go @@ -294,13 +294,13 @@ func (s *Server) RetrieveChunks(ctx context.Context, in *pb.RetrieveChunksReques return nil, errors.New("request rate limited") } - chunks, ok := s.node.Store.GetChunks(ctx, batchHeaderHash, int(in.GetBlobIndex()), uint8(in.GetQuorumId())) + chunks, format, ok := s.node.Store.GetChunks(ctx, batchHeaderHash, int(in.GetBlobIndex()), uint8(in.GetQuorumId())) if !ok { s.node.Metrics.RecordRPCRequest("RetrieveChunks", "failure", time.Since(start)) return nil, fmt.Errorf("could not find chunks for batchHeaderHash %v, blob index: %v, quorumID: %v", batchHeaderHash, in.GetBlobIndex(), in.GetQuorumId()) } s.node.Metrics.RecordRPCRequest("RetrieveChunks", "success", time.Since(start)) - return &pb.RetrieveChunksReply{Chunks: chunks}, nil + return &pb.RetrieveChunksReply{Chunks: chunks, Encoding: format}, nil } func (s *Server) GetBlobHeader(ctx context.Context, in *pb.GetBlobHeaderRequest) (*pb.GetBlobHeaderReply, error) { diff --git a/node/grpc/utils.go b/node/grpc/utils.go index f60c7e235..45659c5cc 100644 --- a/node/grpc/utils.go +++ b/node/grpc/utils.go @@ -54,17 +54,30 @@ func GetBlobMessages(in *pb.StoreChunksRequest, numWorkers int) ([]*core.BlobMes return } + format := node.GetBundleEncodingFormat(blob) bundles := make(map[core.QuorumID]core.Bundle, len(blob.GetBundles())) - for j, chunks := range blob.GetBundles() { + for j, bundle := range blob.GetBundles() { quorumID := blob.GetHeader().GetQuorumHeaders()[j].GetQuorumId() - bundles[uint8(quorumID)] = make([]*encoding.Frame, len(chunks.GetChunks())) - for k, data := range chunks.GetChunks() { - chunk, err := new(encoding.Frame).Deserialize(data) + if format == core.GnarkBundleEncodingFormat { + bundleMsg, err := new(core.Bundle).Deserialize(bundle.GetBundle()) if err != nil { resultChan <- err return } - bundles[uint8(quorumID)][k] = chunk + bundles[uint8(quorumID)] = bundleMsg + } else if format == core.GobBundleEncodingFormat { + bundles[uint8(quorumID)] = make([]*encoding.Frame, len(bundle.GetChunks())) + for k, data := range bundle.GetChunks() { + chunk, err := new(encoding.Frame).Deserialize(data) + if err != nil { + resultChan <- err + return + } + bundles[uint8(quorumID)][k] = chunk + } + } else { + resultChan <- fmt.Errorf("invalid bundle encoding format: %d", format) + return } } diff --git a/node/store.go b/node/store.go index 4191e7dc4..06849a784 100644 --- a/node/store.go +++ b/node/store.go @@ -5,12 +5,15 @@ import ( "context" "encoding/binary" "errors" + "fmt" "time" "github.com/Layr-Labs/eigenda/api/grpc/node" "github.com/Layr-Labs/eigenda/core" + "github.com/Layr-Labs/eigenda/encoding" "github.com/Layr-Labs/eigenda/node/leveldb" "github.com/Layr-Labs/eigensdk-go/logging" + "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/ethereum/go-ethereum/common/hexutil" "google.golang.org/protobuf/proto" ) @@ -241,12 +244,21 @@ func (s *Store) StoreBatch(ctx context.Context, header *core.BatchHeader, blobs if len(rawBlob.GetBundles()) != len(blob.Bundles) { return nil, errors.New("internal error: the number of bundles in parsed blob must be the same as in raw blob") } + format := GetBundleEncodingFormat(rawBlob) + rawBundles := make(map[core.QuorumID][]byte) rawChunks := make(map[core.QuorumID][][]byte) - for i, chunks := range rawBlob.GetBundles() { + for i, bundle := range rawBlob.GetBundles() { quorumID := uint8(rawBlob.GetHeader().GetQuorumHeaders()[i].GetQuorumId()) - rawChunks[quorumID] = make([][]byte, len(chunks.GetChunks())) - for j, chunk := range chunks.GetChunks() { - rawChunks[quorumID][j] = chunk + if format == core.GnarkBundleEncodingFormat { + if len(bundle.GetChunks()) > 0 && len(bundle.GetChunks()[0]) > 0 { + return nil, errors.New("chunks of a bundle are encoded together already") + } + rawBundles[quorumID] = bundle.GetBundle() + } else { + rawChunks[quorumID] = make([][]byte, len(bundle.GetChunks())) + for j, chunk := range bundle.GetChunks() { + rawChunks[quorumID][j] = chunk + } } } serializationDuration += time.Since(start) @@ -258,22 +270,36 @@ func (s *Store) StoreBatch(ctx context.Context, header *core.BatchHeader, blobs log.Error("Cannot generate the key for storing blob:", "err", err) return nil, err } - if len(rawChunks[quorumID]) != len(bundle) { - return nil, errors.New("internal error: the number of chunks in parsed blob bundle must be the same as in raw blob bundle") - } - bundleRaw := make([][]byte, len(bundle)) - for i := 0; i < len(bundle); i++ { - bundleRaw[i] = rawChunks[quorumID][i] + if format == core.GnarkBundleEncodingFormat { + rawBundle, ok := rawBundles[quorumID] + if ok { + size += int64(len(rawBundle)) + keys = append(keys, key) + values = append(values, rawBundle) + } + } else if format == core.GobBundleEncodingFormat { + if len(rawChunks[quorumID]) != len(bundle) { + return nil, errors.New("internal error: the number of chunks in parsed blob bundle must be the same as in raw blob bundle") + } + chunksBytes, ok := rawChunks[quorumID] + if ok { + + bundleRaw := make([][]byte, len(bundle)) + for i := 0; i < len(bundle); i++ { + bundleRaw[i] = chunksBytes[i] + } + chunkBytes, err := EncodeChunks(bundleRaw) + if err != nil { + return nil, err + } + size += int64(len(chunkBytes)) + keys = append(keys, key) + values = append(values, chunkBytes) + } + } else { + return nil, fmt.Errorf("invalid bundle encoding format: %d", format) } - chunkBytes, err := EncodeChunks(bundleRaw) - if err != nil { - return nil, err - } - size += int64(len(chunkBytes)) - - keys = append(keys, key) - values = append(values, chunkBytes) } encodingDuration += time.Since(start) } @@ -321,24 +347,24 @@ func (s *Store) GetBlobHeader(ctx context.Context, batchHeaderHash [32]byte, blo // GetChunks returns the list of byte arrays stored for given blobKey along with a boolean // indicating if the read was unsuccessful or the chunks were serialized correctly -func (s *Store) GetChunks(ctx context.Context, batchHeaderHash [32]byte, blobIndex int, quorumID core.QuorumID) ([][]byte, bool) { +func (s *Store) GetChunks(ctx context.Context, batchHeaderHash [32]byte, blobIndex int, quorumID core.QuorumID) ([][]byte, node.ChunkEncoding, bool) { log := s.logger blobKey, err := EncodeBlobKey(batchHeaderHash, blobIndex, quorumID) if err != nil { - return nil, false + return nil, node.ChunkEncoding_UNKNOWN, false } data, err := s.db.Get(blobKey) if err != nil { - return nil, false + return nil, node.ChunkEncoding_UNKNOWN, false } log.Debug("Retrieved chunk", "blobKey", hexutil.Encode(blobKey), "length", len(data)) - chunks, err := DecodeChunks(data) + chunks, format, err := DecodeChunks(data) if err != nil { - return nil, false + return nil, format, false } - return chunks, true + return chunks, format, true } // HasKey returns if a given key has been stored. @@ -374,11 +400,42 @@ func EncodeChunks(chunks [][]byte) ([]byte, error) { return result, nil } -// Converts a flattened array of chunks into an array of its constituent chunks, -// throwing an error in case the chunks were not serialized correctly -// +func DecodeGnarkChunks(data []byte) ([][]byte, error) { + format, chunkLen, err := parseHeader(data) + if err != nil { + return nil, err + } + if format != core.GnarkBundleEncodingFormat { + return nil, errors.New("invalid bundle data encoding format") + } + if chunkLen == 0 { + return nil, errors.New("chunk length must be greater than zero") + } + chunkSize := bn254.SizeOfG1AffineCompressed + encoding.BYTES_PER_SYMBOL*int(chunkLen) + chunks := make([][]byte, 0) + buf := data[8:] + for len(buf) > 0 { + if len(buf) < chunkSize { + return nil, errors.New("invalid data to decode") + } + chunks = append(chunks, buf[:chunkSize]) + buf = buf[chunkSize:] + } + return chunks, nil +} + // DecodeChunks((len(chunks[0]), chunks[0], len(chunks[1]), chunks[1], ...)) = chunks -func DecodeChunks(data []byte) ([][]byte, error) { +func DecodeGobChunks(data []byte) ([][]byte, error) { + format, chunkLen, err := parseHeader(data) + if err != nil { + return nil, err + } + if format != core.GobBundleEncodingFormat { + return nil, errors.New("invalid bundle data encoding format") + } + if chunkLen == 0 { + return nil, errors.New("chunk length must be greater than zero") + } chunks := make([][]byte, 0) buf := data for len(buf) > 0 { @@ -391,13 +448,48 @@ func DecodeChunks(data []byte) ([][]byte, error) { if len(buf) < int(chunkSize) { return nil, errors.New("invalid data to decode") } - chunk := buf[:chunkSize] + chunks = append(chunks, buf[:chunkSize]) buf = buf[chunkSize:] + } + return chunks, nil +} - chunks = append(chunks, chunk) +// parseHeader parses the header and returns the encoding format and the chunk length. +func parseHeader(data []byte) (core.BundleEncodingFormat, uint64, error) { + if len(data) < 8 { + return 0, 0, errors.New("no header found, the data size is less 8 bytes") } + meta := binary.LittleEndian.Uint64(data) + format := binary.LittleEndian.Uint64(data) >> (core.NumBundleHeaderBits - core.NumBundleEncodingFormatBits) + chunkLen := (meta << core.NumBundleEncodingFormatBits) >> core.NumBundleEncodingFormatBits + return uint8(format), chunkLen, nil +} - return chunks, nil +// DecodeChunks converts a flattened array of chunks into an array of its constituent chunks, +// throwing an error in case the chunks were not serialized correctly. +func DecodeChunks(data []byte) ([][]byte, node.ChunkEncoding, error) { + // Empty chunk is valid, but there is nothing to decode. + if len(data) == 0 { + return [][]byte{}, node.ChunkEncoding_UNKNOWN, nil + } + format, _, err := parseHeader(data) + if err != nil { + return nil, node.ChunkEncoding_UNKNOWN, err + } + + // Note: the encoding format IDs may not be the same as the field ID in protobuf. + // For example, GobBundleEncodingFormat is 1 but node.ChunkEncoding_GOB has proto + // field ID 2. + switch format { + case 0: + chunks, err := DecodeGobChunks(data) + return chunks, node.ChunkEncoding_GOB, err + case 1: + chunks, err := DecodeGnarkChunks(data) + return chunks, node.ChunkEncoding_GNARK, err + default: + return nil, node.ChunkEncoding_UNKNOWN, errors.New("invalid data encoding format") + } } func copyBytes(src []byte) []byte { diff --git a/node/store_test.go b/node/store_test.go index e0293f246..7c6faf45c 100644 --- a/node/store_test.go +++ b/node/store_test.go @@ -25,8 +25,17 @@ import ( "google.golang.org/protobuf/proto" ) -// Creates a batch and returns its header and blobs. +const ( + staleMeasure = uint32(1) + storeDuration = uint32(1) +) + func CreateBatch(t *testing.T) (*core.BatchHeader, []*core.BlobMessage, []*pb.Blob) { + return CreateBatchWith(t, false) +} + +// Creates a batch and returns its header and blobs. +func CreateBatchWith(t *testing.T, encodeBundle bool) (*core.BatchHeader, []*core.BlobMessage, []*pb.Blob) { var commitX, commitY, lengthX, lengthY fp.Element _, err := commitX.SetString("21661178944771197726808973281966770251114553549453983978976194544185382599016") assert.NoError(t, err) @@ -77,6 +86,11 @@ func CreateBatch(t *testing.T) (*core.BatchHeader, []*core.BlobMessage, []*pb.Bl } chunk1bytes, err := chunk1.Serialize() assert.Nil(t, err) + bundle1 := core.Bundle{ + chunk1, + } + bundle1bytes, err := bundle1.Serialize() + assert.Nil(t, err) blobMessage := []*core.BlobMessage{ { @@ -166,12 +180,22 @@ func CreateBatch(t *testing.T) (*core.BatchHeader, []*core.BlobMessage, []*pb.Bl Length: uint32(50), QuorumHeaders: []*pb.BlobQuorumInfo{quorumHeaderProto}, } - bundles := []*pb.Bundle{ - { - Chunks: [][]byte{ - chunk1bytes, + var bundles []*pb.Bundle + if encodeBundle { + bundles = []*pb.Bundle{ + { + Bundle: bundle1bytes, }, - }, + } + } else { + bundles = []*pb.Bundle{ + { + Chunks: [][]byte{ + chunk1bytes, + }, + }, + } + } blobs := []*pb.Blob{ { @@ -186,7 +210,26 @@ func CreateBatch(t *testing.T) (*core.BatchHeader, []*core.BlobMessage, []*pb.Bl return &batchHeader, blobMessage, blobs } +func createStore(t *testing.T) *node.Store { + noopMetrics := metrics.NewNoopMetrics() + reg := prometheus.NewRegistry() + logger := logging.NewNoopLogger() + operatorId := [32]byte(hexutil.MustDecode("0x3fbfefcdc76462d2cdb7d0cea75f27223829481b8b4aa6881c94cb2126a316ad")) + tx := &coremock.MockTransactor{} + dat, _ := mock.MakeChainDataMock(map[uint8]int{ + 0: 6, + 1: 3, + }) + s, _ := node.NewLevelDBStore(t.TempDir(), logger, node.NewMetrics(noopMetrics, reg, logger, ":9090", operatorId, -1, tx, dat), staleMeasure, storeDuration) + return s +} + func TestEncodeDecodeChunks(t *testing.T) { + decoded, format, err := node.DecodeChunks([]byte{}) + assert.Nil(t, err) + assert.Equal(t, pb.ChunkEncoding_UNKNOWN, format) + assert.Equal(t, 0, len(decoded)) + numSamples := 32 numChunks := 10 chunkSize := 2 * 1024 @@ -199,27 +242,26 @@ func TestEncodeDecodeChunks(t *testing.T) { } encoded, err := node.EncodeChunks(chunks) assert.Nil(t, err) - decoded, err := node.DecodeChunks(encoded) + decoded, format, err := node.DecodeChunks(encoded) assert.Nil(t, err) + assert.Equal(t, pb.ChunkEncoding_GOB, format) for i := 0; i < numChunks; i++ { assert.True(t, bytes.Equal(decoded[i], chunks[i])) } } } +func TestStoringInvalidBlob(t *testing.T) { + s := createStore(t) + ctx := context.Background() + batchHeader, blobs, blobsProto := CreateBatchWith(t, true) + blobsProto[0].Bundles[0].Chunks = [][]byte{[]byte{1}} + _, err := s.StoreBatch(ctx, batchHeader, blobs, blobsProto) + assert.EqualError(t, err, "chunks of a bundle are encoded together already") +} + func TestStoringBlob(t *testing.T) { - staleMeasure := uint32(1) - storeDuration := uint32(1) - noopMetrics := metrics.NewNoopMetrics() - reg := prometheus.NewRegistry() - logger := logging.NewNoopLogger() - operatorId := [32]byte(hexutil.MustDecode("0x3fbfefcdc76462d2cdb7d0cea75f27223829481b8b4aa6881c94cb2126a316ad")) - tx := &coremock.MockTransactor{} - dat, _ := mock.MakeChainDataMock(map[uint8]int{ - 0: 6, - 1: 3, - }) - s, _ := node.NewLevelDBStore(t.TempDir(), logger, node.NewMetrics(noopMetrics, reg, logger, ":9090", operatorId, -1, tx, dat), staleMeasure, storeDuration) + s := createStore(t) ctx := context.Background() // Empty store @@ -287,6 +329,62 @@ func TestStoringBlob(t *testing.T) { assert.False(t, s.HasKey(ctx, blobKey2)) } +func decodeChunks(t *testing.T, s *node.Store, batchHeaderHash [32]byte, blobIdx int, chunkEncoding pb.ChunkEncoding) []*encoding.Frame { + ctx := context.Background() + chunks, format, ok := s.GetChunks(ctx, batchHeaderHash, blobIdx, 0) + assert.True(t, ok) + assert.Equal(t, 1, len(chunks)) + assert.Equal(t, chunkEncoding, format) + var f *encoding.Frame + var err error + switch chunkEncoding { + case pb.ChunkEncoding_GOB: + f, err = new(encoding.Frame).Deserialize(chunks[0]) + assert.Nil(t, err) + case pb.ChunkEncoding_GNARK: + f, err = new(encoding.Frame).DeserializeGnark(chunks[0]) + assert.Nil(t, err) + } + return []*encoding.Frame{f} +} + +func checkBundleEquivalence(t *testing.T, bundle1, bundle2 []*encoding.Frame) { + assert.Equal(t, len(bundle1), len(bundle2)) + for i := 0; i < len(bundle1); i++ { + assert.True(t, bundle1[i].Proof.Equal(&bundle2[i].Proof)) + assert.Equal(t, len(bundle1[i].Coeffs), len(bundle2[i].Coeffs)) + for j := 0; j < len(bundle1[i].Coeffs); j++ { + assert.True(t, bundle1[i].Coeffs[j].Equal(&bundle2[i].Coeffs[j])) + } + } +} + +func TestBundleEncodingEquivalence(t *testing.T) { + ctx := context.Background() + // Gnark chunks + s1 := createStore(t) + batchHeader1, blobs1, blobsProto1 := CreateBatchWith(t, true) + _, err := s1.StoreBatch(ctx, batchHeader1, blobs1, blobsProto1) + assert.Nil(t, err) + // Gob chunks + s2 := createStore(t) + batchHeader2, blobs2, blobsProto2 := CreateBatchWith(t, false) + _, err = s2.StoreBatch(ctx, batchHeader2, blobs2, blobsProto2) + assert.Nil(t, err) + + // Check parity + batchHeaderHash, err := batchHeader1.GetBatchHeaderHash() + assert.Nil(t, err) + // The first blob + bundle1 := decodeChunks(t, s1, batchHeaderHash, 0, pb.ChunkEncoding_GNARK) + bundle2 := decodeChunks(t, s2, batchHeaderHash, 0, pb.ChunkEncoding_GOB) + checkBundleEquivalence(t, bundle1, bundle2) + // The second blob + bundle1 = decodeChunks(t, s1, batchHeaderHash, 1, pb.ChunkEncoding_GNARK) + bundle2 = decodeChunks(t, s2, batchHeaderHash, 1, pb.ChunkEncoding_GOB) + checkBundleEquivalence(t, bundle1, bundle2) +} + func BenchmarkEncodeChunks(b *testing.B) { numSamples := 32 numChunks := 10 @@ -326,6 +424,6 @@ func BenchmarkDecocodeChunks(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - _, _ = node.DecodeChunks(sampleChunks[i%numSamples]) + _, _, _ = node.DecodeChunks(sampleChunks[i%numSamples]) } } diff --git a/node/utils.go b/node/utils.go index e493887d6..dcc21a9e2 100644 --- a/node/utils.go +++ b/node/utils.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" + pb "github.com/Layr-Labs/eigenda/api/grpc/node" "github.com/Layr-Labs/eigenda/common/pubip" "github.com/Layr-Labs/eigenda/core" ) @@ -92,3 +93,18 @@ func SocketAddress(ctx context.Context, provider pubip.Provider, dispersalPort s socket := core.MakeOperatorSocket(ip, dispersalPort, retrievalPort) return socket.String(), nil } + +func GetBundleEncodingFormat(blob *pb.Blob) core.BundleEncodingFormat { + // We expect all the bundles of the blob are either using combined bundle + // (with all chunks in a single byte array) or separate chunks, no mixed + // use. + for _, bundle := range blob.GetBundles() { + // If the blob is using combined bundle encoding, there must be at least + // one non-empty bundle (i.e. the node is in at least one quorum otherwise + // it shouldn't have received this blob). + if len(bundle.GetBundle()) > 0 { + return core.GnarkBundleEncodingFormat + } + } + return core.GobBundleEncodingFormat +}