diff --git a/CHANGELOG.md b/CHANGELOG.md index 496dabbc..735cdaea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) * [#211](https://github.com/babylonlabs-io/finality-provider/pull/211) Clean up unused cmd * [#214](https://github.com/babylonlabs-io/finality-provider/pull/214) Gradual benchmark * [#216](https://github.com/babylonlabs-io/finality-provider/pull/216) Add multiple fpd connecting to one eotsd in e2e tests +* [#218](https://github.com/babylonlabs-io/finality-provider/pull/218) Prune used merkle proof ## v0.13.1 diff --git a/finality-provider/cmd/fpd/daemon/daemon_commands.go b/finality-provider/cmd/fpd/daemon/daemon_commands.go index a919c563..3eda12ca 100644 --- a/finality-provider/cmd/fpd/daemon/daemon_commands.go +++ b/finality-provider/cmd/fpd/daemon/daemon_commands.go @@ -488,6 +488,66 @@ func runCommandEditFinalityDescription(cmd *cobra.Command, args []string) error return nil } +// CommandUnsafePruneMerkleProof prunes merkle proof +func CommandUnsafePruneMerkleProof() *cobra.Command { + var cmd = &cobra.Command{ + Use: "unsafe-prune-merkle-proof [eots_pk]", + Aliases: []string{"rmp"}, + Short: "Prunes merkle proofs up to the specified target height", + Long: strings.TrimSpace(`This command will prune all merkle proof up to the target height. The +operator of this command should ensure that finality provider has voted, or doesn't have voting power up to the target height.' +`), + Example: fmt.Sprintf(`fpd unsafe-prune-merkle-proof [eots_pk] --daemon-address %s`, defaultFpdDaemonAddress), + Args: cobra.ExactArgs(1), + RunE: runCommandUnsafePruneMerkleProof, + } + cmd.Flags().String(fpdDaemonAddressFlag, defaultFpdDaemonAddress, "The RPC server address of fpd") + cmd.Flags().String(chainIDFlag, "", "The identifier of the consumer chain") + cmd.Flags().Uint64(upToHeight, 0, "Target height to prune merkle proofs") + + if err := cmd.MarkFlagRequired(chainIDFlag); err != nil { + panic(err) + } + + if err := cmd.MarkFlagRequired(upToHeight); err != nil { + panic(err) + } + + return cmd +} + +func runCommandUnsafePruneMerkleProof(cmd *cobra.Command, args []string) error { + fpPk, err := types.NewBIP340PubKeyFromHex(args[0]) + if err != nil { + return err + } + + flags := cmd.Flags() + daemonAddress, err := flags.GetString(fpdDaemonAddressFlag) + if err != nil { + return fmt.Errorf("failed to read flag %s: %w", fpdDaemonAddressFlag, err) + } + + grpcClient, cleanUp, err := dc.NewFinalityProviderServiceGRpcClient(daemonAddress) + if err != nil { + return err + } + defer func() { + if err := cleanUp(); err != nil { + fmt.Printf("Failed to clean up grpc client: %v\n", err) + } + }() + + chainID, _ := cmd.Flags().GetString(chainIDFlag) + targetHeight, _ := cmd.Flags().GetUint64(upToHeight) + + if err := grpcClient.UnsafeRemoveMerkleProof(cmd.Context(), fpPk, chainID, targetHeight); err != nil { + return fmt.Errorf("failed to edit finality provider %v err %w", fpPk.MarshalHex(), err) + } + + return nil +} + func printRespJSON(resp interface{}) { jsonBytes, err := json.MarshalIndent(resp, "", " ") if err != nil { diff --git a/finality-provider/cmd/fpd/daemon/flags.go b/finality-provider/cmd/fpd/daemon/flags.go index 4a343a20..6a1f7965 100644 --- a/finality-provider/cmd/fpd/daemon/flags.go +++ b/finality-provider/cmd/fpd/daemon/flags.go @@ -13,6 +13,7 @@ const ( signedFlag = "signed" checkDoubleSignFlag = "check-double-sign" fromFile = "from-file" + upToHeight = "up-to-height" // flags for description monikerFlag = "moniker" diff --git a/finality-provider/cmd/fpd/main.go b/finality-provider/cmd/fpd/main.go index 8c03b56d..88aee363 100644 --- a/finality-provider/cmd/fpd/main.go +++ b/finality-provider/cmd/fpd/main.go @@ -37,7 +37,7 @@ func main() { daemon.CommandInfoFP(), daemon.CommandAddFinalitySig(), daemon.CommandUnjailFP(), daemon.CommandEditFinalityDescription(), daemon.CommandCommitPubRand(), incentivecli.NewWithdrawRewardCmd(), incentivecli.NewSetWithdrawAddressCmd(), - version.CommandVersion("fpd"), + version.CommandVersion("fpd"), daemon.CommandUnsafePruneMerkleProof(), ) if err := cmd.Execute(); err != nil { diff --git a/finality-provider/proto/finality_providers.pb.go b/finality-provider/proto/finality_providers.pb.go index 2b2d8f40..685da2c7 100644 --- a/finality-provider/proto/finality_providers.pb.go +++ b/finality-provider/proto/finality_providers.pb.go @@ -1338,6 +1338,72 @@ func (x *EditFinalityProviderRequest) GetCommission() string { return "" } +type RemoveMerkleProofRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // btc_pk_hex is the hex string of the BTC secp256k1 PK of the finality provider encoded in BIP-340 spec + BtcPkHex string `protobuf:"bytes,1,opt,name=btc_pk_hex,json=btcPkHex,proto3" json:"btc_pk_hex,omitempty"` + // chain_id is the identifier of the consumer chain + ChainId string `protobuf:"bytes,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + // target_height to to delete all proofs + TargetHeight uint64 `protobuf:"varint,3,opt,name=target_height,json=targetHeight,proto3" json:"target_height,omitempty"` +} + +func (x *RemoveMerkleProofRequest) Reset() { + *x = RemoveMerkleProofRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_finality_providers_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveMerkleProofRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveMerkleProofRequest) ProtoMessage() {} + +func (x *RemoveMerkleProofRequest) ProtoReflect() protoreflect.Message { + mi := &file_finality_providers_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveMerkleProofRequest.ProtoReflect.Descriptor instead. +func (*RemoveMerkleProofRequest) Descriptor() ([]byte, []int) { + return file_finality_providers_proto_rawDescGZIP(), []int{20} +} + +func (x *RemoveMerkleProofRequest) GetBtcPkHex() string { + if x != nil { + return x.BtcPkHex + } + return "" +} + +func (x *RemoveMerkleProofRequest) GetChainId() string { + if x != nil { + return x.ChainId + } + return "" +} + +func (x *RemoveMerkleProofRequest) GetTargetHeight() uint64 { + if x != nil { + return x.TargetHeight + } + return 0 +} + // Define an empty response message type EmptyResponse struct { state protoimpl.MessageState @@ -1348,7 +1414,7 @@ type EmptyResponse struct { func (x *EmptyResponse) Reset() { *x = EmptyResponse{} if protoimpl.UnsafeEnabled { - mi := &file_finality_providers_proto_msgTypes[20] + mi := &file_finality_providers_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1361,7 +1427,7 @@ func (x *EmptyResponse) String() string { func (*EmptyResponse) ProtoMessage() {} func (x *EmptyResponse) ProtoReflect() protoreflect.Message { - mi := &file_finality_providers_proto_msgTypes[20] + mi := &file_finality_providers_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1374,7 +1440,7 @@ func (x *EmptyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EmptyResponse.ProtoReflect.Descriptor instead. func (*EmptyResponse) Descriptor() ([]byte, []int) { - return file_finality_providers_proto_rawDescGZIP(), []int{20} + return file_finality_providers_proto_rawDescGZIP(), []int{21} } var File_finality_providers_proto protoreflect.FileDescriptor @@ -1543,66 +1609,79 @@ var file_finality_providers_proto_rawDesc = []byte{ 0x01, 0x28, 0x09, 0x42, 0x2d, 0xda, 0xde, 0x1f, 0x1b, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x44, 0x65, 0x63, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x44, - 0x65, 0x63, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x0f, - 0x0a, 0x0d, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, - 0xa4, 0x01, 0x0a, 0x16, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x52, 0x45, - 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x45, 0x44, 0x10, 0x00, 0x1a, 0x0e, 0x8a, 0x9d, 0x20, 0x0a, - 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x45, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x43, - 0x54, 0x49, 0x56, 0x45, 0x10, 0x01, 0x1a, 0x0a, 0x8a, 0x9d, 0x20, 0x06, 0x41, 0x43, 0x54, 0x49, - 0x56, 0x45, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x4e, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, - 0x1a, 0x0c, 0x8a, 0x9d, 0x20, 0x08, 0x49, 0x4e, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x12, 0x18, - 0x0a, 0x07, 0x53, 0x4c, 0x41, 0x53, 0x48, 0x45, 0x44, 0x10, 0x03, 0x1a, 0x0b, 0x8a, 0x9d, 0x20, - 0x07, 0x53, 0x4c, 0x41, 0x53, 0x48, 0x45, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x4a, 0x41, 0x49, 0x4c, - 0x45, 0x44, 0x10, 0x04, 0x1a, 0x0a, 0x8a, 0x9d, 0x20, 0x06, 0x4a, 0x41, 0x49, 0x4c, 0x45, 0x44, - 0x1a, 0x04, 0x88, 0xa3, 0x1e, 0x00, 0x32, 0xa2, 0x05, 0x0a, 0x11, 0x46, 0x69, 0x6e, 0x61, 0x6c, - 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x38, 0x0a, 0x07, - 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x12, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, + 0x65, 0x63, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x78, + 0x0a, 0x18, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x0a, 0x62, 0x74, + 0x63, 0x5f, 0x70, 0x6b, 0x5f, 0x68, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x62, 0x74, 0x63, 0x50, 0x6b, 0x48, 0x65, 0x78, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x0f, 0x0a, 0x0d, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0xa4, 0x01, 0x0a, 0x16, 0x46, 0x69, + 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, + 0x45, 0x44, 0x10, 0x00, 0x1a, 0x0e, 0x8a, 0x9d, 0x20, 0x0a, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, + 0x45, 0x52, 0x45, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x01, + 0x1a, 0x0a, 0x8a, 0x9d, 0x20, 0x06, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x12, 0x1a, 0x0a, 0x08, + 0x49, 0x4e, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, 0x1a, 0x0c, 0x8a, 0x9d, 0x20, 0x08, + 0x49, 0x4e, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x4c, 0x41, 0x53, + 0x48, 0x45, 0x44, 0x10, 0x03, 0x1a, 0x0b, 0x8a, 0x9d, 0x20, 0x07, 0x53, 0x4c, 0x41, 0x53, 0x48, + 0x45, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x4a, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x1a, 0x0a, + 0x8a, 0x9d, 0x20, 0x06, 0x4a, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x1a, 0x04, 0x88, 0xa3, 0x1e, 0x00, + 0x32, 0xf4, 0x05, 0x0a, 0x11, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x38, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x65, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, + 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x24, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, + 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, - 0x14, 0x41, 0x64, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x53, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x64, - 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x41, 0x64, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x53, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, - 0x0a, 0x16, 0x55, 0x6e, 0x6a, 0x61, 0x69, 0x6c, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x46, 0x69, + 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, + 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x64, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, + 0x69, 0x74, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x64, 0x64, 0x46, + 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x16, 0x55, 0x6e, 0x6a, 0x61, + 0x69, 0x6c, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x12, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x6e, 0x6a, 0x61, 0x69, + 0x6c, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x6e, 0x6a, 0x61, 0x69, 0x6c, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x6e, 0x6a, 0x61, 0x69, 0x6c, 0x46, 0x69, 0x6e, - 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x15, 0x51, 0x75, 0x65, 0x72, 0x79, 0x46, 0x69, - 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x23, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x46, 0x69, 0x6e, 0x61, - 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x19, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x46, 0x69, 0x6e, - 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x14, 0x45, 0x64, 0x69, - 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x12, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x46, 0x69, - 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x45, 0x5a, 0x43, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x62, 0x79, 0x6c, 0x6f, - 0x6e, 0x6c, 0x61, 0x62, 0x73, 0x2d, 0x69, 0x6f, 0x2f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, - 0x79, 0x2d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x66, 0x69, 0x6e, 0x61, 0x6c, - 0x69, 0x74, 0x79, 0x2d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x62, 0x0a, 0x15, 0x51, 0x75, 0x65, 0x72, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, + 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, + 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x19, 0x51, 0x75, 0x65, 0x72, 0x79, 0x46, 0x69, 0x6e, 0x61, + 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x46, 0x69, + 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4c, 0x69, + 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x50, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x14, 0x45, 0x64, 0x69, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, + 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x22, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, + 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x17, 0x55, 0x6e, 0x73, 0x61, 0x66, 0x65, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0x12, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, + 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x45, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x62, 0x79, 0x6c, 0x6f, 0x6e, 0x6c, 0x61, 0x62, + 0x73, 0x2d, 0x69, 0x6f, 0x2f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2d, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2d, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1618,7 +1697,7 @@ func file_finality_providers_proto_rawDescGZIP() []byte { } var file_finality_providers_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_finality_providers_proto_msgTypes = make([]protoimpl.MessageInfo, 21) +var file_finality_providers_proto_msgTypes = make([]protoimpl.MessageInfo, 22) var file_finality_providers_proto_goTypes = []interface{}{ (FinalityProviderStatus)(0), // 0: proto.FinalityProviderStatus (*GetInfoRequest)(nil), // 1: proto.GetInfoRequest @@ -1641,7 +1720,8 @@ var file_finality_providers_proto_goTypes = []interface{}{ (*SignMessageFromChainKeyRequest)(nil), // 18: proto.SignMessageFromChainKeyRequest (*SignMessageFromChainKeyResponse)(nil), // 19: proto.SignMessageFromChainKeyResponse (*EditFinalityProviderRequest)(nil), // 20: proto.EditFinalityProviderRequest - (*EmptyResponse)(nil), // 21: proto.EmptyResponse + (*RemoveMerkleProofRequest)(nil), // 21: proto.RemoveMerkleProofRequest + (*EmptyResponse)(nil), // 22: proto.EmptyResponse } var file_finality_providers_proto_depIdxs = []int32{ 14, // 0: proto.CreateFinalityProviderResponse.finality_provider:type_name -> proto.FinalityProviderInfo @@ -1657,15 +1737,17 @@ var file_finality_providers_proto_depIdxs = []int32{ 9, // 10: proto.FinalityProviders.QueryFinalityProvider:input_type -> proto.QueryFinalityProviderRequest 11, // 11: proto.FinalityProviders.QueryFinalityProviderList:input_type -> proto.QueryFinalityProviderListRequest 20, // 12: proto.FinalityProviders.EditFinalityProvider:input_type -> proto.EditFinalityProviderRequest - 2, // 13: proto.FinalityProviders.GetInfo:output_type -> proto.GetInfoResponse - 4, // 14: proto.FinalityProviders.CreateFinalityProvider:output_type -> proto.CreateFinalityProviderResponse - 6, // 15: proto.FinalityProviders.AddFinalitySignature:output_type -> proto.AddFinalitySignatureResponse - 8, // 16: proto.FinalityProviders.UnjailFinalityProvider:output_type -> proto.UnjailFinalityProviderResponse - 10, // 17: proto.FinalityProviders.QueryFinalityProvider:output_type -> proto.QueryFinalityProviderResponse - 12, // 18: proto.FinalityProviders.QueryFinalityProviderList:output_type -> proto.QueryFinalityProviderListResponse - 21, // 19: proto.FinalityProviders.EditFinalityProvider:output_type -> proto.EmptyResponse - 13, // [13:20] is the sub-list for method output_type - 6, // [6:13] is the sub-list for method input_type + 21, // 13: proto.FinalityProviders.UnsafeRemoveMerkleProof:input_type -> proto.RemoveMerkleProofRequest + 2, // 14: proto.FinalityProviders.GetInfo:output_type -> proto.GetInfoResponse + 4, // 15: proto.FinalityProviders.CreateFinalityProvider:output_type -> proto.CreateFinalityProviderResponse + 6, // 16: proto.FinalityProviders.AddFinalitySignature:output_type -> proto.AddFinalitySignatureResponse + 8, // 17: proto.FinalityProviders.UnjailFinalityProvider:output_type -> proto.UnjailFinalityProviderResponse + 10, // 18: proto.FinalityProviders.QueryFinalityProvider:output_type -> proto.QueryFinalityProviderResponse + 12, // 19: proto.FinalityProviders.QueryFinalityProviderList:output_type -> proto.QueryFinalityProviderListResponse + 22, // 20: proto.FinalityProviders.EditFinalityProvider:output_type -> proto.EmptyResponse + 22, // 21: proto.FinalityProviders.UnsafeRemoveMerkleProof:output_type -> proto.EmptyResponse + 14, // [14:22] is the sub-list for method output_type + 6, // [6:14] is the sub-list for method input_type 6, // [6:6] is the sub-list for extension type_name 6, // [6:6] is the sub-list for extension extendee 0, // [0:6] is the sub-list for field type_name @@ -1918,6 +2000,18 @@ func file_finality_providers_proto_init() { } } file_finality_providers_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RemoveMerkleProofRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_finality_providers_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*EmptyResponse); i { case 0: return &v.state @@ -1936,7 +2030,7 @@ func file_finality_providers_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_finality_providers_proto_rawDesc, NumEnums: 1, - NumMessages: 21, + NumMessages: 22, NumExtensions: 0, NumServices: 1, }, diff --git a/finality-provider/proto/finality_providers.proto b/finality-provider/proto/finality_providers.proto index 533c0acf..87e0704b 100644 --- a/finality-provider/proto/finality_providers.proto +++ b/finality-provider/proto/finality_providers.proto @@ -35,6 +35,9 @@ service FinalityProviders { // EditFinalityProvider edits finality provider rpc EditFinalityProvider (EditFinalityProviderRequest) returns (EmptyResponse); + + // UnsafeRemoveMerkleProof removes merkle proofs up to target height + rpc UnsafeRemoveMerkleProof (RemoveMerkleProofRequest) returns (EmptyResponse); } message GetInfoRequest { @@ -243,5 +246,14 @@ message EditFinalityProviderRequest { ]; } +message RemoveMerkleProofRequest { + // btc_pk_hex is the hex string of the BTC secp256k1 PK of the finality provider encoded in BIP-340 spec + string btc_pk_hex = 1; + // chain_id is the identifier of the consumer chain + string chain_id = 2; + // target_height to to delete all proofs + uint64 target_height = 3; +} + // Define an empty response message message EmptyResponse {} diff --git a/finality-provider/proto/finality_providers_grpc.pb.go b/finality-provider/proto/finality_providers_grpc.pb.go index ca523db6..c8726775 100644 --- a/finality-provider/proto/finality_providers_grpc.pb.go +++ b/finality-provider/proto/finality_providers_grpc.pb.go @@ -26,6 +26,7 @@ const ( FinalityProviders_QueryFinalityProvider_FullMethodName = "/proto.FinalityProviders/QueryFinalityProvider" FinalityProviders_QueryFinalityProviderList_FullMethodName = "/proto.FinalityProviders/QueryFinalityProviderList" FinalityProviders_EditFinalityProvider_FullMethodName = "/proto.FinalityProviders/EditFinalityProvider" + FinalityProviders_UnsafeRemoveMerkleProof_FullMethodName = "/proto.FinalityProviders/UnsafeRemoveMerkleProof" ) // FinalityProvidersClient is the client API for FinalityProviders service. @@ -48,6 +49,8 @@ type FinalityProvidersClient interface { QueryFinalityProviderList(ctx context.Context, in *QueryFinalityProviderListRequest, opts ...grpc.CallOption) (*QueryFinalityProviderListResponse, error) // EditFinalityProvider edits finality provider EditFinalityProvider(ctx context.Context, in *EditFinalityProviderRequest, opts ...grpc.CallOption) (*EmptyResponse, error) + // UnsafeRemoveMerkleProof removes merkle proofs up to target height + UnsafeRemoveMerkleProof(ctx context.Context, in *RemoveMerkleProofRequest, opts ...grpc.CallOption) (*EmptyResponse, error) } type finalityProvidersClient struct { @@ -121,6 +124,15 @@ func (c *finalityProvidersClient) EditFinalityProvider(ctx context.Context, in * return out, nil } +func (c *finalityProvidersClient) UnsafeRemoveMerkleProof(ctx context.Context, in *RemoveMerkleProofRequest, opts ...grpc.CallOption) (*EmptyResponse, error) { + out := new(EmptyResponse) + err := c.cc.Invoke(ctx, FinalityProviders_UnsafeRemoveMerkleProof_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // FinalityProvidersServer is the server API for FinalityProviders service. // All implementations must embed UnimplementedFinalityProvidersServer // for forward compatibility @@ -141,6 +153,8 @@ type FinalityProvidersServer interface { QueryFinalityProviderList(context.Context, *QueryFinalityProviderListRequest) (*QueryFinalityProviderListResponse, error) // EditFinalityProvider edits finality provider EditFinalityProvider(context.Context, *EditFinalityProviderRequest) (*EmptyResponse, error) + // UnsafeRemoveMerkleProof removes merkle proofs up to target height + UnsafeRemoveMerkleProof(context.Context, *RemoveMerkleProofRequest) (*EmptyResponse, error) mustEmbedUnimplementedFinalityProvidersServer() } @@ -169,6 +183,9 @@ func (UnimplementedFinalityProvidersServer) QueryFinalityProviderList(context.Co func (UnimplementedFinalityProvidersServer) EditFinalityProvider(context.Context, *EditFinalityProviderRequest) (*EmptyResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method EditFinalityProvider not implemented") } +func (UnimplementedFinalityProvidersServer) UnsafeRemoveMerkleProof(context.Context, *RemoveMerkleProofRequest) (*EmptyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UnsafeRemoveMerkleProof not implemented") +} func (UnimplementedFinalityProvidersServer) mustEmbedUnimplementedFinalityProvidersServer() {} // UnsafeFinalityProvidersServer may be embedded to opt out of forward compatibility for this service. @@ -308,6 +325,24 @@ func _FinalityProviders_EditFinalityProvider_Handler(srv interface{}, ctx contex return interceptor(ctx, in, info, handler) } +func _FinalityProviders_UnsafeRemoveMerkleProof_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveMerkleProofRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FinalityProvidersServer).UnsafeRemoveMerkleProof(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: FinalityProviders_UnsafeRemoveMerkleProof_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FinalityProvidersServer).UnsafeRemoveMerkleProof(ctx, req.(*RemoveMerkleProofRequest)) + } + return interceptor(ctx, in, info, handler) +} + // FinalityProviders_ServiceDesc is the grpc.ServiceDesc for FinalityProviders service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -343,6 +378,10 @@ var FinalityProviders_ServiceDesc = grpc.ServiceDesc{ MethodName: "EditFinalityProvider", Handler: _FinalityProviders_EditFinalityProvider_Handler, }, + { + MethodName: "UnsafeRemoveMerkleProof", + Handler: _FinalityProviders_UnsafeRemoveMerkleProof_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "finality_providers.proto", diff --git a/finality-provider/service/benchmark_helper.go b/finality-provider/service/benchmark_helper.go index 55601fc8..092312d3 100644 --- a/finality-provider/service/benchmark_helper.go +++ b/finality-provider/service/benchmark_helper.go @@ -66,7 +66,7 @@ func (fp *FinalityProviderInstance) commitPubRandPairsWithTiming(startHeight uin // Measure addPubRandProofList addProofStart := time.Now() - if err := fp.pubRandState.addPubRandProofList(pubRandList, proofList); err != nil { + if err := fp.pubRandState.addPubRandProofList(fp.GetChainID(), fp.btcPk.MustMarshal(), startHeight, uint64(fp.cfg.NumPubRand), proofList); err != nil { return nil, timing, fmt.Errorf("failed to save public randomness to DB: %w", err) } timing.AddPubRandProofListTime = time.Since(addProofStart) diff --git a/finality-provider/service/client/rpcclient.go b/finality-provider/service/client/rpcclient.go index fc3ea579..68c2a1c0 100644 --- a/finality-provider/service/client/rpcclient.go +++ b/finality-provider/service/client/rpcclient.go @@ -141,3 +141,15 @@ func (c *FinalityProviderServiceGRpcClient) EditFinalityProvider( return nil } + +// UnsafeRemoveMerkleProof - remove all proofs up to target height +func (c *FinalityProviderServiceGRpcClient) UnsafeRemoveMerkleProof( + ctx context.Context, fpPk *bbntypes.BIP340PubKey, chainID string, targetHeight uint64) error { + req := &proto.RemoveMerkleProofRequest{BtcPkHex: fpPk.MarshalHex(), ChainId: chainID, TargetHeight: targetHeight} + _, err := c.client.UnsafeRemoveMerkleProof(ctx, req) + if err != nil { + return err + } + + return nil +} diff --git a/finality-provider/service/fp_instance.go b/finality-provider/service/fp_instance.go index 911f700b..d1e22c1e 100644 --- a/finality-provider/service/fp_instance.go +++ b/finality-provider/service/fp_instance.go @@ -526,7 +526,7 @@ func (fp *FinalityProviderInstance) commitPubRandPairs(startHeight uint64) (*typ commitment, proofList := types.GetPubRandCommitAndProofs(pubRandList) // store them to database - if err := fp.pubRandState.addPubRandProofList(pubRandList, proofList); err != nil { + if err := fp.pubRandState.addPubRandProofList(fp.btcPk.MustMarshal(), fp.GetChainID(), startHeight, uint64(fp.cfg.NumPubRand), proofList); err != nil { return nil, fmt.Errorf("failed to save public randomness to DB: %w", err) } @@ -638,14 +638,20 @@ func (fp *FinalityProviderInstance) SubmitBatchFinalitySignatures(blocks []*type } // get public randomness list + numPubRand := len(blocks) // #nosec G115 -- performed the conversion check above - prList, err := fp.getPubRandList(blocks[0].Height, uint32(len(blocks))) + prList, err := fp.getPubRandList(blocks[0].Height, uint32(numPubRand)) if err != nil { return nil, fmt.Errorf("failed to get public randomness list: %w", err) } // get proof list // TODO: how to recover upon having an error in getPubRandProofList? - proofBytesList, err := fp.pubRandState.getPubRandProofList(prList) + proofBytesList, err := fp.pubRandState.getPubRandProofList( + fp.btcPk.MustMarshal(), + fp.GetChainID(), + blocks[0].Height, + uint64(numPubRand), + ) if err != nil { return nil, fmt.Errorf("failed to get public randomness inclusion proof list: %w", err) } @@ -693,7 +699,7 @@ func (fp *FinalityProviderInstance) TestSubmitFinalitySignatureAndExtractPrivKey pubRand := prList[0] // get proof - proofBytes, err := fp.pubRandState.getPubRandProof(pubRand) + proofBytes, err := fp.pubRandState.getPubRandProof(fp.btcPk.MustMarshal(), fp.GetChainID(), b.Height) if err != nil { return nil, nil, fmt.Errorf("failed to get public randomness inclusion proof: %w", err) } diff --git a/finality-provider/service/pub_rand_store_adapter.go b/finality-provider/service/pub_rand_store_adapter.go index b4a1a4a8..3ab30891 100644 --- a/finality-provider/service/pub_rand_store_adapter.go +++ b/finality-provider/service/pub_rand_store_adapter.go @@ -2,7 +2,6 @@ package service import ( "github.com/babylonlabs-io/finality-provider/finality-provider/store" - "github.com/btcsuite/btcd/btcec/v2" "github.com/cometbft/cometbft/crypto/merkle" ) @@ -15,16 +14,16 @@ func newPubRandState(s *store.PubRandProofStore) *pubRandState { } func (st *pubRandState) addPubRandProofList( - pubRandList []*btcec.FieldVal, + pk, chainID []byte, height uint64, numPubRand uint64, proofList []*merkle.Proof, ) error { - return st.s.AddPubRandProofList(pubRandList, proofList) + return st.s.AddPubRandProofList(chainID, pk, height, numPubRand, proofList) } -func (st *pubRandState) getPubRandProof(pubRand *btcec.FieldVal) ([]byte, error) { - return st.s.GetPubRandProof(pubRand) +func (st *pubRandState) getPubRandProof(pk, chainID []byte, height uint64) ([]byte, error) { + return st.s.GetPubRandProof(chainID, pk, height) } -func (st *pubRandState) getPubRandProofList(pubRandList []*btcec.FieldVal) ([][]byte, error) { - return st.s.GetPubRandProofList(pubRandList) +func (st *pubRandState) getPubRandProofList(pk, chainID []byte, height uint64, numPubRand uint64) ([][]byte, error) { + return st.s.GetPubRandProofList(chainID, pk, height, numPubRand) } diff --git a/finality-provider/service/rpcserver.go b/finality-provider/service/rpcserver.go index 580bfbea..502780f3 100644 --- a/finality-provider/service/rpcserver.go +++ b/finality-provider/service/rpcserver.go @@ -264,6 +264,20 @@ func (r *rpcServer) QueryFinalityProviderList(_ context.Context, _ *proto.QueryF return &proto.QueryFinalityProviderListResponse{FinalityProviders: fps}, nil } +// UnsafeRemoveMerkleProof - removes proofs up to target height +func (r *rpcServer) UnsafeRemoveMerkleProof(_ context.Context, req *proto.RemoveMerkleProofRequest) (*proto.EmptyResponse, error) { + fpPk, err := parseEotsPk(req.BtcPkHex) + if err != nil { + return nil, err + } + + if err := r.app.pubRandStore.RemovePubRandProofList([]byte(req.ChainId), fpPk.MustMarshal(), req.TargetHeight); err != nil { + return nil, err + } + + return nil, nil +} + func parseEotsPk(eotsPkHex string) (*bbntypes.BIP340PubKey, error) { if eotsPkHex == "" { return nil, fmt.Errorf("eots-pk cannot be empty") diff --git a/finality-provider/store/pub_rand.go b/finality-provider/store/pub_rand.go index 157db821..51fa45b6 100644 --- a/finality-provider/store/pub_rand.go +++ b/finality-provider/store/pub_rand.go @@ -1,9 +1,12 @@ package store import ( + "bytes" "fmt" - "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcwallet/walletdb" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cometbft/cometbft/crypto/merkle" "github.com/lightningnetwork/lnd/kvdb" ) @@ -34,20 +37,56 @@ func (s *PubRandProofStore) initBuckets() error { }) } +// getKey key is (chainID || pk || height) +func getKey(chainID, pk []byte, height uint64) []byte { + // Convert height to bytes + heightBytes := sdk.Uint64ToBigEndian(height) + + // Concatenate all components to create the key + key := make([]byte, 0, len(pk)+len(chainID)+len(heightBytes)) + key = append(key, chainID...) + key = append(key, pk...) + key = append(key, heightBytes...) + + return key +} + +func getPrefixKey(chainID, pk []byte) []byte { + // Concatenate chainID and pk to form the prefix + prefix := make([]byte, 0, len(chainID)+len(pk)) + prefix = append(prefix, chainID...) + prefix = append(prefix, pk...) + + return prefix +} + +func buildKeys(chainID, pk []byte, height uint64, num uint64) [][]byte { + keys := make([][]byte, 0, num) + + for i := uint64(0); i < num; i++ { + key := getKey(chainID, pk, height+i) + keys = append(keys, key) + } + + return keys +} + func (s *PubRandProofStore) AddPubRandProofList( - pubRandList []*btcec.FieldVal, + chainID []byte, + pk []byte, + height uint64, + numPubRand uint64, proofList []*merkle.Proof, ) error { - if len(pubRandList) != len(proofList) { + keys := buildKeys(chainID, pk, height, numPubRand) + + if len(keys) != len(proofList) { return fmt.Errorf("the number of public randomness is not same as the number of proofs") } - pubRandBytesList := [][]byte{} - proofBytesList := [][]byte{} - for i := range pubRandList { - pubRandBytes := *pubRandList[i].Bytes() - pubRandBytesList = append(pubRandBytesList, pubRandBytes[:]) - proofBytes, err := proofList[i].ToProto().Marshal() + var proofBytesList [][]byte + for _, proof := range proofList { + proofBytes, err := proof.ToProto().Marshal() if err != nil { return fmt.Errorf("invalid proof: %w", err) } @@ -60,13 +99,13 @@ func (s *PubRandProofStore) AddPubRandProofList( return ErrCorruptedPubRandProofDB } - for i := range pubRandBytesList { + for i, key := range keys { // skip if already committed - if bucket.Get(pubRandBytesList[i]) != nil { + if bucket.Get(key) != nil { continue } // set to DB - if err := bucket.Put(pubRandBytesList[i], proofBytesList[i]); err != nil { + if err := bucket.Put(key, proofBytesList[i]); err != nil { return err } } @@ -75,8 +114,8 @@ func (s *PubRandProofStore) AddPubRandProofList( }) } -func (s *PubRandProofStore) GetPubRandProof(pubRand *btcec.FieldVal) ([]byte, error) { - pubRandBytes := *pubRand.Bytes() +func (s *PubRandProofStore) GetPubRandProof(chainID []byte, pk []byte, height uint64) ([]byte, error) { + key := getKey(chainID, pk, height) var proofBytes []byte err := s.db.View(func(tx kvdb.RTx) error { @@ -85,7 +124,7 @@ func (s *PubRandProofStore) GetPubRandProof(pubRand *btcec.FieldVal) ([]byte, er return ErrCorruptedPubRandProofDB } - proofBytes = bucket.Get(pubRandBytes[:]) + proofBytes = bucket.Get(key) if proofBytes == nil { return ErrPubRandProofNotFound } @@ -100,14 +139,14 @@ func (s *PubRandProofStore) GetPubRandProof(pubRand *btcec.FieldVal) ([]byte, er return proofBytes, nil } -func (s *PubRandProofStore) GetPubRandProofList(pubRandList []*btcec.FieldVal) ([][]byte, error) { - pubRandBytesList := [][]byte{} - for i := range pubRandList { - pubRandBytes := *pubRandList[i].Bytes() - pubRandBytesList = append(pubRandBytesList, pubRandBytes[:]) - } +func (s *PubRandProofStore) GetPubRandProofList(chainID []byte, + pk []byte, + height uint64, + numPubRand uint64, +) ([][]byte, error) { + keys := buildKeys(chainID, pk, height, numPubRand) - proofBytesList := [][]byte{} + var proofBytesList [][]byte err := s.db.View(func(tx kvdb.RTx) error { bucket := tx.ReadBucket(pubRandProofBucketName) @@ -115,8 +154,8 @@ func (s *PubRandProofStore) GetPubRandProofList(pubRandList []*btcec.FieldVal) ( return ErrCorruptedPubRandProofDB } - for i := range pubRandBytesList { - proofBytes := bucket.Get(pubRandBytesList[i]) + for _, key := range keys { + proofBytes := bucket.Get(key) if proofBytes == nil { return ErrPubRandProofNotFound } @@ -132,3 +171,38 @@ func (s *PubRandProofStore) GetPubRandProofList(pubRandList []*btcec.FieldVal) ( return proofBytesList, nil } + +// RemovePubRandProofList removes all proofs up to the target height +func (s *PubRandProofStore) RemovePubRandProofList(chainID []byte, pk []byte, targetHeight uint64) error { + prefix := getPrefixKey(chainID, pk) + + err := s.db.Update(func(tx walletdb.ReadWriteTx) error { + bucket := tx.ReadWriteBucket(pubRandProofBucketName) + if bucket == nil { + return walletdb.ErrBucketNotFound + } + + cursor := bucket.ReadWriteCursor() + + for k, _ := cursor.Seek(prefix); k != nil && bytes.HasPrefix(k, prefix); k, _ = cursor.Next() { + heightBytes := k[len(k)-8:] + height := sdk.BigEndianToUint64(heightBytes) + + // no need to keep iterating, keys are sorted in lexicographical order upon insert + if height > targetHeight { + break + } + + if err := cursor.Delete(); err != nil { + return err + } + } + return nil + }, func() {}) + + if err != nil { + return err + } + + return nil +} diff --git a/finality-provider/store/pub_rand_test.go b/finality-provider/store/pub_rand_test.go new file mode 100644 index 00000000..5090bbbf --- /dev/null +++ b/finality-provider/store/pub_rand_test.go @@ -0,0 +1,50 @@ +package store_test + +import ( + "github.com/babylonlabs-io/babylon/testutil/datagen" + "github.com/babylonlabs-io/finality-provider/finality-provider/config" + "github.com/babylonlabs-io/finality-provider/finality-provider/store" + "github.com/babylonlabs-io/finality-provider/testutil" + "github.com/stretchr/testify/require" + "math/rand" + "testing" +) + +// FuzzRemoveMerkleProof removal of proofs +func FuzzRemoveMerkleProof(f *testing.F) { + testutil.AddRandomSeedsToFuzzer(f, 10) + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + homePath := t.TempDir() + cfg := config.DefaultDBConfigWithHomePath(homePath) + + db, err := cfg.GetDBBackend() + require.NoError(t, err) + vs, err := store.NewPubRandProofStore(db) + require.NoError(t, err) + + numPubRand := uint64(r.Intn(1000)) + chainID := []byte("test-chain") + rl, err := datagen.GenRandomPubRandList(r, numPubRand) + require.NoError(t, err) + fp := testutil.GenRandomFinalityProvider(r, t) + + defer func() { + err := db.Close() + require.NoError(t, err) + }() + + startHeight := uint64(1) + err = vs.AddPubRandProofList(chainID, fp.GetBIP340BTCPK().MustMarshal(), startHeight, numPubRand, rl.ProofList) + require.NoError(t, err) + + targetHeight := uint64(r.Intn(1000)) + err = vs.RemovePubRandProofList(chainID, fp.GetBIP340BTCPK().MustMarshal(), targetHeight) + require.NoError(t, err) + + _, err = vs.GetPubRandProofList(chainID, fp.GetBIP340BTCPK().MustMarshal(), startHeight, targetHeight) + require.ErrorIs(t, err, store.ErrPubRandProofNotFound) + }) +} diff --git a/itest/e2e_test.go b/itest/e2e_test.go index 08525980..01b8bf0f 100644 --- a/itest/e2e_test.go +++ b/itest/e2e_test.go @@ -1,11 +1,10 @@ -//go:build e2e -// +build e2e - package e2etest import ( "encoding/json" + "errors" "fmt" + "github.com/babylonlabs-io/finality-provider/finality-provider/store" "log" "math/rand" "os" @@ -326,3 +325,30 @@ func TestFinalityProviderCreateCmd(t *testing.T) { require.NoError(t, err) require.NotNil(t, fp) } + +func TestRemoveMerkleProofsCmd(t *testing.T) { + tm, fps := StartManagerWithFinalityProvider(t, 1) + defer tm.Stop(t) + + fpIns := fps[0] + + tm.WaitForFpPubRandTimestamped(t, fps[0]) + cmd := daemon.CommandUnsafePruneMerkleProof() + + cmd.SetArgs([]string{ + fpIns.GetBtcPkHex(), + "--daemon-address=" + fpIns.GetConfig().RPCListener, + "--up-to-height=100", + "--chain-id=" + testChainID, + }) + + err := cmd.Execute() + require.NoError(t, err) + + require.Eventually(t, func() bool { + _, err := tm.Fps[0].GetPubRandProofStore(). + GetPubRandProof(fpIns.GetChainID(), fpIns.GetBtcPkBIP340().MustMarshal(), 99) + + return errors.Is(err, store.ErrPubRandProofNotFound) + }, eventuallyWaitTimeOut, eventuallyPollTime) +}