diff --git a/proto/pb/sync/sync.pb.go b/proto/pb/sync/sync.pb.go index ca04ca902bcc..1ae2ee8ed331 100644 --- a/proto/pb/sync/sync.pb.go +++ b/proto/pb/sync/sync.pb.go @@ -316,7 +316,7 @@ type SyncGetChangeProofRequest struct { StartRootHash []byte `protobuf:"bytes,1,opt,name=start_root_hash,json=startRootHash,proto3" json:"start_root_hash,omitempty"` EndRootHash []byte `protobuf:"bytes,2,opt,name=end_root_hash,json=endRootHash,proto3" json:"end_root_hash,omitempty"` - StartKey []byte `protobuf:"bytes,3,opt,name=start_key,json=startKey,proto3" json:"start_key,omitempty"` + StartKey *MaybeBytes `protobuf:"bytes,3,opt,name=start_key,json=startKey,proto3" json:"start_key,omitempty"` EndKey *MaybeBytes `protobuf:"bytes,4,opt,name=end_key,json=endKey,proto3" json:"end_key,omitempty"` KeyLimit uint32 `protobuf:"varint,5,opt,name=key_limit,json=keyLimit,proto3" json:"key_limit,omitempty"` BytesLimit uint32 `protobuf:"varint,6,opt,name=bytes_limit,json=bytesLimit,proto3" json:"bytes_limit,omitempty"` @@ -368,7 +368,7 @@ func (x *SyncGetChangeProofRequest) GetEndRootHash() []byte { return nil } -func (x *SyncGetChangeProofRequest) GetStartKey() []byte { +func (x *SyncGetChangeProofRequest) GetStartKey() *MaybeBytes { if x != nil { return x.StartKey } @@ -484,7 +484,7 @@ type GetChangeProofRequest struct { StartRootHash []byte `protobuf:"bytes,1,opt,name=start_root_hash,json=startRootHash,proto3" json:"start_root_hash,omitempty"` EndRootHash []byte `protobuf:"bytes,2,opt,name=end_root_hash,json=endRootHash,proto3" json:"end_root_hash,omitempty"` - StartKey []byte `protobuf:"bytes,3,opt,name=start_key,json=startKey,proto3" json:"start_key,omitempty"` + StartKey *MaybeBytes `protobuf:"bytes,3,opt,name=start_key,json=startKey,proto3" json:"start_key,omitempty"` EndKey *MaybeBytes `protobuf:"bytes,4,opt,name=end_key,json=endKey,proto3" json:"end_key,omitempty"` KeyLimit uint32 `protobuf:"varint,5,opt,name=key_limit,json=keyLimit,proto3" json:"key_limit,omitempty"` } @@ -535,7 +535,7 @@ func (x *GetChangeProofRequest) GetEndRootHash() []byte { return nil } -func (x *GetChangeProofRequest) GetStartKey() []byte { +func (x *GetChangeProofRequest) GetStartKey() *MaybeBytes { if x != nil { return x.StartKey } @@ -644,8 +644,8 @@ type VerifyChangeProofRequest struct { unknownFields protoimpl.UnknownFields Proof *ChangeProof `protobuf:"bytes,1,opt,name=proof,proto3" json:"proof,omitempty"` - StartKey []byte `protobuf:"bytes,2,opt,name=start_key,json=startKey,proto3" json:"start_key,omitempty"` - EndKey []byte `protobuf:"bytes,3,opt,name=end_key,json=endKey,proto3" json:"end_key,omitempty"` + StartKey *MaybeBytes `protobuf:"bytes,2,opt,name=start_key,json=startKey,proto3" json:"start_key,omitempty"` + EndKey *MaybeBytes `protobuf:"bytes,3,opt,name=end_key,json=endKey,proto3" json:"end_key,omitempty"` ExpectedRootHash []byte `protobuf:"bytes,4,opt,name=expected_root_hash,json=expectedRootHash,proto3" json:"expected_root_hash,omitempty"` } @@ -688,14 +688,14 @@ func (x *VerifyChangeProofRequest) GetProof() *ChangeProof { return nil } -func (x *VerifyChangeProofRequest) GetStartKey() []byte { +func (x *VerifyChangeProofRequest) GetStartKey() *MaybeBytes { if x != nil { return x.StartKey } return nil } -func (x *VerifyChangeProofRequest) GetEndKey() []byte { +func (x *VerifyChangeProofRequest) GetEndKey() *MaybeBytes { if x != nil { return x.EndKey } @@ -812,7 +812,7 @@ type SyncGetRangeProofRequest struct { unknownFields protoimpl.UnknownFields RootHash []byte `protobuf:"bytes,1,opt,name=root_hash,json=rootHash,proto3" json:"root_hash,omitempty"` - StartKey []byte `protobuf:"bytes,2,opt,name=start_key,json=startKey,proto3" json:"start_key,omitempty"` + StartKey *MaybeBytes `protobuf:"bytes,2,opt,name=start_key,json=startKey,proto3" json:"start_key,omitempty"` EndKey *MaybeBytes `protobuf:"bytes,3,opt,name=end_key,json=endKey,proto3" json:"end_key,omitempty"` KeyLimit uint32 `protobuf:"varint,4,opt,name=key_limit,json=keyLimit,proto3" json:"key_limit,omitempty"` BytesLimit uint32 `protobuf:"varint,5,opt,name=bytes_limit,json=bytesLimit,proto3" json:"bytes_limit,omitempty"` @@ -857,7 +857,7 @@ func (x *SyncGetRangeProofRequest) GetRootHash() []byte { return nil } -func (x *SyncGetRangeProofRequest) GetStartKey() []byte { +func (x *SyncGetRangeProofRequest) GetStartKey() *MaybeBytes { if x != nil { return x.StartKey } @@ -891,7 +891,7 @@ type GetRangeProofRequest struct { unknownFields protoimpl.UnknownFields RootHash []byte `protobuf:"bytes,1,opt,name=root_hash,json=rootHash,proto3" json:"root_hash,omitempty"` - StartKey []byte `protobuf:"bytes,2,opt,name=start_key,json=startKey,proto3" json:"start_key,omitempty"` + StartKey *MaybeBytes `protobuf:"bytes,2,opt,name=start_key,json=startKey,proto3" json:"start_key,omitempty"` EndKey *MaybeBytes `protobuf:"bytes,3,opt,name=end_key,json=endKey,proto3" json:"end_key,omitempty"` KeyLimit uint32 `protobuf:"varint,4,opt,name=key_limit,json=keyLimit,proto3" json:"key_limit,omitempty"` } @@ -935,7 +935,7 @@ func (x *GetRangeProofRequest) GetRootHash() []byte { return nil } -func (x *GetRangeProofRequest) GetStartKey() []byte { +func (x *GetRangeProofRequest) GetStartKey() *MaybeBytes { if x != nil { return x.StartKey } @@ -1008,7 +1008,7 @@ type CommitRangeProofRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - StartKey []byte `protobuf:"bytes,1,opt,name=start_key,json=startKey,proto3" json:"start_key,omitempty"` + StartKey *MaybeBytes `protobuf:"bytes,1,opt,name=start_key,json=startKey,proto3" json:"start_key,omitempty"` RangeProof *RangeProof `protobuf:"bytes,2,opt,name=range_proof,json=rangeProof,proto3" json:"range_proof,omitempty"` } @@ -1044,7 +1044,7 @@ func (*CommitRangeProofRequest) Descriptor() ([]byte, []int) { return file_sync_sync_proto_rawDescGZIP(), []int{15} } -func (x *CommitRangeProofRequest) GetStartKey() []byte { +func (x *CommitRangeProofRequest) GetStartKey() *MaybeBytes { if x != nil { return x.StartKey } @@ -1502,190 +1502,198 @@ var file_sync_sync_proto_rawDesc = []byte{ 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x25, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x50, 0x72, - 0x6f, 0x6f, 0x66, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xed, + 0x6f, 0x6f, 0x66, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xff, 0x01, 0x0a, 0x19, 0x53, 0x79, 0x6e, 0x63, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x6e, 0x64, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x65, 0x6e, 0x64, - 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x07, 0x65, 0x6e, 0x64, 0x5f, 0x6b, 0x65, 0x79, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, - 0x79, 0x62, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x06, 0x65, 0x6e, 0x64, 0x4b, 0x65, 0x79, - 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x79, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1f, 0x0a, - 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x95, - 0x01, 0x0a, 0x1a, 0x53, 0x79, 0x6e, 0x63, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, - 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x33, 0x0a, 0x0b, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x70, - 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, - 0x63, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x48, 0x00, 0x52, 0x0a, - 0x72, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xc8, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x6e, 0x64, 0x5f, - 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0b, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x07, 0x65, 0x6e, 0x64, - 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, - 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x06, 0x65, 0x6e, - 0x64, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x79, 0x5f, 0x6c, 0x69, 0x6d, 0x69, - 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x4c, 0x69, 0x6d, 0x69, - 0x74, 0x22, 0x88, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0c, - 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x6e, 0x6f, 0x74, - 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, - 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, - 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa7, 0x01, 0x0a, - 0x18, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, - 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x05, 0x70, 0x72, 0x6f, - 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x05, 0x70, 0x72, 0x6f, - 0x6f, 0x66, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x12, - 0x17, 0x0a, 0x07, 0x65, 0x6e, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x06, 0x65, 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x12, 0x65, 0x78, 0x70, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x52, 0x6f, - 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0x31, 0x0a, 0x19, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x43, 0x0a, 0x18, 0x43, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xbd, - 0x01, 0x0a, 0x18, 0x53, 0x79, 0x6e, 0x63, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, - 0x6f, 0x6f, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, - 0x72, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x74, 0x61, + 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2d, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, + 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x08, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x07, 0x65, 0x6e, 0x64, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, + 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x06, 0x65, 0x6e, 0x64, 0x4b, + 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x79, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, + 0x1f, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x22, 0x95, 0x01, 0x0a, 0x1a, 0x53, 0x79, 0x6e, 0x63, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x36, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x33, 0x0a, 0x0b, 0x72, 0x61, 0x6e, 0x67, 0x65, + 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, + 0x79, 0x6e, 0x63, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x48, 0x00, + 0x52, 0x0a, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x42, 0x0a, 0x0a, 0x08, + 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xda, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, + 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x6e, + 0x64, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0b, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2d, + 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, + 0x74, 0x65, 0x73, 0x52, 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x29, 0x0a, + 0x07, 0x65, 0x6e, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x52, 0x06, 0x65, 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x79, 0x5f, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6b, 0x65, 0x79, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x88, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x36, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, + 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x48, 0x00, 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x50, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0xcb, 0x01, 0x0a, 0x18, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, + 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, + 0x79, 0x6e, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, + 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x2d, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, + 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, + 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x07, 0x65, 0x6e, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x06, 0x65, 0x6e, 0x64, 0x4b, 0x65, 0x79, - 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x79, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1f, 0x0a, - 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x98, - 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x5f, - 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x74, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6b, 0x65, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, - 0x79, 0x12, 0x29, 0x0a, 0x07, 0x65, 0x6e, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, - 0x79, 0x74, 0x65, 0x73, 0x52, 0x06, 0x65, 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, - 0x6b, 0x65, 0x79, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x08, 0x6b, 0x65, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3f, 0x0a, 0x15, 0x47, 0x65, 0x74, - 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x26, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, - 0x6f, 0x6f, 0x66, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x69, 0x0a, 0x17, 0x43, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, - 0x65, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6f, - 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x52, - 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x0a, 0x72, 0x61, 0x6e, 0x67, 0x65, - 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x9f, 0x01, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x30, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x70, - 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x79, 0x6e, - 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x2c, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x5f, 0x70, - 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x79, 0x6e, - 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x65, 0x6e, 0x64, - 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x30, 0x0a, 0x0b, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x79, 0x6e, - 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0a, 0x6b, 0x65, 0x79, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x22, 0x85, 0x01, 0x0a, 0x0a, 0x52, 0x61, 0x6e, 0x67, - 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x25, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x50, 0x72, 0x6f, - 0x6f, 0x66, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x21, 0x0a, - 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x79, 0x6e, - 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x65, 0x6e, 0x64, - 0x12, 0x2d, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x52, 0x09, 0x6b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, - 0xe1, 0x01, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x26, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x79, 0x6e, - 0x63, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x0d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x6f, - 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, - 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x0b, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x12, 0x39, 0x0a, 0x08, 0x63, - 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x6f, 0x64, 0x65, 0x2e, 0x43, - 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x63, 0x68, - 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x1a, 0x3b, 0x0a, 0x0d, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, - 0x65, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x22, 0x45, 0x0a, 0x09, 0x4b, 0x65, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x26, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, - 0x74, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4b, 0x0a, 0x0e, 0x53, 0x65, - 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x12, 0x23, 0x0a, 0x0d, - 0x6e, 0x69, 0x62, 0x62, 0x6c, 0x65, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6e, 0x69, 0x62, 0x62, 0x6c, 0x65, 0x4c, 0x65, 0x6e, 0x67, 0x74, - 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x41, 0x0a, 0x0a, 0x4d, 0x61, 0x79, 0x62, 0x65, - 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, - 0x73, 0x5f, 0x6e, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x09, 0x69, 0x73, 0x4e, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x22, 0x32, 0x0a, 0x08, 0x4b, 0x65, - 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x8a, - 0x04, 0x0a, 0x02, 0x44, 0x42, 0x12, 0x44, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x72, 0x6b, - 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, - 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, - 0x6f, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x08, 0x47, - 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x15, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x47, - 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, - 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1b, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, - 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x47, 0x65, 0x74, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1e, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, - 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, - 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, - 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, - 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x11, 0x43, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1e, - 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x48, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, - 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1a, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x47, + 0x12, 0x2c, 0x0a, 0x12, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x6f, + 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x65, 0x78, + 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0x31, + 0x0a, 0x19, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x22, 0x43, 0x0a, 0x18, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, + 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, + 0x79, 0x6e, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, + 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xcf, 0x01, 0x0a, 0x18, 0x53, 0x79, 0x6e, 0x63, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x61, - 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x49, 0x0a, 0x10, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1d, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x2f, 0x5a, 0x2d, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x61, 0x2d, 0x6c, 0x61, - 0x62, 0x73, 0x2f, 0x61, 0x76, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x67, 0x6f, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, + 0x12, 0x2d, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, + 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x12, + 0x29, 0x0a, 0x07, 0x65, 0x6e, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, 0x74, + 0x65, 0x73, 0x52, 0x06, 0x65, 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, + 0x79, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6b, + 0x65, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x62, 0x79, + 0x74, 0x65, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0xaa, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, + 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2d, + 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, + 0x74, 0x65, 0x73, 0x52, 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x29, 0x0a, + 0x07, 0x65, 0x6e, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x52, 0x06, 0x65, 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x79, 0x5f, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6b, 0x65, 0x79, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3f, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x67, + 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, + 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, + 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x7b, 0x0a, 0x17, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x2d, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, + 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, + 0x12, 0x31, 0x0a, 0x0b, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x52, 0x61, 0x6e, + 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x0a, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x22, 0x9f, 0x01, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x12, 0x30, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x70, 0x72, 0x6f, + 0x6f, 0x66, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x2c, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x5f, 0x70, 0x72, 0x6f, + 0x6f, 0x66, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x12, 0x30, 0x0a, 0x0b, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, + 0x4b, 0x65, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0a, 0x6b, 0x65, 0x79, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x73, 0x22, 0x85, 0x01, 0x0a, 0x0a, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, + 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x25, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x21, 0x0a, 0x03, 0x65, + 0x6e, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x2d, + 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x09, 0x6b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0xe1, 0x01, + 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x26, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, + 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x0d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x6f, 0x72, 0x5f, + 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x79, 0x6e, + 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x0b, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x4f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x12, 0x39, 0x0a, 0x08, 0x63, 0x68, 0x69, + 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x79, + 0x6e, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x6f, 0x64, 0x65, 0x2e, 0x43, 0x68, 0x69, + 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, + 0x64, 0x72, 0x65, 0x6e, 0x1a, 0x3b, 0x0a, 0x0d, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x45, 0x0a, 0x09, 0x4b, 0x65, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x26, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x10, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, 0x74, 0x65, + 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4b, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x6e, 0x69, + 0x62, 0x62, 0x6c, 0x65, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0c, 0x6e, 0x69, 0x62, 0x62, 0x6c, 0x65, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x41, 0x0a, 0x0a, 0x4d, 0x61, 0x79, 0x62, 0x65, 0x42, 0x79, + 0x74, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, + 0x6e, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, + 0x73, 0x4e, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x22, 0x32, 0x0a, 0x08, 0x4b, 0x65, 0x79, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x8a, 0x04, 0x0a, + 0x02, 0x44, 0x42, 0x12, 0x44, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, + 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x73, + 0x79, 0x6e, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x08, 0x47, 0x65, 0x74, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x15, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x47, 0x65, 0x74, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x73, + 0x79, 0x6e, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1b, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x47, 0x65, + 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x54, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1e, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x56, 0x65, + 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x56, 0x65, + 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1e, 0x2e, 0x73, + 0x79, 0x6e, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x12, 0x48, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1a, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x47, 0x65, 0x74, + 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x67, + 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, + 0x0a, 0x10, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, + 0x6f, 0x66, 0x12, 0x1d, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x61, 0x2d, 0x6c, 0x61, 0x62, 0x73, + 0x2f, 0x61, 0x76, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -1734,46 +1742,53 @@ var file_sync_sync_proto_depIdxs = []int32{ 4, // 2: sync.GetProofResponse.proof:type_name -> sync.Proof 21, // 3: sync.Proof.value:type_name -> sync.MaybeBytes 18, // 4: sync.Proof.proof:type_name -> sync.ProofNode - 21, // 5: sync.SyncGetChangeProofRequest.end_key:type_name -> sync.MaybeBytes - 16, // 6: sync.SyncGetChangeProofResponse.change_proof:type_name -> sync.ChangeProof - 17, // 7: sync.SyncGetChangeProofResponse.range_proof:type_name -> sync.RangeProof - 21, // 8: sync.GetChangeProofRequest.end_key:type_name -> sync.MaybeBytes - 16, // 9: sync.GetChangeProofResponse.change_proof:type_name -> sync.ChangeProof - 16, // 10: sync.VerifyChangeProofRequest.proof:type_name -> sync.ChangeProof - 16, // 11: sync.CommitChangeProofRequest.proof:type_name -> sync.ChangeProof - 21, // 12: sync.SyncGetRangeProofRequest.end_key:type_name -> sync.MaybeBytes - 21, // 13: sync.GetRangeProofRequest.end_key:type_name -> sync.MaybeBytes - 17, // 14: sync.GetRangeProofResponse.proof:type_name -> sync.RangeProof - 17, // 15: sync.CommitRangeProofRequest.range_proof:type_name -> sync.RangeProof - 18, // 16: sync.ChangeProof.start_proof:type_name -> sync.ProofNode - 18, // 17: sync.ChangeProof.end_proof:type_name -> sync.ProofNode - 19, // 18: sync.ChangeProof.key_changes:type_name -> sync.KeyChange - 18, // 19: sync.RangeProof.start:type_name -> sync.ProofNode - 18, // 20: sync.RangeProof.end:type_name -> sync.ProofNode - 22, // 21: sync.RangeProof.key_values:type_name -> sync.KeyValue - 20, // 22: sync.ProofNode.key:type_name -> sync.SerializedPath - 21, // 23: sync.ProofNode.value_or_hash:type_name -> sync.MaybeBytes - 23, // 24: sync.ProofNode.children:type_name -> sync.ProofNode.ChildrenEntry - 21, // 25: sync.KeyChange.value:type_name -> sync.MaybeBytes - 24, // 26: sync.DB.GetMerkleRoot:input_type -> google.protobuf.Empty - 2, // 27: sync.DB.GetProof:input_type -> sync.GetProofRequest - 7, // 28: sync.DB.GetChangeProof:input_type -> sync.GetChangeProofRequest - 9, // 29: sync.DB.VerifyChangeProof:input_type -> sync.VerifyChangeProofRequest - 11, // 30: sync.DB.CommitChangeProof:input_type -> sync.CommitChangeProofRequest - 13, // 31: sync.DB.GetRangeProof:input_type -> sync.GetRangeProofRequest - 15, // 32: sync.DB.CommitRangeProof:input_type -> sync.CommitRangeProofRequest - 1, // 33: sync.DB.GetMerkleRoot:output_type -> sync.GetMerkleRootResponse - 3, // 34: sync.DB.GetProof:output_type -> sync.GetProofResponse - 8, // 35: sync.DB.GetChangeProof:output_type -> sync.GetChangeProofResponse - 10, // 36: sync.DB.VerifyChangeProof:output_type -> sync.VerifyChangeProofResponse - 24, // 37: sync.DB.CommitChangeProof:output_type -> google.protobuf.Empty - 14, // 38: sync.DB.GetRangeProof:output_type -> sync.GetRangeProofResponse - 24, // 39: sync.DB.CommitRangeProof:output_type -> google.protobuf.Empty - 33, // [33:40] is the sub-list for method output_type - 26, // [26:33] is the sub-list for method input_type - 26, // [26:26] is the sub-list for extension type_name - 26, // [26:26] is the sub-list for extension extendee - 0, // [0:26] is the sub-list for field type_name + 21, // 5: sync.SyncGetChangeProofRequest.start_key:type_name -> sync.MaybeBytes + 21, // 6: sync.SyncGetChangeProofRequest.end_key:type_name -> sync.MaybeBytes + 16, // 7: sync.SyncGetChangeProofResponse.change_proof:type_name -> sync.ChangeProof + 17, // 8: sync.SyncGetChangeProofResponse.range_proof:type_name -> sync.RangeProof + 21, // 9: sync.GetChangeProofRequest.start_key:type_name -> sync.MaybeBytes + 21, // 10: sync.GetChangeProofRequest.end_key:type_name -> sync.MaybeBytes + 16, // 11: sync.GetChangeProofResponse.change_proof:type_name -> sync.ChangeProof + 16, // 12: sync.VerifyChangeProofRequest.proof:type_name -> sync.ChangeProof + 21, // 13: sync.VerifyChangeProofRequest.start_key:type_name -> sync.MaybeBytes + 21, // 14: sync.VerifyChangeProofRequest.end_key:type_name -> sync.MaybeBytes + 16, // 15: sync.CommitChangeProofRequest.proof:type_name -> sync.ChangeProof + 21, // 16: sync.SyncGetRangeProofRequest.start_key:type_name -> sync.MaybeBytes + 21, // 17: sync.SyncGetRangeProofRequest.end_key:type_name -> sync.MaybeBytes + 21, // 18: sync.GetRangeProofRequest.start_key:type_name -> sync.MaybeBytes + 21, // 19: sync.GetRangeProofRequest.end_key:type_name -> sync.MaybeBytes + 17, // 20: sync.GetRangeProofResponse.proof:type_name -> sync.RangeProof + 21, // 21: sync.CommitRangeProofRequest.start_key:type_name -> sync.MaybeBytes + 17, // 22: sync.CommitRangeProofRequest.range_proof:type_name -> sync.RangeProof + 18, // 23: sync.ChangeProof.start_proof:type_name -> sync.ProofNode + 18, // 24: sync.ChangeProof.end_proof:type_name -> sync.ProofNode + 19, // 25: sync.ChangeProof.key_changes:type_name -> sync.KeyChange + 18, // 26: sync.RangeProof.start:type_name -> sync.ProofNode + 18, // 27: sync.RangeProof.end:type_name -> sync.ProofNode + 22, // 28: sync.RangeProof.key_values:type_name -> sync.KeyValue + 20, // 29: sync.ProofNode.key:type_name -> sync.SerializedPath + 21, // 30: sync.ProofNode.value_or_hash:type_name -> sync.MaybeBytes + 23, // 31: sync.ProofNode.children:type_name -> sync.ProofNode.ChildrenEntry + 21, // 32: sync.KeyChange.value:type_name -> sync.MaybeBytes + 24, // 33: sync.DB.GetMerkleRoot:input_type -> google.protobuf.Empty + 2, // 34: sync.DB.GetProof:input_type -> sync.GetProofRequest + 7, // 35: sync.DB.GetChangeProof:input_type -> sync.GetChangeProofRequest + 9, // 36: sync.DB.VerifyChangeProof:input_type -> sync.VerifyChangeProofRequest + 11, // 37: sync.DB.CommitChangeProof:input_type -> sync.CommitChangeProofRequest + 13, // 38: sync.DB.GetRangeProof:input_type -> sync.GetRangeProofRequest + 15, // 39: sync.DB.CommitRangeProof:input_type -> sync.CommitRangeProofRequest + 1, // 40: sync.DB.GetMerkleRoot:output_type -> sync.GetMerkleRootResponse + 3, // 41: sync.DB.GetProof:output_type -> sync.GetProofResponse + 8, // 42: sync.DB.GetChangeProof:output_type -> sync.GetChangeProofResponse + 10, // 43: sync.DB.VerifyChangeProof:output_type -> sync.VerifyChangeProofResponse + 24, // 44: sync.DB.CommitChangeProof:output_type -> google.protobuf.Empty + 14, // 45: sync.DB.GetRangeProof:output_type -> sync.GetRangeProofResponse + 24, // 46: sync.DB.CommitRangeProof:output_type -> google.protobuf.Empty + 40, // [40:47] is the sub-list for method output_type + 33, // [33:40] is the sub-list for method input_type + 33, // [33:33] is the sub-list for extension type_name + 33, // [33:33] is the sub-list for extension extendee + 0, // [0:33] is the sub-list for field type_name } func init() { file_sync_sync_proto_init() } diff --git a/proto/sync/sync.proto b/proto/sync/sync.proto index 048e31cfb340..e1c1ccd22ec4 100644 --- a/proto/sync/sync.proto +++ b/proto/sync/sync.proto @@ -54,7 +54,7 @@ message Proof { message SyncGetChangeProofRequest { bytes start_root_hash = 1; bytes end_root_hash = 2; - bytes start_key = 3; + MaybeBytes start_key = 3; MaybeBytes end_key = 4; uint32 key_limit = 5; uint32 bytes_limit = 6; @@ -70,7 +70,7 @@ message SyncGetChangeProofResponse { message GetChangeProofRequest { bytes start_root_hash = 1; bytes end_root_hash = 2; - bytes start_key = 3; + MaybeBytes start_key = 3; MaybeBytes end_key = 4; uint32 key_limit = 5; } @@ -85,8 +85,8 @@ message GetChangeProofResponse { message VerifyChangeProofRequest { ChangeProof proof = 1; - bytes start_key = 2; - bytes end_key = 3; + MaybeBytes start_key = 2; + MaybeBytes end_key = 3; bytes expected_root_hash = 4; } @@ -103,7 +103,7 @@ message CommitChangeProofRequest { // the response. GetRangeProof in the DB service doesn't. message SyncGetRangeProofRequest { bytes root_hash = 1; - bytes start_key = 2; + MaybeBytes start_key = 2; MaybeBytes end_key = 3; uint32 key_limit = 4; uint32 bytes_limit = 5; @@ -111,7 +111,7 @@ message SyncGetRangeProofRequest { message GetRangeProofRequest { bytes root_hash = 1; - bytes start_key = 2; + MaybeBytes start_key = 2; MaybeBytes end_key = 3; uint32 key_limit = 4; } @@ -121,7 +121,7 @@ message GetRangeProofResponse { } message CommitRangeProofRequest { - bytes start_key = 1; + MaybeBytes start_key = 1; RangeProof range_proof = 2; } diff --git a/utils/maybe/maybe.go b/utils/maybe/maybe.go index f13245f43827..b4dfc7f9a452 100644 --- a/utils/maybe/maybe.go +++ b/utils/maybe/maybe.go @@ -3,18 +3,23 @@ package maybe +import "fmt" + // Maybe T = Some T | Nothing. // A data wrapper that allows values to be something [Some T] or nothing [Nothing]. +// Invariant: If [hasValue] is false, then [value] is the zero value of type T. // Maybe is used to wrap types: // * That can't be represented by nil. // * That use nil as a valid value instead of an indicator of a missing value. // For more info see https://en.wikipedia.org/wiki/Option_type type Maybe[T any] struct { hasValue bool - value T + // If [hasValue] is false, [value] is the zero value of type T. + value T } // Some returns a new Maybe[T] with the value val. +// If m.IsNothing(), returns the zero value of type T. func Some[T any](val T) Maybe[T] { return Maybe[T]{ value: val, @@ -42,6 +47,13 @@ func (m Maybe[T]) Value() T { return m.value } +func (m Maybe[T]) String() string { + if !m.hasValue { + return fmt.Sprintf("Nothing[%T]", m.value) + } + return fmt.Sprintf("Some[%T]{%v}", m.value, m.value) +} + // Bind returns Nothing iff [m] is Nothing. // Otherwise applies [f] to the value of [m] and returns the result as a Some. func Bind[T, U any](m Maybe[T], f func(T) U) Maybe[U] { diff --git a/utils/maybe/maybe_test.go b/utils/maybe/maybe_test.go index b2772ff1683b..60b599000d0a 100644 --- a/utils/maybe/maybe_test.go +++ b/utils/maybe/maybe_test.go @@ -32,6 +32,23 @@ func TestMaybeClone(t *testing.T) { } } +func TestMaybeString(t *testing.T) { + require := require.New(t) + + // Case: Value is maybe + { + val := []int{1, 2, 3} + m := Some(val) + require.Equal("Some[[]int]{[1 2 3]}", m.String()) + } + + // Case: Value is nothing + { + m := Nothing[int]() + require.Equal("Nothing[int]", m.String()) + } +} + func TestMaybeEquality(t *testing.T) { require := require.New(t) require.True(Equal(Nothing[int](), Nothing[int](), func(i int, i2 int) bool { diff --git a/x/merkledb/db.go b/x/merkledb/db.go index dd3ee0515911..926f31051a49 100644 --- a/x/merkledb/db.go +++ b/x/merkledb/db.go @@ -63,7 +63,7 @@ type ChangeProofer interface { ctx context.Context, startRootID ids.ID, endRootID ids.ID, - start []byte, + start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], maxLength int, ) (*ChangeProof, error) @@ -72,7 +72,7 @@ type ChangeProofer interface { // - [start] <= [end]. // - [proof] is non-empty. // - All keys in [proof.KeyValues] and [proof.DeletedKeys] are in [start, end]. - // If [start] is empty, all keys are considered > [start]. + // If [start] is nothing, all keys are considered > [start]. // If [end] is nothing, all keys are considered < [end]. // - [proof.KeyValues] and [proof.DeletedKeys] are sorted in order of increasing key. // - [proof.StartProof] and [proof.EndProof] are well-formed. @@ -84,7 +84,7 @@ type ChangeProofer interface { VerifyChangeProof( ctx context.Context, proof *ChangeProof, - start []byte, + start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], expectedEndRootID ids.ID, ) error @@ -96,17 +96,19 @@ type ChangeProofer interface { type RangeProofer interface { // GetRangeProofAtRoot returns a proof for the key/value pairs in this trie within the range // [start, end] when the root of the trie was [rootID]. + // If [start] is Nothing, there's no lower bound on the range. + // If [end] is Nothing, there's no upper bound on the range. GetRangeProofAtRoot( ctx context.Context, rootID ids.ID, - start []byte, + start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], maxLength int, ) (*RangeProof, error) // CommitRangeProof commits the key/value pairs within the [proof] to the db. // [start] is the smallest key in the range this [proof] covers. - CommitRangeProof(ctx context.Context, start []byte, proof *RangeProof) error + CommitRangeProof(ctx context.Context, start maybe.Maybe[[]byte], proof *RangeProof) error } type MerkleDB interface { @@ -314,7 +316,7 @@ func (db *merkleDB) CommitChangeProof(ctx context.Context, proof *ChangeProof) e return view.commitToDB(ctx) } -func (db *merkleDB) CommitRangeProof(ctx context.Context, start []byte, proof *RangeProof) error { +func (db *merkleDB) CommitRangeProof(ctx context.Context, start maybe.Maybe[[]byte], proof *RangeProof) error { db.commitLock.Lock() defer db.commitLock.Unlock() @@ -336,7 +338,7 @@ func (db *merkleDB) CommitRangeProof(ctx context.Context, start []byte, proof *R if len(proof.KeyValues) > 0 { largestKey = proof.KeyValues[len(proof.KeyValues)-1].Key } - keysToDelete, err := db.getKeysNotInSet(start, largestKey, keys) + keysToDelete, err := db.getKeysNotInSet(start.Value(), largestKey, keys) if err != nil { return err } @@ -509,11 +511,9 @@ func (db *merkleDB) getProof(ctx context.Context, key []byte) (*Proof, error) { return view.getProof(ctx, key) } -// GetRangeProof returns a proof for the key/value pairs in this trie within the range -// [start, end]. func (db *merkleDB) GetRangeProof( ctx context.Context, - start []byte, + start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], maxLength int, ) (*RangeProof, error) { @@ -523,12 +523,10 @@ func (db *merkleDB) GetRangeProof( return db.getRangeProofAtRoot(ctx, db.getMerkleRoot(), start, end, maxLength) } -// GetRangeProofAtRoot returns a proof for the key/value pairs in this trie within the range -// [start, end] when the root of the trie was [rootID]. func (db *merkleDB) GetRangeProofAtRoot( ctx context.Context, rootID ids.ID, - start []byte, + start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], maxLength int, ) (*RangeProof, error) { @@ -542,7 +540,7 @@ func (db *merkleDB) GetRangeProofAtRoot( func (db *merkleDB) getRangeProofAtRoot( ctx context.Context, rootID ids.ID, - start []byte, + start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], maxLength int, ) (*RangeProof, error) { @@ -564,11 +562,11 @@ func (db *merkleDB) GetChangeProof( ctx context.Context, startRootID ids.ID, endRootID ids.ID, - start []byte, + start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], maxLength int, ) (*ChangeProof, error) { - if end.HasValue() && bytes.Compare(start, end.Value()) == 1 { + if start.HasValue() && end.HasValue() && bytes.Compare(start.Value(), end.Value()) == 1 { return nil, ErrStartAfterEnd } if startRootID == endRootID { @@ -628,8 +626,8 @@ func (db *merkleDB) GetChangeProof( result.EndProof = endProof.Path } - if len(start) > 0 { - startProof, err := historicalView.getProof(ctx, start) + if start.HasValue() { + startProof, err := historicalView.getProof(ctx, start.Value()) if err != nil { return nil, err } @@ -988,19 +986,19 @@ func (*merkleDB) CommitToDB(context.Context) error { func (db *merkleDB) VerifyChangeProof( ctx context.Context, proof *ChangeProof, - start []byte, + start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], expectedEndRootID ids.ID, ) error { switch { - case end.HasValue() && bytes.Compare(start, end.Value()) > 0: + case start.HasValue() && end.HasValue() && bytes.Compare(start.Value(), end.Value()) > 0: return ErrStartAfterEnd case proof.Empty(): return ErrNoMerkleProof case end.HasValue() && len(proof.KeyChanges) == 0 && len(proof.EndProof) == 0: // We requested an end proof but didn't get one. return ErrNoEndProof - case len(start) > 0 && len(proof.StartProof) == 0 && len(proof.EndProof) == 0: + case start.HasValue() && len(proof.StartProof) == 0 && len(proof.EndProof) == 0: // We requested a start proof but didn't get one. // Note that we also have to check that [proof.EndProof] is empty // to handle the case that the start proof is empty because all @@ -1013,7 +1011,8 @@ func (db *merkleDB) VerifyChangeProof( return err } - smallestPath := newPath(start) + // Note that if [start] is Nothing, smallestPath is the empty path. + smallestPath := newPath(start.Value()) // Make sure the start proof, if given, is well-formed. if err := verifyProofPath(proof.StartProof, smallestPath); err != nil { @@ -1179,10 +1178,12 @@ func (db *merkleDB) initializeRootIfNeeded() (ids.ID, error) { } // Returns a view of the trie as it was when it had root [rootID] for keys within range [start, end]. +// If [start] is Nothing, there's no lower bound on the range. +// If [end] is Nothing, there's no upper bound on the range. // Assumes [db.commitLock] is read locked. func (db *merkleDB) getHistoricalViewForRange( rootID ids.ID, - start []byte, + start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], ) (*trieView, error) { currentRootID := db.getMerkleRoot() diff --git a/x/merkledb/db_test.go b/x/merkledb/db_test.go index 1927dbc3cbd6..001bb86d11a6 100644 --- a/x/merkledb/db_test.go +++ b/x/merkledb/db_test.go @@ -266,13 +266,13 @@ func Test_MerkleDB_Commit_Proof_To_Empty_Trie(t *testing.T) { require.NoError(batch.Put([]byte("key3"), []byte("3"))) require.NoError(batch.Write()) - proof, err := db.GetRangeProof(context.Background(), []byte("key1"), maybe.Some([]byte("key3")), 10) + proof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte("key1")), maybe.Some([]byte("key3")), 10) require.NoError(err) freshDB, err := getBasicDB() require.NoError(err) - require.NoError(freshDB.CommitRangeProof(context.Background(), []byte("key1"), proof)) + require.NoError(freshDB.CommitRangeProof(context.Background(), maybe.Some([]byte("key1")), proof)) value, err := freshDB.Get([]byte("key2")) require.NoError(err) @@ -296,7 +296,7 @@ func Test_MerkleDB_Commit_Proof_To_Filled_Trie(t *testing.T) { require.NoError(batch.Put([]byte("key3"), []byte("3"))) require.NoError(batch.Write()) - proof, err := db.GetRangeProof(context.Background(), []byte("key1"), maybe.Some([]byte("key3")), 10) + proof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte("key1")), maybe.Some([]byte("key3")), 10) require.NoError(err) freshDB, err := getBasicDB() @@ -308,7 +308,7 @@ func Test_MerkleDB_Commit_Proof_To_Filled_Trie(t *testing.T) { require.NoError(batch.Put([]byte("key25"), []byte("5"))) require.NoError(batch.Write()) - require.NoError(freshDB.CommitRangeProof(context.Background(), []byte("key1"), proof)) + require.NoError(freshDB.CommitRangeProof(context.Background(), maybe.Some([]byte("key1")), proof)) value, err := freshDB.Get([]byte("key2")) require.NoError(err) @@ -747,16 +747,20 @@ func runRandDBTest(require *require.Assertions, r *rand.Rand, rt randTest) { if len(pastRoots) > 0 { root = pastRoots[r.Intn(len(pastRoots))] } + start := maybe.Nothing[[]byte]() + if len(step.key) > 0 { + start = maybe.Some(step.key) + } end := maybe.Nothing[[]byte]() if len(step.value) > 0 { end = maybe.Some(step.value) } - rangeProof, err := db.GetRangeProofAtRoot(context.Background(), root, step.key, end, 100) + rangeProof, err := db.GetRangeProofAtRoot(context.Background(), root, start, end, 100) require.NoError(err) require.NoError(rangeProof.Verify( context.Background(), - step.key, + start, end, root, )) @@ -771,8 +775,12 @@ func runRandDBTest(require *require.Assertions, r *rand.Rand, rt randTest) { if len(step.value) > 0 { end = maybe.Some(step.value) } + start := maybe.Nothing[[]byte]() + if len(step.key) > 0 { + start = maybe.Some(step.key) + } - changeProof, err := db.GetChangeProof(context.Background(), startRoot, root, step.key, end, 100) + changeProof, err := db.GetChangeProof(context.Background(), startRoot, root, start, end, 100) if startRoot == root { require.ErrorIs(err, errSameRoot) continue @@ -784,7 +792,7 @@ func runRandDBTest(require *require.Assertions, r *rand.Rand, rt randTest) { require.NoError(changeProofDB.VerifyChangeProof( context.Background(), changeProof, - step.key, + start, end, root, )) diff --git a/x/merkledb/history.go b/x/merkledb/history.go index 1c23634a8191..a6baeb925a51 100644 --- a/x/merkledb/history.go +++ b/x/merkledb/history.go @@ -73,12 +73,14 @@ func newTrieHistory(maxHistoryLookback int) *trieHistory { // Returns up to [maxLength] key-value pair changes with keys in // [start, end] that occurred between [startRoot] and [endRoot]. +// If [start] is Nothing, there's no lower bound on the range. +// If [end] is Nothing, there's no upper bound on the range. // Returns [ErrInsufficientHistory] if the history is insufficient // to generate the proof. func (th *trieHistory) getValueChanges( startRoot ids.ID, endRoot ids.ID, - start []byte, + start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], maxLength int, ) (*changeSummary, error) { @@ -153,7 +155,7 @@ func (th *trieHistory) getValueChanges( // in order to stay within the [maxLength] limit if necessary. changedKeys = set.Set[path]{} - startPath = newPath(start) + startPath = maybe.Bind(start, newPath) endPath = maybe.Bind(end, newPath) // For each element in the history in the range between [startRoot]'s @@ -178,7 +180,7 @@ func (th *trieHistory) getValueChanges( // Add the changes from this commit to [combinedChanges]. for key, valueChange := range changes.values { // The key is outside the range [start, end]. - if (len(startPath) > 0 && key.Compare(startPath) < 0) || + if (startPath.HasValue() && key.Compare(startPath.Value()) < 0) || (end.HasValue() && key.Compare(endPath.Value()) > 0) { continue } @@ -222,9 +224,9 @@ func (th *trieHistory) getValueChanges( // Returns the changes to go from the current trie state back to the requested [rootID] // for the keys in [start, end]. -// If [start] is nil, all keys are considered > [start]. -// If [end] is nil, all keys are considered < [end]. -func (th *trieHistory) getChangesToGetToRoot(rootID ids.ID, start []byte, end maybe.Maybe[[]byte]) (*changeSummary, error) { +// If [start] is Nothing, all keys are considered > [start]. +// If [end] is Nothing, all keys are considered < [end]. +func (th *trieHistory) getChangesToGetToRoot(rootID ids.ID, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte]) (*changeSummary, error) { // [lastRootChange] is the last change in the history resulting in [rootID]. lastRootChange, ok := th.lastChanges[rootID] if !ok { @@ -232,7 +234,7 @@ func (th *trieHistory) getChangesToGetToRoot(rootID ids.ID, start []byte, end ma } var ( - startPath = newPath(start) + startPath = maybe.Bind(start, newPath) endPath = maybe.Bind(end, newPath) combinedChanges = newChangeSummary(defaultPreallocationSize) mostRecentChangeInsertNumber = th.nextInsertNumber - 1 @@ -254,7 +256,7 @@ func (th *trieHistory) getChangesToGetToRoot(rootID ids.ID, start []byte, end ma } for key, valueChange := range changes.values { - if (len(startPath) == 0 || key.Compare(startPath) >= 0) && + if (startPath.IsNothing() || key.Compare(startPath.Value()) >= 0) && (endPath.IsNothing() || key.Compare(endPath.Value()) <= 0) { if existing, ok := combinedChanges.values[key]; ok { existing.after = valueChange.before diff --git a/x/merkledb/history_test.go b/x/merkledb/history_test.go index 5018ad9a7add..b3bf89fb5ef1 100644 --- a/x/merkledb/history_test.go +++ b/x/merkledb/history_test.go @@ -33,36 +33,36 @@ func Test_History_Simple(t *testing.T) { require.NoError(err) require.Equal([]byte("value"), val) - origProof, err := db.GetRangeProof(context.Background(), []byte("k"), maybe.Some([]byte("key3")), 10) + origProof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(origProof) origRootID := db.root.id - require.NoError(origProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(origProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) batch = db.NewBatch() require.NoError(batch.Put([]byte("key"), []byte("value0"))) require.NoError(batch.Write()) - newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), maybe.Some([]byte("key3")), 10) + newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(newProof) - require.NoError(newProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(newProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) batch = db.NewBatch() require.NoError(batch.Put([]byte("key1"), []byte("value1"))) require.NoError(batch.Put([]byte("key8"), []byte("value8"))) require.NoError(batch.Write()) - newProof, err = db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), maybe.Some([]byte("key3")), 10) + newProof, err = db.GetRangeProofAtRoot(context.Background(), origRootID, maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(newProof) - require.NoError(newProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(newProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) batch = db.NewBatch() require.NoError(batch.Put([]byte("k"), []byte("v"))) require.NoError(batch.Write()) - newProof, err = db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), maybe.Some([]byte("key3")), 10) + newProof, err = db.GetRangeProofAtRoot(context.Background(), origRootID, maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(newProof) - require.NoError(newProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(newProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) batch = db.NewBatch() require.NoError(batch.Delete([]byte("k"))) @@ -75,10 +75,10 @@ func Test_History_Simple(t *testing.T) { require.NoError(batch.Delete([]byte("key5"))) require.NoError(batch.Delete([]byte("key8"))) require.NoError(batch.Write()) - newProof, err = db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), maybe.Some([]byte("key3")), 10) + newProof, err = db.GetRangeProofAtRoot(context.Background(), origRootID, maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(newProof) - require.NoError(newProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(newProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) } func Test_History_Large(t *testing.T) { @@ -134,11 +134,11 @@ func Test_History_Large(t *testing.T) { require.NoError(err) roots = append(roots, root) } - proof, err := db.GetRangeProofAtRoot(context.Background(), roots[0], nil, maybe.Nothing[[]byte](), 10) + proof, err := db.GetRangeProofAtRoot(context.Background(), roots[0], maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 10) require.NoError(err) require.NotNil(proof) - require.NoError(proof.Verify(context.Background(), nil, maybe.Nothing[[]byte](), roots[0])) + require.NoError(proof.Verify(context.Background(), maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), roots[0])) } } @@ -183,15 +183,15 @@ func Test_History_Bad_GetValueChanges_Input(t *testing.T) { endRoot := db.getMerkleRoot() // ensure these start as valid calls - _, err = db.history.getValueChanges(toBeDeletedRoot, endRoot, nil, maybe.Nothing[[]byte](), 1) + _, err = db.history.getValueChanges(toBeDeletedRoot, endRoot, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 1) require.NoError(err) - _, err = db.history.getValueChanges(startRoot, endRoot, nil, maybe.Nothing[[]byte](), 1) + _, err = db.history.getValueChanges(startRoot, endRoot, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 1) require.NoError(err) - _, err = db.history.getValueChanges(startRoot, endRoot, nil, maybe.Nothing[[]byte](), -1) + _, err = db.history.getValueChanges(startRoot, endRoot, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), -1) require.ErrorIs(err, ErrInvalidMaxLength) - _, err = db.history.getValueChanges(endRoot, startRoot, nil, maybe.Nothing[[]byte](), 1) + _, err = db.history.getValueChanges(endRoot, startRoot, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 1) require.ErrorIs(err, ErrInsufficientHistory) // trigger the first root to be deleted by exiting the lookback window @@ -200,11 +200,11 @@ func Test_History_Bad_GetValueChanges_Input(t *testing.T) { require.NoError(batch.Write()) // now this root should no longer be present - _, err = db.history.getValueChanges(toBeDeletedRoot, endRoot, nil, maybe.Nothing[[]byte](), 1) + _, err = db.history.getValueChanges(toBeDeletedRoot, endRoot, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 1) require.ErrorIs(err, ErrInsufficientHistory) // same start/end roots should yield an empty changelist - changes, err := db.history.getValueChanges(endRoot, endRoot, nil, maybe.Nothing[[]byte](), 10) + changes, err := db.history.getValueChanges(endRoot, endRoot, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 10) require.NoError(err) require.Empty(changes.values) } @@ -228,12 +228,12 @@ func Test_History_Trigger_History_Queue_Looping(t *testing.T) { require.NoError(batch.Write()) origRootID := db.getMerkleRoot() - origProof, err := db.GetRangeProof(context.Background(), []byte("k"), maybe.Some([]byte("key3")), 10) + origProof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(origProof) require.NoError(origProof.Verify( context.Background(), - []byte("k"), + maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID, )) @@ -244,12 +244,12 @@ func Test_History_Trigger_History_Queue_Looping(t *testing.T) { require.NoError(batch.Write()) // ensure that previous root is still present and generates a valid proof - newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), maybe.Some([]byte("key3")), 10) + newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(newProof) require.NoError(newProof.Verify( context.Background(), - []byte("k"), + maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID, )) @@ -260,7 +260,7 @@ func Test_History_Trigger_History_Queue_Looping(t *testing.T) { require.NoError(batch.Write()) // proof from first root shouldn't be generatable since it should have been removed from the history - _, err = db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), maybe.Some([]byte("key3")), 10) + _, err = db.GetRangeProofAtRoot(context.Background(), origRootID, maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.ErrorIs(err, ErrInsufficientHistory) } @@ -306,7 +306,7 @@ func Test_History_Values_Lookup_Over_Queue_Break(t *testing.T) { endRoot := db.getMerkleRoot() // changes should still be collectable even though the history has had to loop due to hitting max size - changes, err := db.history.getValueChanges(startRoot, endRoot, nil, maybe.Nothing[[]byte](), 10) + changes, err := db.history.getValueChanges(startRoot, endRoot, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 10) require.NoError(err) require.Contains(changes.values, newPath([]byte("key1"))) require.Equal([]byte("value1"), changes.values[newPath([]byte("key1"))].after.Value()) @@ -329,21 +329,21 @@ func Test_History_RepeatedRoot(t *testing.T) { require.NoError(batch.Put([]byte("key3"), []byte("value3"))) require.NoError(batch.Write()) - origProof, err := db.GetRangeProof(context.Background(), []byte("k"), maybe.Some([]byte("key3")), 10) + origProof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(origProof) origRootID := db.root.id - require.NoError(origProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(origProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) batch = db.NewBatch() require.NoError(batch.Put([]byte("key1"), []byte("other"))) require.NoError(batch.Put([]byte("key2"), []byte("other"))) require.NoError(batch.Put([]byte("key3"), []byte("other"))) require.NoError(batch.Write()) - newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), maybe.Some([]byte("key3")), 10) + newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(newProof) - require.NoError(newProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(newProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) // revert state to be the same as in orig proof batch = db.NewBatch() @@ -352,10 +352,10 @@ func Test_History_RepeatedRoot(t *testing.T) { require.NoError(batch.Put([]byte("key3"), []byte("value3"))) require.NoError(batch.Write()) - newProof, err = db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), maybe.Some([]byte("key3")), 10) + newProof, err = db.GetRangeProofAtRoot(context.Background(), origRootID, maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(newProof) - require.NoError(newProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(newProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) } func Test_History_ExcessDeletes(t *testing.T) { @@ -371,11 +371,11 @@ func Test_History_ExcessDeletes(t *testing.T) { require.NoError(batch.Put([]byte("key"), []byte("value"))) require.NoError(batch.Write()) - origProof, err := db.GetRangeProof(context.Background(), []byte("k"), maybe.Some([]byte("key3")), 10) + origProof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(origProof) origRootID := db.root.id - require.NoError(origProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(origProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) batch = db.NewBatch() require.NoError(batch.Delete([]byte("key1"))) @@ -384,10 +384,10 @@ func Test_History_ExcessDeletes(t *testing.T) { require.NoError(batch.Delete([]byte("key4"))) require.NoError(batch.Delete([]byte("key5"))) require.NoError(batch.Write()) - newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), maybe.Some([]byte("key3")), 10) + newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(newProof) - require.NoError(newProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(newProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) } func Test_History_DontIncludeAllNodes(t *testing.T) { @@ -403,19 +403,19 @@ func Test_History_DontIncludeAllNodes(t *testing.T) { require.NoError(batch.Put([]byte("key"), []byte("value"))) require.NoError(batch.Write()) - origProof, err := db.GetRangeProof(context.Background(), []byte("k"), maybe.Some([]byte("key3")), 10) + origProof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(origProof) origRootID := db.root.id - require.NoError(origProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(origProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) batch = db.NewBatch() require.NoError(batch.Put([]byte("z"), []byte("z"))) require.NoError(batch.Write()) - newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), maybe.Some([]byte("key3")), 10) + newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(newProof) - require.NoError(newProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(newProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) } func Test_History_Branching2Nodes(t *testing.T) { @@ -431,19 +431,19 @@ func Test_History_Branching2Nodes(t *testing.T) { require.NoError(batch.Put([]byte("key"), []byte("value"))) require.NoError(batch.Write()) - origProof, err := db.GetRangeProof(context.Background(), []byte("k"), maybe.Some([]byte("key3")), 10) + origProof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(origProof) origRootID := db.root.id - require.NoError(origProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(origProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) batch = db.NewBatch() require.NoError(batch.Put([]byte("k"), []byte("v"))) require.NoError(batch.Write()) - newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), maybe.Some([]byte("key3")), 10) + newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(newProof) - require.NoError(newProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(newProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) } func Test_History_Branching3Nodes(t *testing.T) { @@ -459,19 +459,19 @@ func Test_History_Branching3Nodes(t *testing.T) { require.NoError(batch.Put([]byte("key123"), []byte("value123"))) require.NoError(batch.Write()) - origProof, err := db.GetRangeProof(context.Background(), []byte("k"), maybe.Some([]byte("key3")), 10) + origProof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(origProof) origRootID := db.root.id - require.NoError(origProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(origProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) batch = db.NewBatch() require.NoError(batch.Put([]byte("key321"), []byte("value321"))) require.NoError(batch.Write()) - newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), maybe.Some([]byte("key3")), 10) + newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, maybe.Some([]byte("k")), maybe.Some([]byte("key3")), 10) require.NoError(err) require.NotNil(newProof) - require.NoError(newProof.Verify(context.Background(), []byte("k"), maybe.Some([]byte("key3")), origRootID)) + require.NoError(newProof.Verify(context.Background(), maybe.Some([]byte("k")), maybe.Some([]byte("key3")), origRootID)) } func Test_History_MaxLength(t *testing.T) { @@ -544,7 +544,7 @@ func Test_Change_List(t *testing.T) { endRoot, err := db.GetMerkleRoot(context.Background()) require.NoError(err) - changes, err := db.history.getValueChanges(startRoot, endRoot, nil, maybe.Nothing[[]byte](), 8) + changes, err := db.history.getValueChanges(startRoot, endRoot, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 8) require.NoError(err) require.Len(changes.values, 8) } @@ -651,7 +651,7 @@ func TestHistoryGetChangesToRoot(t *testing.T) { type test struct { name string rootID ids.ID - start []byte + start maybe.Maybe[[]byte] end maybe.Maybe[[]byte] validateFunc func(*require.Assertions, *changeSummary) expectedErr error @@ -705,7 +705,7 @@ func TestHistoryGetChangesToRoot(t *testing.T) { { name: "third most recent change with start filter", rootID: changes[maxHistoryLen-3].rootID, - start: []byte{byte(maxHistoryLen - 1)}, // Omit values from second most recent change + start: maybe.Some([]byte{byte(maxHistoryLen - 1)}), // Omit values from second most recent change validateFunc: func(require *require.Assertions, got *changeSummary) { require.Len(got.nodes, 2) require.Len(got.values, 1) diff --git a/x/merkledb/mock_db.go b/x/merkledb/mock_db.go index 562a6a126597..5db7ff039bbb 100644 --- a/x/merkledb/mock_db.go +++ b/x/merkledb/mock_db.go @@ -69,7 +69,7 @@ func (mr *MockMerkleDBMockRecorder) CommitChangeProof(arg0, arg1 interface{}) *g } // CommitRangeProof mocks base method. -func (m *MockMerkleDB) CommitRangeProof(arg0 context.Context, arg1 []byte, arg2 *RangeProof) error { +func (m *MockMerkleDB) CommitRangeProof(arg0 context.Context, arg1 maybe.Maybe[[]uint8], arg2 *RangeProof) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CommitRangeProof", arg0, arg1, arg2) ret0, _ := ret[0].(error) @@ -126,7 +126,7 @@ func (mr *MockMerkleDBMockRecorder) Get(arg0 interface{}) *gomock.Call { } // GetChangeProof mocks base method. -func (m *MockMerkleDB) GetChangeProof(arg0 context.Context, arg1, arg2 ids.ID, arg3 []byte, arg4 maybe.Maybe[[]uint8], arg5 int) (*ChangeProof, error) { +func (m *MockMerkleDB) GetChangeProof(arg0 context.Context, arg1, arg2 ids.ID, arg3, arg4 maybe.Maybe[[]uint8], arg5 int) (*ChangeProof, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetChangeProof", arg0, arg1, arg2, arg3, arg4, arg5) ret0, _ := ret[0].(*ChangeProof) @@ -171,7 +171,7 @@ func (mr *MockMerkleDBMockRecorder) GetProof(arg0, arg1 interface{}) *gomock.Cal } // GetRangeProof mocks base method. -func (m *MockMerkleDB) GetRangeProof(arg0 context.Context, arg1 []byte, arg2 maybe.Maybe[[]uint8], arg3 int) (*RangeProof, error) { +func (m *MockMerkleDB) GetRangeProof(arg0 context.Context, arg1, arg2 maybe.Maybe[[]uint8], arg3 int) (*RangeProof, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetRangeProof", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(*RangeProof) @@ -186,7 +186,7 @@ func (mr *MockMerkleDBMockRecorder) GetRangeProof(arg0, arg1, arg2, arg3 interfa } // GetRangeProofAtRoot mocks base method. -func (m *MockMerkleDB) GetRangeProofAtRoot(arg0 context.Context, arg1 ids.ID, arg2 []byte, arg3 maybe.Maybe[[]uint8], arg4 int) (*RangeProof, error) { +func (m *MockMerkleDB) GetRangeProofAtRoot(arg0 context.Context, arg1 ids.ID, arg2, arg3 maybe.Maybe[[]uint8], arg4 int) (*RangeProof, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetRangeProofAtRoot", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(*RangeProof) @@ -360,7 +360,7 @@ func (mr *MockMerkleDBMockRecorder) Put(arg0, arg1 interface{}) *gomock.Call { } // VerifyChangeProof mocks base method. -func (m *MockMerkleDB) VerifyChangeProof(arg0 context.Context, arg1 *ChangeProof, arg2 []byte, arg3 maybe.Maybe[[]uint8], arg4 ids.ID) error { +func (m *MockMerkleDB) VerifyChangeProof(arg0 context.Context, arg1 *ChangeProof, arg2, arg3 maybe.Maybe[[]uint8], arg4 ids.ID) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "VerifyChangeProof", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(error) diff --git a/x/merkledb/proof.go b/x/merkledb/proof.go index d6250fc57100..84008abc710f 100644 --- a/x/merkledb/proof.go +++ b/x/merkledb/proof.go @@ -276,16 +276,16 @@ type RangeProof struct { // - [proof] proves the key-value pairs in [proof.KeyValues] are in the trie // whose root is [expectedRootID]. // - All keys in [proof.KeyValues] are in the range [start, end]. -// If [start] is empty, all keys are considered > [start]. -// If [end] is empty, all keys are considered < [end]. +// If [start] is Nothing, all keys are considered > [start]. +// If [end] is Nothing, all keys are considered < [end]. func (proof *RangeProof) Verify( ctx context.Context, - start []byte, + start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], expectedRootID ids.ID, ) error { switch { - case end.HasValue() && bytes.Compare(start, end.Value()) > 0: + case start.HasValue() && end.HasValue() && bytes.Compare(start.Value(), end.Value()) > 0: return ErrStartAfterEnd case len(proof.KeyValues) == 0 && len(proof.StartProof) == 0 && len(proof.EndProof) == 0: return ErrNoMerkleProof @@ -309,10 +309,7 @@ func (proof *RangeProof) Verify( // If [largestProvenPath] is Nothing, [proof] should // provide and prove all keys > [smallestProvenPath]. // If both are Nothing, [proof] should prove the entire trie. - smallestProvenPath := maybe.Nothing[path]() - if start != nil { - smallestProvenPath = maybe.Some(newPath(start)) - } + smallestProvenPath := maybe.Bind(start, newPath) largestProvenPath := maybe.Bind(end, newPath) if len(proof.KeyValues) > 0 { @@ -692,10 +689,10 @@ type ChangeOrRangeProof struct { // Returns nil iff both hold: // 1. [kvs] is sorted by key in increasing order. // 2. All keys in [kvs] are in the range [start, end]. -// If [start] is nil, there is no lower bound on acceptable keys. -// If [end] is nothing, there is no upper bound on acceptable keys. +// If [start] is Nothing, there is no lower bound on acceptable keys. +// If [end] is Nothing, there is no upper bound on acceptable keys. // If [kvs] is empty, returns nil. -func verifyKeyChanges(kvs []KeyChange, start []byte, end maybe.Maybe[[]byte]) error { +func verifyKeyChanges(kvs []KeyChange, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte]) error { if len(kvs) == 0 { return nil } @@ -708,7 +705,7 @@ func verifyKeyChanges(kvs []KeyChange, start []byte, end maybe.Maybe[[]byte]) er } // ensure that the keys are within the range [start, end] - if (len(start) > 0 && bytes.Compare(kvs[0].Key, start) < 0) || + if (start.HasValue() && bytes.Compare(kvs[0].Key, start.Value()) < 0) || (end.HasValue() && bytes.Compare(kvs[len(kvs)-1].Key, end.Value()) > 0) { return ErrStateFromOutsideOfRange } @@ -722,14 +719,15 @@ func verifyKeyChanges(kvs []KeyChange, start []byte, end maybe.Maybe[[]byte]) er // If [start] is nil, there is no lower bound on acceptable keys. // If [end] is nothing, there is no upper bound on acceptable keys. // If [kvs] is empty, returns nil. -func verifyKeyValues(kvs []KeyValue, start []byte, end maybe.Maybe[[]byte]) error { - hasLowerBound := len(start) > 0 +func verifyKeyValues(kvs []KeyValue, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte]) error { + hasLowerBound := start.HasValue() + hasUpperBound := end.HasValue() for i := 0; i < len(kvs); i++ { if i < len(kvs)-1 && bytes.Compare(kvs[i].Key, kvs[i+1].Key) >= 0 { return ErrNonIncreasingValues } - if (hasLowerBound && bytes.Compare(kvs[i].Key, start) < 0) || - (end.HasValue() && bytes.Compare(kvs[i].Key, end.Value()) > 0) { + if (hasLowerBound && bytes.Compare(kvs[i].Key, start.Value()) < 0) || + (hasUpperBound && bytes.Compare(kvs[i].Key, end.Value()) > 0) { return ErrStateFromOutsideOfRange } } diff --git a/x/merkledb/proof_test.go b/x/merkledb/proof_test.go index 6da5171d8ef2..f4935987531a 100644 --- a/x/merkledb/proof_test.go +++ b/x/merkledb/proof_test.go @@ -164,13 +164,13 @@ func Test_RangeProof_Extra_Value(t *testing.T) { require.NoError(err) require.Equal([]byte{2}, val) - proof, err := db.GetRangeProof(context.Background(), []byte{1}, maybe.Some([]byte{5, 5}), 10) + proof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte{1}), maybe.Some([]byte{5, 5}), 10) require.NoError(err) require.NotNil(proof) require.NoError(proof.Verify( context.Background(), - []byte{1}, + maybe.Some([]byte{1}), maybe.Some([]byte{5, 5}), db.root.id, )) @@ -179,7 +179,7 @@ func Test_RangeProof_Extra_Value(t *testing.T) { err = proof.Verify( context.Background(), - []byte{1}, + maybe.Some([]byte{1}), maybe.Some([]byte{5, 5}), db.root.id, ) @@ -237,13 +237,13 @@ func Test_RangeProof_Verify_Bad_Data(t *testing.T) { require.NoError(err) writeBasicBatch(t, db) - proof, err := db.GetRangeProof(context.Background(), []byte{2}, maybe.Some([]byte{3, 0}), 50) + proof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte{2}), maybe.Some([]byte{3, 0}), 50) require.NoError(err) require.NotNil(proof) tt.malform(proof) - err = proof.Verify(context.Background(), []byte{2}, maybe.Some([]byte{3, 0}), db.getMerkleRoot()) + err = proof.Verify(context.Background(), maybe.Some([]byte{2}), maybe.Some([]byte{3, 0}), db.getMerkleRoot()) require.ErrorIs(err, tt.expectedErr) }) } @@ -258,10 +258,10 @@ func Test_RangeProof_MaxLength(t *testing.T) { trie, err := dbTrie.NewView(nil) require.NoError(err) - _, err = trie.GetRangeProof(context.Background(), nil, maybe.Nothing[[]byte](), -1) + _, err = trie.GetRangeProof(context.Background(), maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), -1) require.ErrorIs(err, ErrInvalidMaxLength) - _, err = trie.GetRangeProof(context.Background(), nil, maybe.Nothing[[]byte](), 0) + _, err = trie.GetRangeProof(context.Background(), maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 0) require.ErrorIs(err, ErrInvalidMaxLength) } @@ -307,7 +307,7 @@ func Test_Proof(t *testing.T) { func Test_RangeProof_Syntactic_Verify(t *testing.T) { type test struct { name string - start []byte + start maybe.Maybe[[]byte] end maybe.Maybe[[]byte] proof *RangeProof expectedErr error @@ -316,21 +316,21 @@ func Test_RangeProof_Syntactic_Verify(t *testing.T) { tests := []test{ { name: "start > end", - start: []byte{1}, + start: maybe.Some([]byte{1}), end: maybe.Some([]byte{0}), proof: &RangeProof{}, expectedErr: ErrStartAfterEnd, }, { name: "empty", // Also tests start can be > end if end is nil - start: []byte{1}, + start: maybe.Some([]byte{1}), end: maybe.Nothing[[]byte](), proof: &RangeProof{}, expectedErr: ErrNoMerkleProof, }, { name: "unexpected end proof", - start: []byte{1}, + start: maybe.Some([]byte{1}), end: maybe.Nothing[[]byte](), proof: &RangeProof{ StartProof: []ProofNode{{}}, @@ -340,7 +340,7 @@ func Test_RangeProof_Syntactic_Verify(t *testing.T) { }, { name: "should just be root", - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Nothing[[]byte](), proof: &RangeProof{ EndProof: []ProofNode{{}, {}}, @@ -349,7 +349,7 @@ func Test_RangeProof_Syntactic_Verify(t *testing.T) { }, { name: "no end proof; has end bound", - start: []byte{1}, + start: maybe.Some([]byte{1}), end: maybe.Some([]byte{1}), proof: &RangeProof{ StartProof: []ProofNode{{}}, @@ -358,7 +358,7 @@ func Test_RangeProof_Syntactic_Verify(t *testing.T) { }, { name: "no end proof; has key-values", - start: []byte{1}, + start: maybe.Some([]byte{1}), end: maybe.Nothing[[]byte](), proof: &RangeProof{ KeyValues: []KeyValue{{}}, @@ -367,7 +367,7 @@ func Test_RangeProof_Syntactic_Verify(t *testing.T) { }, { name: "unsorted key values", - start: []byte{1}, + start: maybe.Some([]byte{1}), end: maybe.Nothing[[]byte](), proof: &RangeProof{ KeyValues: []KeyValue{ @@ -380,7 +380,7 @@ func Test_RangeProof_Syntactic_Verify(t *testing.T) { }, { name: "key lower than start", - start: []byte{1}, + start: maybe.Some([]byte{1}), end: maybe.Nothing[[]byte](), proof: &RangeProof{ KeyValues: []KeyValue{ @@ -392,7 +392,7 @@ func Test_RangeProof_Syntactic_Verify(t *testing.T) { }, { name: "key greater than end", - start: []byte{1}, + start: maybe.Some([]byte{1}), end: maybe.Some([]byte{1}), proof: &RangeProof{ KeyValues: []KeyValue{ @@ -404,7 +404,7 @@ func Test_RangeProof_Syntactic_Verify(t *testing.T) { }, { name: "start proof nodes in wrong order", - start: []byte{1, 2}, + start: maybe.Some([]byte{1, 2}), end: maybe.Nothing[[]byte](), proof: &RangeProof{ KeyValues: []KeyValue{ @@ -424,7 +424,7 @@ func Test_RangeProof_Syntactic_Verify(t *testing.T) { }, { name: "start proof has node for wrong key", - start: []byte{1, 2}, + start: maybe.Some([]byte{1, 2}), end: maybe.Nothing[[]byte](), proof: &RangeProof{ KeyValues: []KeyValue{ @@ -447,7 +447,7 @@ func Test_RangeProof_Syntactic_Verify(t *testing.T) { }, { name: "end proof nodes in wrong order", - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Some([]byte{1, 2}), proof: &RangeProof{ KeyValues: []KeyValue{ @@ -466,7 +466,7 @@ func Test_RangeProof_Syntactic_Verify(t *testing.T) { }, { name: "end proof has node for wrong key", - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Some([]byte{1, 2}), proof: &RangeProof{ KeyValues: []KeyValue{ @@ -503,7 +503,7 @@ func Test_RangeProof(t *testing.T) { require.NoError(err) writeBasicBatch(t, db) - proof, err := db.GetRangeProof(context.Background(), []byte{1}, maybe.Some([]byte{3, 5}), 10) + proof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte{1}), maybe.Some([]byte{3, 5}), 10) require.NoError(err) require.NotNil(proof) require.Len(proof.KeyValues, 3) @@ -525,7 +525,7 @@ func Test_RangeProof(t *testing.T) { require.NoError(proof.Verify( context.Background(), - []byte{1}, + maybe.Some([]byte{1}), maybe.Some([]byte{3, 5}), db.root.id, )) @@ -538,7 +538,7 @@ func Test_RangeProof_BadBounds(t *testing.T) { require.NoError(err) // non-nil start/end - proof, err := db.GetRangeProof(context.Background(), []byte{4}, maybe.Some([]byte{3}), 50) + proof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte{4}), maybe.Some([]byte{3}), 50) require.ErrorIs(err, ErrStartAfterEnd) require.Nil(proof) } @@ -559,7 +559,7 @@ func Test_RangeProof_NilStart(t *testing.T) { require.NoError(err) require.Equal([]byte("value1"), val) - proof, err := db.GetRangeProof(context.Background(), nil, maybe.Some([]byte("key35")), 2) + proof, err := db.GetRangeProof(context.Background(), maybe.Nothing[[]byte](), maybe.Some([]byte("key35")), 2) require.NoError(err) require.NotNil(proof) @@ -577,7 +577,7 @@ func Test_RangeProof_NilStart(t *testing.T) { require.NoError(proof.Verify( context.Background(), - nil, + maybe.Nothing[[]byte](), maybe.Some([]byte("key35")), db.root.id, )) @@ -591,7 +591,7 @@ func Test_RangeProof_NilEnd(t *testing.T) { writeBasicBatch(t, db) require.NoError(err) - proof, err := db.GetRangeProof(context.Background(), []byte{1}, maybe.Nothing[[]byte](), 2) + proof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte{1}), maybe.Nothing[[]byte](), 2) require.NoError(err) require.NotNil(proof) @@ -611,7 +611,7 @@ func Test_RangeProof_NilEnd(t *testing.T) { require.NoError(proof.Verify( context.Background(), - []byte{1}, + maybe.Some([]byte{1}), maybe.Nothing[[]byte](), db.root.id, )) @@ -632,7 +632,7 @@ func Test_RangeProof_EmptyValues(t *testing.T) { require.NoError(err) require.Equal([]byte("value1"), val) - proof, err := db.GetRangeProof(context.Background(), []byte("key1"), maybe.Some([]byte("key2")), 10) + proof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte("key1")), maybe.Some([]byte("key2")), 10) require.NoError(err) require.NotNil(proof) @@ -653,7 +653,7 @@ func Test_RangeProof_EmptyValues(t *testing.T) { require.NoError(proof.Verify( context.Background(), - []byte("key1"), + maybe.Some([]byte("key1")), maybe.Some([]byte("key2")), db.root.id, )) @@ -667,7 +667,7 @@ func Test_ChangeProof_Missing_History_For_EndRoot(t *testing.T) { startRoot, err := db.GetMerkleRoot(context.Background()) require.NoError(err) - _, err = db.GetChangeProof(context.Background(), startRoot, ids.Empty, nil, maybe.Nothing[[]byte](), 50) + _, err = db.GetChangeProof(context.Background(), startRoot, ids.Empty, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 50) require.ErrorIs(err, ErrInsufficientHistory) } @@ -686,7 +686,7 @@ func Test_ChangeProof_BadBounds(t *testing.T) { require.NoError(err) // non-nil start/end - proof, err := db.GetChangeProof(context.Background(), startRoot, endRoot, []byte("key4"), maybe.Some([]byte("key3")), 50) + proof, err := db.GetChangeProof(context.Background(), startRoot, endRoot, maybe.Some([]byte("key4")), maybe.Some([]byte("key3")), 50) require.ErrorIs(err, ErrStartAfterEnd) require.Nil(proof) } @@ -742,36 +742,36 @@ func Test_ChangeProof_Verify(t *testing.T) { require.NoError(err) // non-nil start/end - proof, err := db.GetChangeProof(context.Background(), startRoot, endRoot, []byte("key21"), maybe.Some([]byte("key30")), 50) + proof, err := db.GetChangeProof(context.Background(), startRoot, endRoot, maybe.Some([]byte("key21")), maybe.Some([]byte("key30")), 50) require.NoError(err) require.NotNil(proof) - require.NoError(dbClone.VerifyChangeProof(context.Background(), proof, []byte("key21"), maybe.Some([]byte("key30")), db.getMerkleRoot())) + require.NoError(dbClone.VerifyChangeProof(context.Background(), proof, maybe.Some([]byte("key21")), maybe.Some([]byte("key30")), db.getMerkleRoot())) // low maxLength - proof, err = db.GetChangeProof(context.Background(), startRoot, endRoot, nil, maybe.Nothing[[]byte](), 5) + proof, err = db.GetChangeProof(context.Background(), startRoot, endRoot, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 5) require.NoError(err) require.NotNil(proof) - require.NoError(dbClone.VerifyChangeProof(context.Background(), proof, nil, maybe.Nothing[[]byte](), db.getMerkleRoot())) + require.NoError(dbClone.VerifyChangeProof(context.Background(), proof, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), db.getMerkleRoot())) // nil start/end - proof, err = db.GetChangeProof(context.Background(), startRoot, endRoot, nil, maybe.Nothing[[]byte](), 50) + proof, err = db.GetChangeProof(context.Background(), startRoot, endRoot, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 50) require.NoError(err) require.NotNil(proof) - require.NoError(dbClone.VerifyChangeProof(context.Background(), proof, nil, maybe.Nothing[[]byte](), endRoot)) + require.NoError(dbClone.VerifyChangeProof(context.Background(), proof, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), endRoot)) require.NoError(dbClone.CommitChangeProof(context.Background(), proof)) newRoot, err := dbClone.GetMerkleRoot(context.Background()) require.NoError(err) require.Equal(endRoot, newRoot) - proof, err = db.GetChangeProof(context.Background(), startRoot, endRoot, []byte("key20"), maybe.Some([]byte("key30")), 50) + proof, err = db.GetChangeProof(context.Background(), startRoot, endRoot, maybe.Some([]byte("key20")), maybe.Some([]byte("key30")), 50) require.NoError(err) require.NotNil(proof) - require.NoError(dbClone.VerifyChangeProof(context.Background(), proof, []byte("key20"), maybe.Some([]byte("key30")), db.getMerkleRoot())) + require.NoError(dbClone.VerifyChangeProof(context.Background(), proof, maybe.Some([]byte("key20")), maybe.Some([]byte("key30")), db.getMerkleRoot())) } func Test_ChangeProof_Verify_Bad_Data(t *testing.T) { @@ -829,13 +829,13 @@ func Test_ChangeProof_Verify_Bad_Data(t *testing.T) { dbClone, err := getBasicDB() require.NoError(err) - proof, err := db.GetChangeProof(context.Background(), startRoot, endRoot, []byte{2}, maybe.Some([]byte{3, 0}), 50) + proof, err := db.GetChangeProof(context.Background(), startRoot, endRoot, maybe.Some([]byte{2}), maybe.Some([]byte{3, 0}), 50) require.NoError(err) require.NotNil(proof) tt.malform(proof) - err = dbClone.VerifyChangeProof(context.Background(), proof, []byte{2}, maybe.Some([]byte{3, 0}), db.getMerkleRoot()) + err = dbClone.VerifyChangeProof(context.Background(), proof, maybe.Some([]byte{2}), maybe.Some([]byte{3, 0}), db.getMerkleRoot()) require.ErrorIs(err, tt.expectedErr) }) } @@ -845,7 +845,7 @@ func Test_ChangeProof_Syntactic_Verify(t *testing.T) { type test struct { name string proof *ChangeProof - start []byte + start maybe.Maybe[[]byte] end maybe.Maybe[[]byte] expectedErr error } @@ -854,14 +854,14 @@ func Test_ChangeProof_Syntactic_Verify(t *testing.T) { { name: "start after end", proof: nil, - start: []byte{1}, + start: maybe.Some([]byte{1}), end: maybe.Some([]byte{0}), expectedErr: ErrStartAfterEnd, }, { name: "empty", proof: &ChangeProof{}, - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Nothing[[]byte](), expectedErr: ErrNoMerkleProof, }, @@ -870,7 +870,7 @@ func Test_ChangeProof_Syntactic_Verify(t *testing.T) { proof: &ChangeProof{ StartProof: []ProofNode{{}}, }, - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Some([]byte{1}), expectedErr: ErrNoEndProof, }, @@ -879,7 +879,7 @@ func Test_ChangeProof_Syntactic_Verify(t *testing.T) { proof: &ChangeProof{ KeyChanges: []KeyChange{{Key: []byte{1}}}, }, - start: []byte{1}, + start: maybe.Some([]byte{1}), end: maybe.Nothing[[]byte](), expectedErr: ErrNoStartProof, }, @@ -891,7 +891,7 @@ func Test_ChangeProof_Syntactic_Verify(t *testing.T) { {Key: []byte{0}}, }, }, - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Nothing[[]byte](), expectedErr: ErrNonIncreasingValues, }, @@ -903,7 +903,7 @@ func Test_ChangeProof_Syntactic_Verify(t *testing.T) { {Key: []byte{0}}, }, }, - start: []byte{1}, + start: maybe.Some([]byte{1}), end: maybe.Nothing[[]byte](), expectedErr: ErrStateFromOutsideOfRange, }, @@ -915,7 +915,7 @@ func Test_ChangeProof_Syntactic_Verify(t *testing.T) { {Key: []byte{2}}, }, }, - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Some([]byte{1}), expectedErr: ErrStateFromOutsideOfRange, }, @@ -927,7 +927,7 @@ func Test_ChangeProof_Syntactic_Verify(t *testing.T) { {Key: []byte{1}}, }, }, - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Nothing[[]byte](), expectedErr: ErrNonIncreasingValues, }, @@ -939,7 +939,7 @@ func Test_ChangeProof_Syntactic_Verify(t *testing.T) { {KeyPath: newPath([]byte{2, 3}).Serialize()}, }, }, - start: []byte{1, 2, 3}, + start: maybe.Some([]byte{1, 2, 3}), end: maybe.Nothing[[]byte](), expectedErr: ErrProofNodeNotForKey, }, @@ -951,7 +951,7 @@ func Test_ChangeProof_Syntactic_Verify(t *testing.T) { {KeyPath: newPath([]byte{2, 3}).Serialize()}, }, }, - start: []byte{1, 2, 3}, + start: maybe.Some([]byte{1, 2, 3}), end: maybe.Nothing[[]byte](), expectedErr: ErrNonIncreasingProofNodes, }, @@ -966,7 +966,7 @@ func Test_ChangeProof_Syntactic_Verify(t *testing.T) { {KeyPath: newPath([]byte{2, 3}).Serialize()}, }, }, - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Nothing[[]byte](), expectedErr: ErrProofNodeNotForKey, }, @@ -981,7 +981,7 @@ func Test_ChangeProof_Syntactic_Verify(t *testing.T) { {KeyPath: newPath([]byte{2, 3}).Serialize()}, }, }, - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Nothing[[]byte](), expectedErr: ErrNonIncreasingProofNodes, }, @@ -1002,7 +1002,7 @@ func Test_ChangeProof_Syntactic_Verify(t *testing.T) { func TestVerifyKeyValues(t *testing.T) { type test struct { name string - start []byte + start maybe.Maybe[[]byte] end maybe.Maybe[[]byte] kvs []KeyValue expectedErr error @@ -1011,14 +1011,14 @@ func TestVerifyKeyValues(t *testing.T) { tests := []test{ { name: "empty", - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Nothing[[]byte](), kvs: nil, expectedErr: nil, }, { name: "1 key", - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Nothing[[]byte](), kvs: []KeyValue{ {Key: []byte{0}}, @@ -1027,7 +1027,7 @@ func TestVerifyKeyValues(t *testing.T) { }, { name: "non-increasing keys", - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Nothing[[]byte](), kvs: []KeyValue{ {Key: []byte{0}}, @@ -1037,7 +1037,7 @@ func TestVerifyKeyValues(t *testing.T) { }, { name: "key before start", - start: []byte{1, 2}, + start: maybe.Some([]byte{1, 2}), end: maybe.Nothing[[]byte](), kvs: []KeyValue{ {Key: []byte{1}}, @@ -1047,7 +1047,7 @@ func TestVerifyKeyValues(t *testing.T) { }, { name: "key after end", - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Some([]byte{1, 2}), kvs: []KeyValue{ {Key: []byte{1}}, @@ -1058,7 +1058,7 @@ func TestVerifyKeyValues(t *testing.T) { }, { name: "happy path", - start: nil, + start: maybe.Nothing[[]byte](), end: maybe.Some([]byte{1, 2, 3}), kvs: []KeyValue{ {Key: []byte{1}}, @@ -1654,6 +1654,11 @@ func FuzzRangeProofInvariants(f *testing.F) { return } + start := maybe.Nothing[[]byte]() + if len(startBytes) != 0 { + start = maybe.Some(startBytes) + } + end := maybe.Nothing[[]byte]() if len(endBytes) != 0 { end = maybe.Some(endBytes) @@ -1661,7 +1666,7 @@ func FuzzRangeProofInvariants(f *testing.F) { rangeProof, err := db.GetRangeProof( context.Background(), - startBytes, + start, end, int(maxProofLen), ) @@ -1672,7 +1677,7 @@ func FuzzRangeProofInvariants(f *testing.F) { require.NoError(rangeProof.Verify( context.Background(), - startBytes, + start, end, rootID, )) @@ -1844,6 +1849,11 @@ func FuzzChangeProof(f *testing.F) { return } + start := maybe.Nothing[[]byte]() + if len(startBytes) != 0 { + start = maybe.Some(startBytes) + } + end := maybe.Nothing[[]byte]() if len(endBytes) != 0 { end = maybe.Some(endBytes) @@ -1853,7 +1863,7 @@ func FuzzChangeProof(f *testing.F) { context.Background(), startRootID, endRootID, - startBytes, + start, end, int(maxProofLen), ) @@ -1862,7 +1872,7 @@ func FuzzChangeProof(f *testing.F) { require.NoError(db.VerifyChangeProof( context.Background(), changeProof, - startBytes, + start, end, endRootID, )) diff --git a/x/merkledb/trie.go b/x/merkledb/trie.go index 1a3d4ac0cc94..b4b8962726c3 100644 --- a/x/merkledb/trie.go +++ b/x/merkledb/trie.go @@ -44,8 +44,11 @@ type ReadOnlyTrie interface { // get an editable copy of the node with the given key path getEditableNode(key path) (*node, error) - // GetRangeProof generates a proof of up to maxLength smallest key/values with keys between start and end - GetRangeProof(ctx context.Context, start []byte, end maybe.Maybe[[]byte], maxLength int) (*RangeProof, error) + // GetRangeProof returns a proof of up to [maxLength] key-value pairs with + // keys in range [start, end]. + // If [start] is Nothing, there's no lower bound on the range. + // If [end] is Nothing, there's no upper bound on the range. + GetRangeProof(ctx context.Context, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], maxLength int) (*RangeProof, error) database.Iteratee } diff --git a/x/merkledb/trieview.go b/x/merkledb/trieview.go index 560513871915..3f394fe198cb 100644 --- a/x/merkledb/trieview.go +++ b/x/merkledb/trieview.go @@ -376,14 +376,14 @@ func (t *trieView) getProof(ctx context.Context, key []byte) (*Proof, error) { // [maxLength] must be > 0. func (t *trieView) GetRangeProof( ctx context.Context, - start []byte, + start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], maxLength int, ) (*RangeProof, error) { ctx, span := t.db.tracer.Start(ctx, "MerkleDB.trieview.GetRangeProof") defer span.End() - if end.HasValue() && bytes.Compare(start, end.Value()) == 1 { + if start.HasValue() && end.HasValue() && bytes.Compare(start.Value(), end.Value()) == 1 { return nil, ErrStartAfterEnd } @@ -409,7 +409,7 @@ func (t *trieView) GetRangeProof( var result RangeProof result.KeyValues = make([]KeyValue, 0, initKeyValuesSize) - it := t.NewIteratorWithStart(start) + it := t.NewIteratorWithStart(start.Value()) for it.Next() && len(result.KeyValues) < maxLength && (end.IsNothing() || bytes.Compare(it.Key(), end.Value()) <= 0) { // clone the value to prevent editing of the values stored within the trie result.KeyValues = append(result.KeyValues, KeyValue{ @@ -445,8 +445,8 @@ func (t *trieView) GetRangeProof( result.EndProof = endProof.Path } - if len(start) > 0 { - startProof, err := t.getProof(ctx, start) + if start.HasValue() { + startProof, err := t.getProof(ctx, start.Value()) if err != nil { return nil, err } diff --git a/x/sync/client.go b/x/sync/client.go index a69a433bcad8..73746f143e0d 100644 --- a/x/sync/client.go +++ b/x/sync/client.go @@ -111,10 +111,8 @@ func (c *client) GetChangeProof( return nil, err } - endKey := maybe.Nothing[[]byte]() - if req.EndKey != nil && !req.EndKey.IsNothing { - endKey = maybe.Some(req.EndKey.Value) - } + startKey := maybeBytesToMaybe(req.StartKey) + endKey := maybeBytesToMaybe(req.EndKey) switch changeProofResp := changeProofResp.Response.(type) { case *pb.SyncGetChangeProofResponse_ChangeProof: @@ -141,7 +139,7 @@ func (c *client) GetChangeProof( if err := db.VerifyChangeProof( ctx, &changeProof, - req.StartKey, + startKey, endKey, endRoot, ); err != nil { @@ -158,7 +156,7 @@ func (c *client) GetChangeProof( ctx, changeProofResp.RangeProof, int(req.KeyLimit), - req.StartKey, + startKey, endKey, req.EndRootHash, ) @@ -195,7 +193,7 @@ func parseAndVerifyRangeProof( ctx context.Context, rangeProofProto *pb.RangeProof, keyLimit int, - start []byte, + start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], rootBytes []byte, ) (*merkledb.RangeProof, error) { @@ -248,16 +246,14 @@ func (c *client) GetRangeProof( return nil, err } - endKey := maybe.Nothing[[]byte]() - if req.EndKey != nil && !req.EndKey.IsNothing { - endKey = maybe.Some(req.EndKey.Value) - } + startKey := maybeBytesToMaybe(req.StartKey) + endKey := maybeBytesToMaybe(req.EndKey) return parseAndVerifyRangeProof( ctx, &rangeProofProto, int(req.KeyLimit), - req.StartKey, + startKey, endKey, req.RootHash, ) diff --git a/x/sync/client_test.go b/x/sync/client_test.go index 59de4d60cd33..b4d78f03d1d8 100644 --- a/x/sync/client_test.go +++ b/x/sync/client_test.go @@ -222,8 +222,11 @@ func TestGetRangeProof(t *testing.T) { "full response from near end of trie to end of trie (less than leaf limit)": { db: largeTrieDB, request: &pb.SyncGetRangeProofRequest{ - RootHash: largeTrieRoot[:], - StartKey: largeTrieKeys[len(largeTrieKeys)-30], // Set start 30 keys from the end of the large trie + RootHash: largeTrieRoot[:], + StartKey: &pb.MaybeBytes{ + Value: largeTrieKeys[len(largeTrieKeys)-30], // Set start 30 keys from the end of the large trie + IsNothing: false, + }, KeyLimit: defaultRequestKeyLimit, BytesLimit: defaultRequestByteSizeLimit, }, @@ -232,8 +235,11 @@ func TestGetRangeProof(t *testing.T) { "full response for intermediate range of trie (less than leaf limit)": { db: largeTrieDB, request: &pb.SyncGetRangeProofRequest{ - RootHash: largeTrieRoot[:], - StartKey: largeTrieKeys[1000], // Set the range for 1000 leafs in an intermediate range of the trie + RootHash: largeTrieRoot[:], + StartKey: &pb.MaybeBytes{ + Value: largeTrieKeys[1000], // Set the range for 1000 leafs in an intermediate range of the trie + IsNothing: false, + }, EndKey: &pb.MaybeBytes{Value: largeTrieKeys[1099]}, // (inclusive range) KeyLimit: defaultRequestKeyLimit, BytesLimit: defaultRequestByteSizeLimit, @@ -260,7 +266,7 @@ func TestGetRangeProof(t *testing.T) { BytesLimit: defaultRequestByteSizeLimit, }, modifyResponse: func(response *merkledb.RangeProof) { - start := response.KeyValues[1].Key + start := maybe.Some(response.KeyValues[1].Key) rootID, err := largeTrieDB.GetMerkleRoot(context.Background()) require.NoError(t, err) proof, err := largeTrieDB.GetRangeProofAtRoot(context.Background(), rootID, start, maybe.Nothing[[]byte](), defaultRequestKeyLimit) diff --git a/x/sync/g_db/db_client.go b/x/sync/g_db/db_client.go index d7374ecccd9d..ddde3fa67898 100644 --- a/x/sync/g_db/db_client.go +++ b/x/sync/g_db/db_client.go @@ -39,16 +39,22 @@ func (c *DBClient) GetChangeProof( ctx context.Context, startRootID ids.ID, endRootID ids.ID, - startKey []byte, + startKey maybe.Maybe[[]byte], endKey maybe.Maybe[[]byte], keyLimit int, ) (*merkledb.ChangeProof, error) { resp, err := c.client.GetChangeProof(ctx, &pb.GetChangeProofRequest{ StartRootHash: startRootID[:], EndRootHash: endRootID[:], - StartKey: startKey, - EndKey: &pb.MaybeBytes{IsNothing: endKey.IsNothing(), Value: endKey.Value()}, - KeyLimit: uint32(keyLimit), + StartKey: &pb.MaybeBytes{ + IsNothing: startKey.IsNothing(), + Value: startKey.Value(), + }, + EndKey: &pb.MaybeBytes{ + IsNothing: endKey.IsNothing(), + Value: endKey.Value(), + }, + KeyLimit: uint32(keyLimit), }) if err != nil { return nil, err @@ -69,14 +75,20 @@ func (c *DBClient) GetChangeProof( func (c *DBClient) VerifyChangeProof( ctx context.Context, proof *merkledb.ChangeProof, - startKey []byte, + startKey maybe.Maybe[[]byte], endKey maybe.Maybe[[]byte], expectedRootID ids.ID, ) error { resp, err := c.client.VerifyChangeProof(ctx, &pb.VerifyChangeProofRequest{ - Proof: proof.ToProto(), - StartKey: startKey, - EndKey: endKey.Value(), + Proof: proof.ToProto(), + StartKey: &pb.MaybeBytes{ + Value: startKey.Value(), + IsNothing: startKey.IsNothing(), + }, + EndKey: &pb.MaybeBytes{ + Value: endKey.Value(), + IsNothing: endKey.IsNothing(), + }, ExpectedRootHash: expectedRootID[:], }) if err != nil { @@ -115,14 +127,20 @@ func (c *DBClient) GetProof(ctx context.Context, key []byte) (*merkledb.Proof, e func (c *DBClient) GetRangeProofAtRoot( ctx context.Context, rootID ids.ID, - startKey []byte, + startKey maybe.Maybe[[]byte], endKey maybe.Maybe[[]byte], keyLimit int, ) (*merkledb.RangeProof, error) { resp, err := c.client.GetRangeProof(ctx, &pb.GetRangeProofRequest{ RootHash: rootID[:], - StartKey: startKey, - EndKey: &pb.MaybeBytes{IsNothing: endKey.IsNothing(), Value: endKey.Value()}, + StartKey: &pb.MaybeBytes{ + IsNothing: startKey.IsNothing(), + Value: startKey.Value(), + }, + EndKey: &pb.MaybeBytes{ + IsNothing: endKey.IsNothing(), + Value: endKey.Value(), + }, KeyLimit: uint32(keyLimit), }) if err != nil { @@ -138,11 +156,14 @@ func (c *DBClient) GetRangeProofAtRoot( func (c *DBClient) CommitRangeProof( ctx context.Context, - startKey []byte, + startKey maybe.Maybe[[]byte], proof *merkledb.RangeProof, ) error { _, err := c.client.CommitRangeProof(ctx, &pb.CommitRangeProofRequest{ - StartKey: startKey, + StartKey: &pb.MaybeBytes{ + IsNothing: startKey.IsNothing(), + Value: startKey.Value(), + }, RangeProof: proof.ToProto(), }) return err diff --git a/x/sync/g_db/db_server.go b/x/sync/g_db/db_server.go index 7d1a3ec16d13..4bfad2a685c9 100644 --- a/x/sync/g_db/db_server.go +++ b/x/sync/g_db/db_server.go @@ -54,15 +54,20 @@ func (s *DBServer) GetChangeProof( if err != nil { return nil, err } + start := maybe.Nothing[[]byte]() + if req.StartKey != nil && !req.StartKey.IsNothing { + start = maybe.Some(req.StartKey.Value) + } end := maybe.Nothing[[]byte]() if req.EndKey != nil && !req.EndKey.IsNothing { end = maybe.Some(req.EndKey.Value) } + changeProof, err := s.db.GetChangeProof( ctx, startRootID, endRootID, - req.StartKey, + start, end, int(req.KeyLimit), ) @@ -97,10 +102,18 @@ func (s *DBServer) VerifyChangeProof( if err != nil { return nil, err } + startKey := maybe.Nothing[[]byte]() + if req.StartKey != nil && !req.StartKey.IsNothing { + startKey = maybe.Some(req.StartKey.Value) + } + endKey := maybe.Nothing[[]byte]() + if req.EndKey != nil && !req.EndKey.IsNothing { + endKey = maybe.Some(req.EndKey.Value) + } // TODO there's probably a better way to do this. var errString string - if err := s.db.VerifyChangeProof(ctx, &proof, req.StartKey, maybe.Some(req.EndKey), rootID); err != nil { + if err := s.db.VerifyChangeProof(ctx, &proof, startKey, endKey, rootID); err != nil { errString = err.Error() } return &pb.VerifyChangeProofResponse{ @@ -143,11 +156,15 @@ func (s *DBServer) GetRangeProof( if err != nil { return nil, err } + start := maybe.Nothing[[]byte]() + if req.StartKey != nil && !req.StartKey.IsNothing { + start = maybe.Some(req.StartKey.Value) + } end := maybe.Nothing[[]byte]() if req.EndKey != nil && !req.EndKey.IsNothing { end = maybe.Some(req.EndKey.Value) } - proof, err := s.db.GetRangeProofAtRoot(ctx, rootID, req.StartKey, end, int(req.KeyLimit)) + proof, err := s.db.GetRangeProofAtRoot(ctx, rootID, start, end, int(req.KeyLimit)) if err != nil { return nil, err } @@ -184,6 +201,11 @@ func (s *DBServer) CommitRangeProof( return nil, err } - err := s.db.CommitRangeProof(ctx, req.StartKey, &proof) + start := maybe.Nothing[[]byte]() + if req.StartKey != nil && !req.StartKey.IsNothing { + start = maybe.Some(req.StartKey.Value) + } + + err := s.db.CommitRangeProof(ctx, start, &proof) return &emptypb.Empty{}, err } diff --git a/x/sync/manager.go b/x/sync/manager.go index c10c33869377..2c2dae06c091 100644 --- a/x/sync/manager.go +++ b/x/sync/manager.go @@ -11,6 +11,7 @@ import ( "sync" "go.uber.org/zap" + "golang.org/x/exp/slices" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/logging" @@ -50,13 +51,13 @@ const ( // [localRootID] is the ID of the root of this range in our database. // If we have no local root for this range, [localRootID] is ids.Empty. type workItem struct { - start []byte + start maybe.Maybe[[]byte] end maybe.Maybe[[]byte] priority priority localRootID ids.ID } -func newWorkItem(localRootID ids.ID, start []byte, end maybe.Maybe[[]byte], priority priority) *workItem { +func newWorkItem(localRootID ids.ID, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], priority priority) *workItem { return &workItem{ localRootID: localRootID, start: start, @@ -146,7 +147,7 @@ func (m *Manager) Start(ctx context.Context) error { // Add work item to fetch the entire key range. // Note that this will be the first work item to be processed. - m.unprocessedWork.Insert(newWorkItem(ids.Empty, nil, maybe.Nothing[[]byte](), lowPriority)) + m.unprocessedWork.Insert(newWorkItem(ids.Empty, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), lowPriority)) m.syncing = true ctx, m.cancelCtx = context.WithCancel(ctx) @@ -259,7 +260,10 @@ func (m *Manager) getAndApplyChangeProof(ctx context.Context, work *workItem) { &pb.SyncGetChangeProofRequest{ StartRootHash: work.localRootID[:], EndRootHash: targetRootID[:], - StartKey: work.start, + StartKey: &pb.MaybeBytes{ + Value: work.start.Value(), + IsNothing: work.start.IsNothing(), + }, EndKey: &pb.MaybeBytes{ Value: work.end.Value(), IsNothing: work.end.IsNothing(), @@ -320,7 +324,10 @@ func (m *Manager) getAndApplyRangeProof(ctx context.Context, work *workItem) { proof, err := m.config.Client.GetRangeProof(ctx, &pb.SyncGetRangeProofRequest{ RootHash: targetRootID[:], - StartKey: work.start, + StartKey: &pb.MaybeBytes{ + Value: work.start.Value(), + IsNothing: work.start.IsNothing(), + }, EndKey: &pb.MaybeBytes{ Value: work.end.Value(), IsNothing: work.end.IsNothing(), @@ -355,30 +362,31 @@ func (m *Manager) getAndApplyRangeProof(ctx context.Context, work *workItem) { m.completeWorkItem(ctx, work, largestHandledKey, targetRootID, proof.EndProof) } -// findNextKey returns the start of the key range that should be fetched next. -// Returns nil if there are no more keys to fetch up to [rangeEnd]. -// -// If the last proof received contained at least one key-value pair, then -// [lastReceivedKey] is the greatest key in the key-value pairs received. -// Otherwise it's the end of the range for the last proof received. +// findNextKey returns the start of the key range that should be fetched next +// given that we just received a range/change proof that proved a range of +// key-value pairs ending at [lastReceivedKey]. // // [rangeEnd] is the end of the range that we want to fetch. // +// Returns Nothing if there are no more keys to fetch in [lastReceivedKey, rangeEnd]. +// // [endProof] is the end proof of the last proof received. -// Namely it's an inclusion/exclusion proof for [lastReceivedKey]. // // Invariant: [lastReceivedKey] < [rangeEnd]. +// If [rangeEnd] is Nothing it's considered > [lastReceivedKey]. func (m *Manager) findNextKey( ctx context.Context, lastReceivedKey []byte, - rangeEnd []byte, + rangeEnd maybe.Maybe[[]byte], endProof []merkledb.ProofNode, -) ([]byte, error) { +) (maybe.Maybe[[]byte], error) { if len(endProof) == 0 { // We try to find the next key to fetch by looking at the end proof. // If the end proof is empty, we have no information to use. // Start fetching from the next key after [lastReceivedKey]. - return append(lastReceivedKey, 0), nil + nextKey := lastReceivedKey + nextKey = append(nextKey, 0) + return maybe.Some(nextKey), nil } // We want the first key larger than the [lastReceivedKey]. @@ -405,7 +413,7 @@ func (m *Manager) findNextKey( // get a proof for the same key as the received proof from the local db localProofOfKey, err := m.config.DB.GetProof(ctx, proofKeyPath.Value) if err != nil { - return nil, err + return maybe.Nothing[[]byte](), err } localProofNodes := localProofOfKey.Path @@ -415,13 +423,13 @@ func (m *Manager) findNextKey( localProofNodes = localProofNodes[:len(localProofNodes)-1] } - var nextKey []byte + nextKey := maybe.Nothing[[]byte]() localProofNodeIndex := len(localProofNodes) - 1 receivedProofNodeIndex := len(endProof) - 1 // traverse the two proofs from the deepest nodes up to the root until a difference is found - for localProofNodeIndex >= 0 && receivedProofNodeIndex >= 0 && nextKey == nil { + for localProofNodeIndex >= 0 && receivedProofNodeIndex >= 0 && nextKey.IsNothing() { localProofNode := localProofNodes[localProofNodeIndex] receivedProofNode := endProof[receivedProofNodeIndex] @@ -481,7 +489,7 @@ func (m *Manager) findNextKey( // determine if there are any differences in the children for the deepest unhandled node of the two proofs if childIndex, hasDifference := findChildDifference(deepestNode, deepestNodeFromOtherProof, startingChildNibble); hasDifference { - nextKey = deepestNode.KeyPath.AppendNibble(childIndex).Value + nextKey = maybe.Some(deepestNode.KeyPath.AppendNibble(childIndex).Value) break } } @@ -490,15 +498,15 @@ func (m *Manager) findNextKey( // then we couldn't find a better answer than the [lastReceivedKey]. // Set the nextKey to [lastReceivedKey] + 0, which is the first key in // the open range (lastReceivedKey, rangeEnd). - if nextKey != nil && bytes.Compare(nextKey, lastReceivedKey) <= 0 { - nextKey = lastReceivedKey - nextKey = append(nextKey, 0) + if nextKey.HasValue() && bytes.Compare(nextKey.Value(), lastReceivedKey) <= 0 { + nextKeyVal := slices.Clone(lastReceivedKey) + nextKeyVal = append(nextKeyVal, 0) + nextKey = maybe.Some(nextKeyVal) } - // If the nextKey is larger than the end of the range, - // return nil to signal that there is no next key in range. - if len(rangeEnd) > 0 && bytes.Compare(nextKey, rangeEnd) >= 0 { - return nil, nil + // If the [nextKey] is larger than the end of the range, return Nothing to signal that there is no next key in range + if rangeEnd.HasValue() && bytes.Compare(nextKey.Value(), rangeEnd.Value()) >= 0 { + return maybe.Nothing[[]byte](), nil } // the nextKey is within the open range (lastReceivedKey, rangeEnd), so return it @@ -599,25 +607,41 @@ func (m *Manager) setError(err error) { go m.Close() } -// Mark the range [start, end] as synced up to [rootID]. +// Mark that we've fetched all the key-value pairs in the range +// [workItem.start, largestHandledKey] for the trie with root [rootID]. +// +// If [workItem.start] is Nothing, then we've fetched all the key-value +// pairs up to and including [largestHandledKey]. +// +// If [largestHandledKey] is Nothing, then we've fetched all the key-value +// pairs at and after [workItem.start]. +// +// [proofOfLargestKey] is the end proof for the range/change proof +// that gave us the range up to and including [largestHandledKey]. +// // Assumes [m.workLock] is not held. func (m *Manager) completeWorkItem(ctx context.Context, work *workItem, largestHandledKey maybe.Maybe[[]byte], rootID ids.ID, proofOfLargestKey []merkledb.ProofNode) { - // if the last key is equal to the end, then the full range is completed if !maybe.Equal(largestHandledKey, work.end, bytes.Equal) { - // find the next key to start querying by comparing the proofs for the last completed key - nextStartKey, err := m.findNextKey(ctx, largestHandledKey.Value(), work.end.Value(), proofOfLargestKey) + // The largest handled key isn't equal to the end of the work item. + // Find the start of the next key range to fetch. + // Note that [largestHandledKey] can't be Nothing. + // Proof: Suppose it is. That means that we got a range/change proof that proved up to the + // greatest key-value pair in the database. That means we requested a proof with no upper + // bound. That is, [workItem.end] is Nothing. Since we're here, [bothNothing] is false, + // which means [workItem.end] isn't Nothing. Contradiction. + nextStartKey, err := m.findNextKey(ctx, largestHandledKey.Value(), work.end, proofOfLargestKey) if err != nil { m.setError(err) return } - // nextStartKey being nil indicates that the entire range has been completed - if nextStartKey == nil { + // nextStartKey being Nothing indicates that the entire range has been completed + if nextStartKey.IsNothing() { largestHandledKey = work.end } else { // the full range wasn't completed, so enqueue a new work item for the range [nextStartKey, workItem.end] m.enqueueWork(newWorkItem(work.localRootID, nextStartKey, work.end, work.priority)) - largestHandledKey = maybe.Some(nextStartKey) + largestHandledKey = nextStartKey } } @@ -639,8 +663,8 @@ func (m *Manager) completeWorkItem(ctx context.Context, work *workItem, largestH // completed the range [work.start, lastKey], log and record in the completed work heap m.config.Log.Info("completed range", - zap.Binary("start", work.start), - zap.Binary("end", largestHandledKey.Value()), + zap.Stringer("start", work.start), + zap.Stringer("end", largestHandledKey), zap.Stringer("rootID", rootID), zap.Bool("stale", stale), ) @@ -667,7 +691,7 @@ func (m *Manager) enqueueWork(work *workItem) { // Find the middle point. mid := midPoint(work.start, work.end) - if bytes.Equal(work.start, mid) || bytes.Equal(mid, work.end.Value()) { + if maybe.Equal(work.start, mid, bytes.Equal) || maybe.Equal(mid, work.end, bytes.Equal) { // The range is too small to split. // If we didn't have this check we would add work items // [start, start] and [start, end]. Since start <= end, this would @@ -679,7 +703,7 @@ func (m *Manager) enqueueWork(work *workItem) { // first item gets higher priority than the second to encourage finished ranges to grow // rather than start a new range that is not contiguous with existing completed ranges - first := newWorkItem(work.localRootID, work.start, maybe.Some(mid), medPriority) + first := newWorkItem(work.localRootID, work.start, mid, medPriority) second := newWorkItem(work.localRootID, mid, work.end, lowPriority) m.unprocessedWork.Insert(first) @@ -688,26 +712,28 @@ func (m *Manager) enqueueWork(work *workItem) { // find the midpoint between two keys // start is expected to be less than end -// nil on start or end is treated as all 0's -// nothing on end is treated as all 255's -func midPoint(start []byte, end maybe.Maybe[[]byte]) []byte { +// Nothing/nil [start] is treated as all 0's +// Nothing/nil [end] is treated as all 255's +func midPoint(startMaybe, endMaybe maybe.Maybe[[]byte]) maybe.Maybe[[]byte] { + start := startMaybe.Value() + end := endMaybe.Value() length := len(start) - if len(end.Value()) > length { - length = len(end.Value()) + if len(end) > length { + length = len(end) } if length == 0 { - if end.IsNothing() { - return []byte{127} - } else if len(end.Value()) == 0 { - return nil + if endMaybe.IsNothing() { + return maybe.Some([]byte{127}) + } else if len(end) == 0 { + return maybe.Nothing[[]byte]() } } // This check deals with cases where the end has a 255(or is nothing which is treated as all 255s) and the start key ends 255. // For example, midPoint([255], nothing) should be [255, 127], not [255]. // The result needs the extra byte added on to the end to deal with the fact that the naive midpoint between 255 and 255 would be 255 - if (len(start) > 0 && start[len(start)-1] == 255) && (len(end.Value()) == 0 || end.Value()[len(end.Value())-1] == 255) { + if (len(start) > 0 && start[len(start)-1] == 255) && (len(end) == 0 || end[len(end)-1] == 255) { length++ } @@ -720,11 +746,11 @@ func midPoint(start []byte, end maybe.Maybe[[]byte]) []byte { } endVal := 0 - if end.IsNothing() { + if endMaybe.IsNothing() { endVal = 255 } - if i < len(end.Value()) { - endVal = int(end.Value()[i]) + if i < len(end) { + endVal = int(end[i]) } total := startVal + endVal + leftover @@ -755,7 +781,7 @@ func midPoint(start []byte, end maybe.Maybe[[]byte]) []byte { } else { midpoint = midpoint[0:length] } - return midpoint + return maybe.Some(midpoint) } // findChildDifference returns the first child index that is different between node 1 and node 2 if one exists and diff --git a/x/sync/network_server.go b/x/sync/network_server.go index db0b972f1cb8..9c505b98f70e 100644 --- a/x/sync/network_server.go +++ b/x/sync/network_server.go @@ -19,6 +19,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/engine/common" "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/math" "github.com/ava-labs/avalanchego/utils/maybe" @@ -41,7 +42,18 @@ const ( endProofSizeBufferAmount = 2 * units.KiB ) -var ErrMinProofSizeIsTooLarge = errors.New("cannot generate any proof within the requested limit") +var ( + ErrMinProofSizeIsTooLarge = errors.New("cannot generate any proof within the requested limit") + + errInvalidBytesLimit = errors.New("bytes limit must be greater than 0") + errInvalidKeyLimit = errors.New("key limit must be greater than 0") + errInvalidStartRootHash = fmt.Errorf("start root hash must have length %d", hashing.HashLen) + errInvalidEndRootHash = fmt.Errorf("end root hash must have length %d", hashing.HashLen) + errInvalidStartKey = errors.New("start key is Nothing but has value") + errInvalidEndKey = errors.New("end key is Nothing but has value") + errInvalidBounds = errors.New("start key is greater than end key") + errInvalidRootHash = fmt.Errorf("root hash must have length %d", hashing.HashLen) +) type NetworkServer struct { appSender common.AppSender // Used to respond to peer requests via AppResponse. @@ -154,19 +166,13 @@ func (s *NetworkServer) HandleChangeProofRequest( requestID uint32, req *pb.SyncGetChangeProofRequest, ) error { - if req.EndKey == nil { - req.EndKey = &pb.MaybeBytes{IsNothing: true} - } - if req.BytesLimit == 0 || - req.KeyLimit == 0 || - len(req.StartRootHash) != ids.IDLen || - len(req.EndRootHash) != ids.IDLen || - (!req.EndKey.IsNothing && bytes.Compare(req.StartKey, req.EndKey.Value) > 0) { + if err := validateChangeProofRequest(req); err != nil { s.log.Debug( "dropping invalid change proof request", zap.Stringer("nodeID", nodeID), zap.Uint32("requestID", requestID), zap.Stringer("req", req), + zap.Error(err), ) return nil // dropping request } @@ -175,6 +181,7 @@ func (s *NetworkServer) HandleChangeProofRequest( var ( keyLimit = math.Min(req.KeyLimit, maxKeyValuesLimit) bytesLimit = math.Min(int(req.BytesLimit), maxByteSizeLimit) + start = maybeBytesToMaybe(req.StartKey) end = maybeBytesToMaybe(req.EndKey) ) @@ -189,7 +196,7 @@ func (s *NetworkServer) HandleChangeProofRequest( } for keyLimit > 0 { - changeProof, err := s.db.GetChangeProof(ctx, startRoot, endRoot, req.StartKey, end, int(keyLimit)) + changeProof, err := s.db.GetChangeProof(ctx, startRoot, endRoot, start, end, int(keyLimit)) if err != nil { if !errors.Is(err, merkledb.ErrInsufficientHistory) { return err @@ -270,20 +277,15 @@ func (s *NetworkServer) HandleRangeProofRequest( requestID uint32, req *pb.SyncGetRangeProofRequest, ) error { - if req.EndKey == nil { - req.EndKey = &pb.MaybeBytes{IsNothing: true} - } - if req.BytesLimit == 0 || - req.KeyLimit == 0 || - len(req.RootHash) != ids.IDLen || - (!req.EndKey.IsNothing && bytes.Compare(req.StartKey, req.EndKey.Value) > 0) { + if err := validateRangeProofRequest(req); err != nil { s.log.Debug( "dropping invalid range proof request", zap.Stringer("nodeID", nodeID), zap.Uint32("requestID", requestID), zap.Stringer("req", req), + zap.Error(err), ) - return nil // dropping request + return nil // drop request } // override limits if they exceed caps @@ -339,7 +341,7 @@ func getRangeProof( rangeProof, err := db.GetRangeProofAtRoot( ctx, root, - req.StartKey, + maybeBytesToMaybe(req.StartKey), maybeBytesToMaybe(req.EndKey), keyLimit, ) @@ -377,3 +379,47 @@ func isTimeout(err error) bool { // otherwise, check for context.DeadlineExceeded directly return errors.Is(err, context.DeadlineExceeded) } + +// Returns nil iff [req] is well-formed. +func validateChangeProofRequest(req *pb.SyncGetChangeProofRequest) error { + switch { + case req.BytesLimit == 0: + return errInvalidBytesLimit + case req.KeyLimit == 0: + return errInvalidKeyLimit + case len(req.StartRootHash) != hashing.HashLen: + return errInvalidStartRootHash + case len(req.EndRootHash) != hashing.HashLen: + return errInvalidEndRootHash + case req.StartKey != nil && req.StartKey.IsNothing && len(req.StartKey.Value) > 0: + return errInvalidStartKey + case req.EndKey != nil && req.EndKey.IsNothing && len(req.EndKey.Value) > 0: + return errInvalidEndKey + case req.StartKey != nil && req.EndKey != nil && !req.StartKey.IsNothing && + !req.EndKey.IsNothing && bytes.Compare(req.StartKey.Value, req.EndKey.Value) > 0: + return errInvalidBounds + default: + return nil + } +} + +// Returns nil iff [req] is well-formed. +func validateRangeProofRequest(req *pb.SyncGetRangeProofRequest) error { + switch { + case req.BytesLimit == 0: + return errInvalidBytesLimit + case req.KeyLimit == 0: + return errInvalidKeyLimit + case len(req.RootHash) != ids.IDLen: + return errInvalidRootHash + case req.StartKey != nil && req.StartKey.IsNothing && len(req.StartKey.Value) > 0: + return errInvalidStartKey + case req.EndKey != nil && req.EndKey.IsNothing && len(req.EndKey.Value) > 0: + return errInvalidEndKey + case req.StartKey != nil && req.EndKey != nil && !req.StartKey.IsNothing && + !req.EndKey.IsNothing && bytes.Compare(req.StartKey.Value, req.EndKey.Value) > 0: + return errInvalidBounds + default: + return nil + } +} diff --git a/x/sync/network_server_test.go b/x/sync/network_server_test.go index d3b9d1886d64..abc62d97d977 100644 --- a/x/sync/network_server_test.go +++ b/x/sync/network_server_test.go @@ -72,7 +72,7 @@ func Test_Server_GetRangeProof(t *testing.T) { RootHash: smallTrieRoot[:], KeyLimit: defaultRequestKeyLimit, BytesLimit: defaultRequestByteSizeLimit, - StartKey: []byte{1}, + StartKey: &pb.MaybeBytes{Value: []byte{1}}, EndKey: &pb.MaybeBytes{Value: []byte{0}}, }, proofNil: true, @@ -222,7 +222,7 @@ func Test_Server_GetChangeProof(t *testing.T) { EndRootHash: endRoot[:], KeyLimit: defaultRequestKeyLimit, BytesLimit: defaultRequestByteSizeLimit, - StartKey: []byte{1}, + StartKey: &pb.MaybeBytes{Value: []byte{1}}, EndKey: &pb.MaybeBytes{Value: []byte{0}}, }, proofNil: true, @@ -359,7 +359,7 @@ func TestAppRequestErrAppSendFailed(t *testing.T) { ChangeProofRequest: &pb.SyncGetChangeProofRequest{ StartRootHash: startRootID[:], EndRootHash: endRootID[:], - StartKey: []byte{1}, + StartKey: &pb.MaybeBytes{Value: []byte{1}}, EndKey: &pb.MaybeBytes{Value: []byte{2}}, KeyLimit: 100, BytesLimit: 100, @@ -395,7 +395,7 @@ func TestAppRequestErrAppSendFailed(t *testing.T) { Message: &pb.Request_RangeProofRequest{ RangeProofRequest: &pb.SyncGetRangeProofRequest{ RootHash: endRootID[:], - StartKey: []byte{1}, + StartKey: &pb.MaybeBytes{Value: []byte{1}}, EndKey: &pb.MaybeBytes{Value: []byte{2}}, KeyLimit: 100, BytesLimit: 100, diff --git a/x/sync/sync_test.go b/x/sync/sync_test.go index f162c4750872..e03ef1bc959b 100644 --- a/x/sync/sync_test.go +++ b/x/sync/sync_test.go @@ -38,7 +38,7 @@ func newCallthroughSyncClient(ctrl *gomock.Controller, db merkledb.MerkleDB) *Mo func(_ context.Context, request *pb.SyncGetRangeProofRequest) (*merkledb.RangeProof, error) { return db.GetRangeProof( context.Background(), - request.StartKey, + maybeBytesToMaybe(request.StartKey), maybeBytesToMaybe(request.EndKey), int(request.KeyLimit), ) @@ -59,7 +59,7 @@ func newCallthroughSyncClient(ctrl *gomock.Controller, db merkledb.MerkleDB) *Mo context.Background(), startRoot, endRoot, - request.StartKey, + maybeBytesToMaybe(request.StartKey), maybeBytesToMaybe(request.EndKey), int(request.KeyLimit), ) @@ -137,47 +137,41 @@ func Test_Completion(t *testing.T) { func Test_Midpoint(t *testing.T) { require := require.New(t) - mid := midPoint(nil, maybe.Some[[]byte](nil)) - require.Nil(mid) + mid := midPoint(maybe.Some([]byte{1, 255}), maybe.Some([]byte{2, 1})) + require.Equal(maybe.Some([]byte{2, 0}), mid) - mid = midPoint([]byte{1, 255}, maybe.Some([]byte{2, 1})) - require.Equal([]byte{2, 0}, mid) + mid = midPoint(maybe.Nothing[[]byte](), maybe.Some([]byte{255, 255, 0})) + require.Equal(maybe.Some([]byte{127, 255, 128}), mid) - mid = midPoint([]byte{1, 255}, maybe.Some([]byte{2, 1})) - require.Equal([]byte{2, 0}, mid) + mid = midPoint(maybe.Some([]byte{255, 255, 255}), maybe.Some([]byte{255, 255})) + require.Equal(maybe.Some([]byte{255, 255, 127, 128}), mid) - mid = midPoint(nil, maybe.Some([]byte{255, 255, 0})) - require.Equal([]byte{127, 255, 128}, mid) + mid = midPoint(maybe.Nothing[[]byte](), maybe.Some([]byte{255})) + require.Equal(maybe.Some([]byte{127, 127}), mid) - mid = midPoint([]byte{255, 255}, maybe.Some([]byte{255, 255, 255})) - require.Equal([]byte{255, 255, 127, 128}, mid) + mid = midPoint(maybe.Some([]byte{1, 255}), maybe.Some([]byte{255, 1})) + require.Equal(maybe.Some([]byte{128, 128}), mid) - mid = midPoint(nil, maybe.Some([]byte{255})) - require.Equal([]byte{127, 127}, mid) + mid = midPoint(maybe.Some([]byte{140, 255}), maybe.Some([]byte{141, 0})) + require.Equal(maybe.Some([]byte{140, 255, 127}), mid) - mid = midPoint([]byte{1, 255}, maybe.Some([]byte{255, 1})) - require.Equal([]byte{128, 128}, mid) + mid = midPoint(maybe.Some([]byte{126, 255}), maybe.Some([]byte{127})) + require.Equal(maybe.Some([]byte{126, 255, 127}), mid) - mid = midPoint([]byte{140, 255}, maybe.Some([]byte{141, 0})) - require.Equal([]byte{140, 255, 127}, mid) + mid = midPoint(maybe.Nothing[[]byte](), maybe.Nothing[[]byte]()) + require.Equal(maybe.Some([]byte{127}), mid) - mid = midPoint([]byte{126, 255}, maybe.Some([]byte{127})) - require.Equal([]byte{126, 255, 127}, mid) - - mid = midPoint(nil, maybe.Nothing[[]byte]()) - require.Equal([]byte{127}, mid) - - low := midPoint(nil, maybe.Some(mid)) - require.Equal([]byte{63, 127}, low) + low := midPoint(maybe.Nothing[[]byte](), mid) + require.Equal(maybe.Some([]byte{63, 127}), low) high := midPoint(mid, maybe.Nothing[[]byte]()) - require.Equal([]byte{191}, high) + require.Equal(maybe.Some([]byte{191}), high) - mid = midPoint([]byte{255, 255}, maybe.Nothing[[]byte]()) - require.Equal([]byte{255, 255, 127, 127}, mid) + mid = midPoint(maybe.Some([]byte{255, 255}), maybe.Nothing[[]byte]()) + require.Equal(maybe.Some([]byte{255, 255, 127, 127}), mid) - mid = midPoint([]byte{255}, maybe.Nothing[[]byte]()) - require.Equal([]byte{255, 127, 127}, mid) + mid = midPoint(maybe.Some([]byte{255}), maybe.Nothing[[]byte]()) + require.Equal(maybe.Some([]byte{255, 127, 127}), mid) for i := 0; i < 5000; i++ { r := rand.New(rand.NewSource(int64(i))) // #nosec G404 @@ -199,9 +193,9 @@ func Test_Midpoint(t *testing.T) { start, end = end, start } - mid = midPoint(start, maybe.Some(end)) - require.Equal(-1, bytes.Compare(start, mid)) - require.Equal(-1, bytes.Compare(mid, end)) + mid = midPoint(maybe.Some(start), maybe.Some(end)) + require.Equal(-1, bytes.Compare(start, mid.Value())) + require.Equal(-1, bytes.Compare(mid.Value(), end)) } } @@ -239,27 +233,28 @@ func Test_Sync_FindNextKey_InSync(t *testing.T) { require.NoError(syncer.Start(context.Background())) require.NoError(syncer.Wait(context.Background())) - proof, err := dbToSync.GetRangeProof(context.Background(), nil, maybe.Nothing[[]byte](), 500) + proof, err := dbToSync.GetRangeProof(context.Background(), maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 500) require.NoError(err) // the two dbs should be in sync, so next key should be nil lastKey := proof.KeyValues[len(proof.KeyValues)-1].Key - nextKey, err := syncer.findNextKey(context.Background(), lastKey, nil, proof.EndProof) + nextKey, err := syncer.findNextKey(context.Background(), lastKey, maybe.Nothing[[]byte](), proof.EndProof) require.NoError(err) - require.Nil(nextKey) + require.True(nextKey.IsNothing()) // add an extra value to sync db past the last key returned - newKey := midPoint(lastKey, maybe.Nothing[[]byte]()) - require.NoError(db.Put(newKey, []byte{1})) + newKey := midPoint(maybe.Some(lastKey), maybe.Nothing[[]byte]()) + newKeyVal := newKey.Value() + require.NoError(db.Put(newKeyVal, []byte{1})) // create a range endpoint that is before the newly added key, but after the last key endPointBeforeNewKey := make([]byte, 0, 2) - for i := 0; i < len(newKey); i++ { - endPointBeforeNewKey = append(endPointBeforeNewKey, newKey[i]) + for i := 0; i < len(newKeyVal); i++ { + endPointBeforeNewKey = append(endPointBeforeNewKey, newKeyVal[i]) // we need the new key to be after the last key // don't subtract anything from the current byte if newkey and lastkey are equal - if lastKey[i] == newKey[i] { + if lastKey[i] == newKeyVal[i] { continue } @@ -276,11 +271,11 @@ func Test_Sync_FindNextKey_InSync(t *testing.T) { // both nibbles were 0, so move onto the next byte } - nextKey, err = syncer.findNextKey(context.Background(), lastKey, endPointBeforeNewKey, proof.EndProof) + nextKey, err = syncer.findNextKey(context.Background(), lastKey, maybe.Some(endPointBeforeNewKey), proof.EndProof) require.NoError(err) - // next key would be after the end of the range, so it returns nil instead - require.Nil(nextKey) + // next key would be after the end of the range, so it returns Nothing instead + require.True(nextKey.IsNothing()) } } @@ -321,13 +316,13 @@ func Test_Sync_FindNextKey_Deleted(t *testing.T) { // there is now another value in the range that needs to be sync'ed require.NoError(db.Put([]byte{0x13}, []byte{3})) - nextKey, err := syncer.findNextKey(context.Background(), []byte{0x12}, []byte{0x20}, noExtraNodeProof.Path) + nextKey, err := syncer.findNextKey(context.Background(), []byte{0x12}, maybe.Some([]byte{0x20}), noExtraNodeProof.Path) require.NoError(err) - require.Equal([]byte{0x13}, nextKey) + require.Equal(maybe.Some([]byte{0x13}), nextKey) - nextKey, err = syncer.findNextKey(context.Background(), []byte{0x11}, []byte{0x20}, extraNodeProof.Path) + nextKey, err = syncer.findNextKey(context.Background(), []byte{0x11}, maybe.Some([]byte{0x20}), extraNodeProof.Path) require.NoError(err) - require.Equal([]byte{0x13}, nextKey) + require.Equal(maybe.Some([]byte{0x13}), nextKey) } func Test_Sync_FindNextKey_BranchInLocal(t *testing.T) { @@ -358,9 +353,9 @@ func Test_Sync_FindNextKey_BranchInLocal(t *testing.T) { require.NoError(err) require.NoError(db.Put([]byte{0x12}, []byte{4})) - nextKey, err := syncer.findNextKey(context.Background(), []byte{0x11, 0x11}, []byte{0x20}, proof.Path) + nextKey, err := syncer.findNextKey(context.Background(), []byte{0x11, 0x11}, maybe.Some([]byte{0x20}), proof.Path) require.NoError(err) - require.Equal([]byte{0x12}, nextKey) + require.Equal(maybe.Some([]byte{0x12}), nextKey) } func Test_Sync_FindNextKey_BranchInReceived(t *testing.T) { @@ -392,9 +387,9 @@ func Test_Sync_FindNextKey_BranchInReceived(t *testing.T) { require.NoError(err) require.NoError(db.Delete([]byte{0x12})) - nextKey, err := syncer.findNextKey(context.Background(), []byte{0x11, 0x11}, []byte{0x20}, proof.Path) + nextKey, err := syncer.findNextKey(context.Background(), []byte{0x11, 0x11}, maybe.Some([]byte{0x20}), proof.Path) require.NoError(err) - require.Equal([]byte{0x12}, nextKey) + require.Equal(maybe.Some([]byte{0x12}), nextKey) } func Test_Sync_FindNextKey_ExtraValues(t *testing.T) { @@ -430,36 +425,37 @@ func Test_Sync_FindNextKey_ExtraValues(t *testing.T) { require.NoError(syncer.Start(context.Background())) require.NoError(syncer.Wait(context.Background())) - proof, err := dbToSync.GetRangeProof(context.Background(), nil, maybe.Nothing[[]byte](), 500) + proof, err := dbToSync.GetRangeProof(context.Background(), maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 500) require.NoError(err) // add an extra value to local db lastKey := proof.KeyValues[len(proof.KeyValues)-1].Key - midpoint := midPoint(lastKey, maybe.Nothing[[]byte]()) + midpoint := midPoint(maybe.Some(lastKey), maybe.Nothing[[]byte]()) + midPointVal := midpoint.Value() - require.NoError(db.Put(midpoint, []byte{1})) + require.NoError(db.Put(midPointVal, []byte{1})) // next key at prefix of newly added point - nextKey, err := syncer.findNextKey(context.Background(), lastKey, nil, proof.EndProof) + nextKey, err := syncer.findNextKey(context.Background(), lastKey, maybe.Nothing[[]byte](), proof.EndProof) require.NoError(err) require.NotNil(nextKey) - require.True(isPrefix(midpoint, nextKey)) + require.True(isPrefix(midPointVal, nextKey.Value())) - require.NoError(db.Delete(midpoint)) + require.NoError(db.Delete(midPointVal)) - require.NoError(dbToSync.Put(midpoint, []byte{1})) + require.NoError(dbToSync.Put(midPointVal, []byte{1})) - proof, err = dbToSync.GetRangeProof(context.Background(), nil, maybe.Some(lastKey), 500) + proof, err = dbToSync.GetRangeProof(context.Background(), maybe.Nothing[[]byte](), maybe.Some(lastKey), 500) require.NoError(err) // next key at prefix of newly added point - nextKey, err = syncer.findNextKey(context.Background(), lastKey, nil, proof.EndProof) + nextKey, err = syncer.findNextKey(context.Background(), lastKey, maybe.Nothing[[]byte](), proof.EndProof) require.NoError(err) require.NotNil(nextKey) // deal with odd length key - require.True(isPrefix(midpoint, nextKey)) + require.True(isPrefix(midPointVal, nextKey.Value())) } } @@ -494,8 +490,13 @@ func TestFindNextKeyEmptyEndProof(t *testing.T) { _, _ = r.Read(lastReceivedKey) // #nosec G404 rangeEndLen := r.Intn(16) - rangeEnd := make([]byte, rangeEndLen) - _, _ = r.Read(rangeEnd) // #nosec G404 + rangeEndBytes := make([]byte, rangeEndLen) + _, _ = r.Read(rangeEndBytes) // #nosec G404 + + rangeEnd := maybe.Nothing[[]byte]() + if rangeEndLen > 0 { + rangeEnd = maybe.Some(rangeEndBytes) + } nextKey, err := syncer.findNextKey( context.Background(), @@ -504,7 +505,7 @@ func TestFindNextKeyEmptyEndProof(t *testing.T) { nil, /* endProof */ ) require.NoError(err) - require.Equal(append(lastReceivedKey, 0), nextKey) + require.Equal(maybe.Some(append(lastReceivedKey, 0)), nextKey) } } @@ -553,7 +554,7 @@ func Test_Sync_FindNextKey_DifferentChild(t *testing.T) { require.NoError(syncer.Start(context.Background())) require.NoError(syncer.Wait(context.Background())) - proof, err := dbToSync.GetRangeProof(context.Background(), nil, maybe.Nothing[[]byte](), 100) + proof, err := dbToSync.GetRangeProof(context.Background(), maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 100) require.NoError(err) lastKey := proof.KeyValues[len(proof.KeyValues)-1].Key @@ -563,12 +564,12 @@ func Test_Sync_FindNextKey_DifferentChild(t *testing.T) { require.NoError(dbToSync.Put(lastKey, []byte{2})) - proof, err = dbToSync.GetRangeProof(context.Background(), nil, maybe.Some(proof.KeyValues[len(proof.KeyValues)-1].Key), 100) + proof, err = dbToSync.GetRangeProof(context.Background(), maybe.Nothing[[]byte](), maybe.Some(proof.KeyValues[len(proof.KeyValues)-1].Key), 100) require.NoError(err) - nextKey, err := syncer.findNextKey(context.Background(), proof.KeyValues[len(proof.KeyValues)-1].Key, nil, proof.EndProof) + nextKey, err := syncer.findNextKey(context.Background(), proof.KeyValues[len(proof.KeyValues)-1].Key, maybe.Nothing[[]byte](), proof.EndProof) require.NoError(err) - require.Equal(nextKey, lastKey) + require.Equal(nextKey.Value(), lastKey) } } @@ -634,10 +635,19 @@ func TestFindNextKeyRandom(t *testing.T) { _, _ = rand.Read(rangeEnd) } + startKey := maybe.Nothing[[]byte]() + if len(rangeStart) > 0 { + startKey = maybe.Some(rangeStart) + } + endKey := maybe.Nothing[[]byte]() + if len(rangeEnd) > 0 { + endKey = maybe.Some(rangeEnd) + } + remoteProof, err := remoteDB.GetRangeProof( context.Background(), - rangeStart, - maybe.Some(rangeEnd), + startKey, + endKey, rand.Intn(maxProofLen)+1, ) require.NoError(err) @@ -651,7 +661,7 @@ func TestFindNextKeyRandom(t *testing.T) { // in the actual syncer. require.NoError(localDB.CommitRangeProof( context.Background(), - rangeStart, + startKey, remoteProof, )) @@ -766,7 +776,7 @@ func TestFindNextKeyRandom(t *testing.T) { gotFirstDiff, err := syncer.findNextKey( context.Background(), lastReceivedKey, - rangeEnd, + endKey, remoteProof.EndProof, ) require.NoError(err) @@ -774,9 +784,9 @@ func TestFindNextKeyRandom(t *testing.T) { if bytes.Compare(smallestDiffKey.Value, rangeEnd) >= 0 { // The smallest key which differs is after the range end so the // next key to get should be nil because we're done fetching the range. - require.Nil(gotFirstDiff) + require.True(gotFirstDiff.IsNothing()) } else { - require.Equal(smallestDiffKey.Value, gotFirstDiff) + require.Equal(smallestDiffKey.Value, gotFirstDiff.Value()) } } } @@ -940,7 +950,7 @@ func Test_Sync_Error_During_Sync(t *testing.T) { endRoot, err := ids.ToID(request.EndRootHash) require.NoError(err) - changeProof, err := dbToSync.GetChangeProof(ctx, startRoot, endRoot, request.StartKey, maybeBytesToMaybe(request.EndKey), int(request.KeyLimit)) + changeProof, err := dbToSync.GetChangeProof(ctx, startRoot, endRoot, maybeBytesToMaybe(request.StartKey), maybeBytesToMaybe(request.EndKey), int(request.KeyLimit)) if err != nil { return nil, err } @@ -1025,7 +1035,7 @@ func Test_Sync_Result_Correct_Root_Update_Root_During(t *testing.T) { <-updatedRootChan root, err := ids.ToID(request.RootHash) require.NoError(err) - return dbToSync.GetRangeProofAtRoot(ctx, root, request.StartKey, maybeBytesToMaybe(request.EndKey), int(request.KeyLimit)) + return dbToSync.GetRangeProofAtRoot(ctx, root, maybeBytesToMaybe(request.StartKey), maybeBytesToMaybe(request.EndKey), int(request.KeyLimit)) }, ).AnyTimes() client.EXPECT().GetChangeProof(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( @@ -1038,7 +1048,7 @@ func Test_Sync_Result_Correct_Root_Update_Root_During(t *testing.T) { endRoot, err := ids.ToID(request.EndRootHash) require.NoError(err) - changeProof, err := dbToSync.GetChangeProof(ctx, startRoot, endRoot, request.StartKey, maybeBytesToMaybe(request.EndKey), int(request.KeyLimit)) + changeProof, err := dbToSync.GetChangeProof(ctx, startRoot, endRoot, maybeBytesToMaybe(request.StartKey), maybeBytesToMaybe(request.EndKey), int(request.KeyLimit)) if err != nil { return nil, err } @@ -1101,7 +1111,7 @@ func Test_Sync_UpdateSyncTarget(t *testing.T) { // Populate [m.processWork] to ensure that UpdateSyncTarget // moves the work to [m.unprocessedWork]. item := &workItem{ - start: []byte{1}, + start: maybe.Some([]byte{1}), end: maybe.Some([]byte{2}), localRootID: ids.GenerateTestID(), } diff --git a/x/sync/workheap.go b/x/sync/workheap.go index 45065286b5a0..36b27e229296 100644 --- a/x/sync/workheap.go +++ b/x/sync/workheap.go @@ -8,6 +8,7 @@ import ( "container/heap" "github.com/ava-labs/avalanchego/utils/math" + "github.com/ava-labs/avalanchego/utils/maybe" "github.com/google/btree" ) @@ -30,7 +31,7 @@ type workHeap struct { // i.e. heap.Pop returns highest priority item. innerHeap innerHeap // The heap items sorted by range start. - // A nil start is considered to be the smallest. + // A Nothing start is considered to be the smallest. sortedItems *btree.BTreeG[*heapItem] closed bool } @@ -40,7 +41,19 @@ func newWorkHeap() *workHeap { sortedItems: btree.NewG( 2, func(a, b *heapItem) bool { - return bytes.Compare(a.workItem.start, b.workItem.start) < 0 + aNothing := a.workItem.start.IsNothing() + bNothing := b.workItem.start.IsNothing() + if aNothing { + // [a] is Nothing, so if [b] is Nothing, they're equal. + // Otherwise, [b] is greater. + return !bNothing + } + if bNothing { + // [a] has a value and [b] doesn't so [a] is greater. + return false + } + // [a] and [b] both contain values. Compare the values. + return bytes.Compare(a.workItem.start.Value(), b.workItem.start.Value()) < 0 }, ), } @@ -98,7 +111,8 @@ func (wh *workHeap) MergeInsert(item *workItem) { wh.sortedItems.DescendLessOrEqual( searchItem, func(beforeItem *heapItem) bool { - if item.localRootID == beforeItem.workItem.localRootID && bytes.Equal(beforeItem.workItem.end.Value(), item.start) { + if item.localRootID == beforeItem.workItem.localRootID && + maybe.Equal(item.start, beforeItem.workItem.end, bytes.Equal) { // [beforeItem.start, beforeItem.end] and [item.start, item.end] are // merged into [beforeItem.start, item.end] beforeItem.workItem.end = item.end @@ -114,7 +128,8 @@ func (wh *workHeap) MergeInsert(item *workItem) { wh.sortedItems.AscendGreaterOrEqual( searchItem, func(afterItem *heapItem) bool { - if item.localRootID == afterItem.workItem.localRootID && bytes.Equal(afterItem.workItem.start, item.end.Value()) { + if item.localRootID == afterItem.workItem.localRootID && + maybe.Equal(item.end, afterItem.workItem.start, bytes.Equal) { // [item.start, item.end] and [afterItem.start, afterItem.end] are merged into // [item.start, afterItem.end]. afterItem.workItem.start = item.start diff --git a/x/sync/workheap_test.go b/x/sync/workheap_test.go index 83b326170f40..0e48f66be26e 100644 --- a/x/sync/workheap_test.go +++ b/x/sync/workheap_test.go @@ -19,7 +19,7 @@ func Test_WorkHeap_InnerHeap(t *testing.T) { lowPriorityItem := &heapItem{ workItem: &workItem{ - start: []byte{1}, + start: maybe.Some([]byte{1}), end: maybe.Some([]byte{2}), priority: lowPriority, localRootID: ids.GenerateTestID(), @@ -28,7 +28,7 @@ func Test_WorkHeap_InnerHeap(t *testing.T) { mediumPriorityItem := &heapItem{ workItem: &workItem{ - start: []byte{3}, + start: maybe.Some([]byte{3}), end: maybe.Some([]byte{4}), priority: medPriority, localRootID: ids.GenerateTestID(), @@ -37,7 +37,7 @@ func Test_WorkHeap_InnerHeap(t *testing.T) { highPriorityItem := &heapItem{ workItem: &workItem{ - start: []byte{5}, + start: maybe.Some([]byte{5}), end: maybe.Some([]byte{6}), priority: highPriority, localRootID: ids.GenerateTestID(), @@ -115,19 +115,19 @@ func Test_WorkHeap_Insert_GetWork(t *testing.T) { h := newWorkHeap() lowPriorityItem := &workItem{ - start: []byte{4}, + start: maybe.Some([]byte{4}), end: maybe.Some([]byte{5}), priority: lowPriority, localRootID: ids.GenerateTestID(), } mediumPriorityItem := &workItem{ - start: []byte{0}, + start: maybe.Some([]byte{0}), end: maybe.Some([]byte{1}), priority: medPriority, localRootID: ids.GenerateTestID(), } highPriorityItem := &workItem{ - start: []byte{2}, + start: maybe.Some([]byte{2}), end: maybe.Some([]byte{3}), priority: highPriority, localRootID: ids.GenerateTestID(), @@ -169,21 +169,21 @@ func Test_WorkHeap_remove(t *testing.T) { h := newWorkHeap() lowPriorityItem := &workItem{ - start: []byte{0}, + start: maybe.Some([]byte{0}), end: maybe.Some([]byte{1}), priority: lowPriority, localRootID: ids.GenerateTestID(), } mediumPriorityItem := &workItem{ - start: []byte{2}, + start: maybe.Some([]byte{2}), end: maybe.Some([]byte{3}), priority: medPriority, localRootID: ids.GenerateTestID(), } highPriorityItem := &workItem{ - start: []byte{4}, + start: maybe.Some([]byte{4}), end: maybe.Some([]byte{5}), priority: highPriority, localRootID: ids.GenerateTestID(), @@ -232,42 +232,42 @@ func Test_WorkHeap_Merge_Insert(t *testing.T) { // merge with range before syncHeap := newWorkHeap() - syncHeap.MergeInsert(&workItem{start: nil, end: maybe.Some([]byte{63})}) + syncHeap.MergeInsert(&workItem{start: maybe.Nothing[[]byte](), end: maybe.Some([]byte{63})}) require.Equal(t, 1, syncHeap.Len()) - syncHeap.MergeInsert(&workItem{start: []byte{127}, end: maybe.Some([]byte{192})}) + syncHeap.MergeInsert(&workItem{start: maybe.Some([]byte{127}), end: maybe.Some([]byte{192})}) require.Equal(t, 2, syncHeap.Len()) - syncHeap.MergeInsert(&workItem{start: []byte{193}, end: maybe.Nothing[[]byte]()}) + syncHeap.MergeInsert(&workItem{start: maybe.Some([]byte{193}), end: maybe.Nothing[[]byte]()}) require.Equal(t, 3, syncHeap.Len()) - syncHeap.MergeInsert(&workItem{start: []byte{63}, end: maybe.Some([]byte{126}), priority: lowPriority}) + syncHeap.MergeInsert(&workItem{start: maybe.Some([]byte{63}), end: maybe.Some([]byte{126}), priority: lowPriority}) require.Equal(t, 3, syncHeap.Len()) // merge with range after syncHeap = newWorkHeap() - syncHeap.MergeInsert(&workItem{start: nil, end: maybe.Some([]byte{63})}) + syncHeap.MergeInsert(&workItem{start: maybe.Nothing[[]byte](), end: maybe.Some([]byte{63})}) require.Equal(t, 1, syncHeap.Len()) - syncHeap.MergeInsert(&workItem{start: []byte{127}, end: maybe.Some([]byte{192})}) + syncHeap.MergeInsert(&workItem{start: maybe.Some([]byte{127}), end: maybe.Some([]byte{192})}) require.Equal(t, 2, syncHeap.Len()) - syncHeap.MergeInsert(&workItem{start: []byte{193}, end: maybe.Nothing[[]byte]()}) + syncHeap.MergeInsert(&workItem{start: maybe.Some([]byte{193}), end: maybe.Nothing[[]byte]()}) require.Equal(t, 3, syncHeap.Len()) - syncHeap.MergeInsert(&workItem{start: []byte{64}, end: maybe.Some([]byte{127}), priority: lowPriority}) + syncHeap.MergeInsert(&workItem{start: maybe.Some([]byte{64}), end: maybe.Some([]byte{127}), priority: lowPriority}) require.Equal(t, 3, syncHeap.Len()) // merge both sides at the same time syncHeap = newWorkHeap() - syncHeap.MergeInsert(&workItem{start: nil, end: maybe.Some([]byte{63})}) + syncHeap.MergeInsert(&workItem{start: maybe.Nothing[[]byte](), end: maybe.Some([]byte{63})}) require.Equal(t, 1, syncHeap.Len()) - syncHeap.MergeInsert(&workItem{start: []byte{127}, end: maybe.Nothing[[]byte]()}) + syncHeap.MergeInsert(&workItem{start: maybe.Some([]byte{127}), end: maybe.Nothing[[]byte]()}) require.Equal(t, 2, syncHeap.Len()) - syncHeap.MergeInsert(&workItem{start: []byte{63}, end: maybe.Some([]byte{127}), priority: lowPriority}) + syncHeap.MergeInsert(&workItem{start: maybe.Some([]byte{63}), end: maybe.Some([]byte{127}), priority: lowPriority}) require.Equal(t, 1, syncHeap.Len()) }