From d9437303b9715a374318405dac6075d79275689e Mon Sep 17 00:00:00 2001 From: Tomasz Slabon Date: Thu, 4 Jan 2024 19:03:35 +0100 Subject: [PATCH] Added moving funds message unmarshaling --- pkg/tbtc/gen/pb/message.pb.go | 105 ++++++++++++++++++++++++++++++---- pkg/tbtc/gen/pb/message.proto | 8 ++- pkg/tbtc/marshaling.go | 33 +++++++++-- pkg/tbtc/marshaling_test.go | 73 ++++++++++++++++++----- pkg/tbtc/moving_funds.go | 3 + 5 files changed, 194 insertions(+), 28 deletions(-) diff --git a/pkg/tbtc/gen/pb/message.pb.go b/pkg/tbtc/gen/pb/message.pb.go index 424df0eacd..82068dd9a3 100644 --- a/pkg/tbtc/gen/pb/message.pb.go +++ b/pkg/tbtc/gen/pb/message.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v3.7.1 +// protoc-gen-go v1.28.0 +// protoc v3.19.4 // source: pkg/tbtc/gen/pb/message.proto package pb @@ -390,6 +390,69 @@ func (x *RedemptionProposal) GetRedemptionTxFee() []byte { return nil } +type MovingFundsProposal struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WalletPublicKeyHash []byte `protobuf:"bytes,1,opt,name=walletPublicKeyHash,proto3" json:"walletPublicKeyHash,omitempty"` + TargetWallets [][]byte `protobuf:"bytes,2,rep,name=targetWallets,proto3" json:"targetWallets,omitempty"` + MovingFundsTxFee []byte `protobuf:"bytes,3,opt,name=movingFundsTxFee,proto3" json:"movingFundsTxFee,omitempty"` +} + +func (x *MovingFundsProposal) Reset() { + *x = MovingFundsProposal{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_tbtc_gen_pb_message_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MovingFundsProposal) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MovingFundsProposal) ProtoMessage() {} + +func (x *MovingFundsProposal) ProtoReflect() protoreflect.Message { + mi := &file_pkg_tbtc_gen_pb_message_proto_msgTypes[6] + 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 MovingFundsProposal.ProtoReflect.Descriptor instead. +func (*MovingFundsProposal) Descriptor() ([]byte, []int) { + return file_pkg_tbtc_gen_pb_message_proto_rawDescGZIP(), []int{6} +} + +func (x *MovingFundsProposal) GetWalletPublicKeyHash() []byte { + if x != nil { + return x.WalletPublicKeyHash + } + return nil +} + +func (x *MovingFundsProposal) GetTargetWallets() [][]byte { + if x != nil { + return x.TargetWallets + } + return nil +} + +func (x *MovingFundsProposal) GetMovingFundsTxFee() []byte { + if x != nil { + return x.MovingFundsTxFee + } + return nil +} + type DepositSweepProposal_DepositKey struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -402,7 +465,7 @@ type DepositSweepProposal_DepositKey struct { func (x *DepositSweepProposal_DepositKey) Reset() { *x = DepositSweepProposal_DepositKey{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_tbtc_gen_pb_message_proto_msgTypes[6] + mi := &file_pkg_tbtc_gen_pb_message_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -415,7 +478,7 @@ func (x *DepositSweepProposal_DepositKey) String() string { func (*DepositSweepProposal_DepositKey) ProtoMessage() {} func (x *DepositSweepProposal_DepositKey) ProtoReflect() protoreflect.Message { - mi := &file_pkg_tbtc_gen_pb_message_proto_msgTypes[6] + mi := &file_pkg_tbtc_gen_pb_message_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -507,8 +570,17 @@ var file_pkg_tbtc_gen_pb_message_proto_rawDesc = []byte{ 0x75, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x64, 0x65, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x78, 0x46, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x72, 0x65, 0x64, 0x65, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x78, - 0x46, 0x65, 0x65, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x46, 0x65, 0x65, 0x22, 0x99, 0x01, 0x0a, 0x13, 0x4d, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x46, 0x75, + 0x6e, 0x64, 0x73, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x30, 0x0a, 0x13, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x48, 0x61, + 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x48, 0x61, 0x73, 0x68, 0x12, 0x24, 0x0a, + 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6d, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x46, 0x75, 0x6e, + 0x64, 0x73, 0x54, 0x78, 0x46, 0x65, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x6d, + 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x46, 0x75, 0x6e, 0x64, 0x73, 0x54, 0x78, 0x46, 0x65, 0x65, 0x42, + 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -523,7 +595,7 @@ func file_pkg_tbtc_gen_pb_message_proto_rawDescGZIP() []byte { return file_pkg_tbtc_gen_pb_message_proto_rawDescData } -var file_pkg_tbtc_gen_pb_message_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_pkg_tbtc_gen_pb_message_proto_msgTypes = make([]protoimpl.MessageInfo, 8) var file_pkg_tbtc_gen_pb_message_proto_goTypes = []interface{}{ (*SigningDoneMessage)(nil), // 0: tbtc.SigningDoneMessage (*CoordinationProposal)(nil), // 1: tbtc.CoordinationProposal @@ -531,11 +603,12 @@ var file_pkg_tbtc_gen_pb_message_proto_goTypes = []interface{}{ (*HeartbeatProposal)(nil), // 3: tbtc.HeartbeatProposal (*DepositSweepProposal)(nil), // 4: tbtc.DepositSweepProposal (*RedemptionProposal)(nil), // 5: tbtc.RedemptionProposal - (*DepositSweepProposal_DepositKey)(nil), // 6: tbtc.DepositSweepProposal.DepositKey + (*MovingFundsProposal)(nil), // 6: tbtc.MovingFundsProposal + (*DepositSweepProposal_DepositKey)(nil), // 7: tbtc.DepositSweepProposal.DepositKey } var file_pkg_tbtc_gen_pb_message_proto_depIdxs = []int32{ 1, // 0: tbtc.CoordinationMessage.proposal:type_name -> tbtc.CoordinationProposal - 6, // 1: tbtc.DepositSweepProposal.depositsKeys:type_name -> tbtc.DepositSweepProposal.DepositKey + 7, // 1: tbtc.DepositSweepProposal.depositsKeys:type_name -> tbtc.DepositSweepProposal.DepositKey 2, // [2:2] is the sub-list for method output_type 2, // [2:2] is the sub-list for method input_type 2, // [2:2] is the sub-list for extension type_name @@ -622,6 +695,18 @@ func file_pkg_tbtc_gen_pb_message_proto_init() { } } file_pkg_tbtc_gen_pb_message_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MovingFundsProposal); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_tbtc_gen_pb_message_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DepositSweepProposal_DepositKey); i { case 0: return &v.state @@ -640,7 +725,7 @@ func file_pkg_tbtc_gen_pb_message_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_pkg_tbtc_gen_pb_message_proto_rawDesc, NumEnums: 0, - NumMessages: 7, + NumMessages: 8, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/tbtc/gen/pb/message.proto b/pkg/tbtc/gen/pb/message.proto index 1da799a18f..beba80ea45 100644 --- a/pkg/tbtc/gen/pb/message.proto +++ b/pkg/tbtc/gen/pb/message.proto @@ -41,4 +41,10 @@ message DepositSweepProposal { message RedemptionProposal { repeated bytes redeemersOutputScripts = 1; bytes redemptionTxFee = 2; -} \ No newline at end of file +} + +message MovingFundsProposal { + bytes walletPublicKeyHash = 1; + repeated bytes targetWallets = 2; + bytes movingFundsTxFee = 3; +} diff --git a/pkg/tbtc/marshaling.go b/pkg/tbtc/marshaling.go index 587cb4269b..6c970a1e37 100644 --- a/pkg/tbtc/marshaling.go +++ b/pkg/tbtc/marshaling.go @@ -398,13 +398,38 @@ func (rp *RedemptionProposal) Unmarshal(bytes []byte) error { // Marshal converts the movingFundsProposal to a byte array. func (mfp *MovingFundsProposal) Marshal() ([]byte, error) { - // TODO: Implement - return nil, nil + targetWallets := make([][]byte, len(mfp.TargetWallets)) + + for i, wallet := range mfp.TargetWallets { + targetWallet := make([]byte, len(wallet)) + copy(targetWallet, wallet[:]) + + targetWallets[i] = targetWallet + } + + return proto.Marshal( + &pb.MovingFundsProposal{ + WalletPublicKeyHash: mfp.WalletPublicKeyHash[:], + TargetWallets: targetWallets, + MovingFundsTxFee: mfp.MovingFundsTxFee.Bytes(), + }) } // Unmarshal converts a byte array back to the movingFundsProposal. -func (mfp *MovingFundsProposal) Unmarshal(bytes []byte) error { - // TODO: Implement +func (mfp *MovingFundsProposal) Unmarshal(data []byte) error { + pbMsg := pb.MovingFundsProposal{} + if err := proto.Unmarshal(data, &pbMsg); err != nil { + return fmt.Errorf("failed to unmarshal MovingFundsProposal: [%v]", err) + } + + copy(mfp.WalletPublicKeyHash[:], pbMsg.WalletPublicKeyHash) + + mfp.TargetWallets = make([][20]byte, len(pbMsg.TargetWallets)) + for i, wallet := range pbMsg.TargetWallets { + copy(mfp.TargetWallets[i][:], wallet) + } + + mfp.MovingFundsTxFee = new(big.Int).SetBytes(pbMsg.MovingFundsTxFee) return nil } diff --git a/pkg/tbtc/marshaling_test.go b/pkg/tbtc/marshaling_test.go index 9092eb2ef4..c686f30a1c 100644 --- a/pkg/tbtc/marshaling_test.go +++ b/pkg/tbtc/marshaling_test.go @@ -4,11 +4,12 @@ import ( "crypto/ecdsa" "crypto/elliptic" "encoding/hex" - "github.com/keep-network/keep-core/pkg/bitcoin" "math/big" "reflect" "testing" + "github.com/keep-network/keep-core/pkg/bitcoin" + fuzz "github.com/google/gofuzz" "github.com/keep-network/keep-core/internal/testutils" @@ -126,6 +127,21 @@ func TestCoordinationMessage_MarshalingRoundtrip(t *testing.T) { return parsed } + toByte20 := func(s string) [20]byte { + bytes, err := hex.DecodeString(s) + if err != nil { + t.Fatal(err) + } + + if len(bytes) != 20 { + t.Fatal("incorrect hexstring length") + } + + var result [20]byte + copy(result[:], bytes[:]) + return result + } + tests := map[string]struct { proposal CoordinationProposal }{ @@ -168,23 +184,25 @@ func TestCoordinationMessage_MarshalingRoundtrip(t *testing.T) { RedemptionTxFee: big.NewInt(10000), }, }, - // TODO: Uncomment when moving funds support is implemented. - // "with moving funds proposal": { - // proposal: &MovingFundsProposal{}, - // }, + "with moving funds proposal": { + proposal: &MovingFundsProposal{ + WalletPublicKeyHash: toByte20( + "da7c1fb602db1931a3b815563b6f6fae6a58f224", + ), + TargetWallets: [][20]byte{ + toByte20("cb7d88a87c37aff0c1535fa4efe6f0a2406ea5e9"), + toByte20("f87eb7ec3b15a3fdd7b57754d765694b3e0b4bf4"), + }, + MovingFundsTxFee: big.NewInt(10000), + }, + }, + // TODO: Uncomment when moved funds sweep support is implemented. // "with moved funds sweep proposal": { // proposal: &MovedFundsSweepProposal{}, // }, } - walletPublicKeyHashBytes, err := hex.DecodeString( - "aa768412ceed10bd423c025542ca90071f9fb62d", - ) - if err != nil { - t.Fatal(err) - } - var walletPublicKeyHash [20]byte - copy(walletPublicKeyHash[:], walletPublicKeyHashBytes) + walletPublicKeyHash := toByte20("aa768412ceed10bd423c025542ca90071f9fb62d") for testName, test := range tests { t.Run(testName, func(t *testing.T) { @@ -295,6 +313,35 @@ func TestFuzzCoordinationMessage_MarshalingRoundtrip_WithRedemptionProposal(t *t } } +func TestFuzzCoordinationMessage_MarshalingRoundtrip_WithMovingFundsProposal(t *testing.T) { + for i := 0; i < 10; i++ { + var ( + senderID group.MemberIndex + coordinationBlock uint64 + walletPublicKeyHash [20]byte + proposal MovingFundsProposal + ) + + f := fuzz.New().NilChance(0.1). + NumElements(0, 512). + Funcs(pbutils.FuzzFuncs()...) + + f.Fuzz(&senderID) + f.Fuzz(&coordinationBlock) + f.Fuzz(&walletPublicKeyHash) + f.Fuzz(&proposal) + + doneMessage := &coordinationMessage{ + senderID: senderID, + coordinationBlock: coordinationBlock, + walletPublicKeyHash: walletPublicKeyHash, + proposal: &proposal, + } + + _ = pbutils.RoundTrip(doneMessage, &coordinationMessage{}) + } +} + func TestFuzzCoordinationMessage_MarshalingRoundtrip_WithNoopProposal(t *testing.T) { for i := 0; i < 10; i++ { var ( diff --git a/pkg/tbtc/moving_funds.go b/pkg/tbtc/moving_funds.go index 6a776211a6..b2658de17c 100644 --- a/pkg/tbtc/moving_funds.go +++ b/pkg/tbtc/moving_funds.go @@ -1,6 +1,8 @@ package tbtc import ( + "math/big" + "github.com/ipfs/go-log/v2" "github.com/keep-network/keep-core/pkg/bitcoin" @@ -18,6 +20,7 @@ type MovingFundsProposal struct { // TODO: Remove WalletPublicKeyHash field. WalletPublicKeyHash [20]byte TargetWallets [][20]byte + MovingFundsTxFee *big.Int } func (mfp *MovingFundsProposal) ActionType() WalletActionType {