From c183f992449e588849b02e31097a7a5e91174c40 Mon Sep 17 00:00:00 2001 From: Louis Singer <41042567+louisinger@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:32:35 +0200 Subject: [PATCH] Make the round participants sign the vtxo tree (#271) * [proto] add APIs to send and receive musig2 signing data * [common] add serialization functions for nonces and signatures * [application] implements tree signing * fix: remove old debug logs * [proto] cleaning * [common] fix musig2.go * [application] fixes and logs * [interface] fix: stop forwarding 2 times the events * [client] add musig2 support + sign the tree when joining a round * [interface] add new APIs into permissions.go * [application][proto] rework PingResponse (return all events type) * [common] split SetKeys into 2 distinct methods * [client] fixes according to musig2.go changes * [sdk] support tree signing + new PingResponse * [sdk] fixes * [application] revert event channel type * [application] use domain.RoundEvent as lastEvent type * [application] remove IsCovenantLess * comments * [application] revert roundAborted changes * [interface] remove bitcointree dependencie --- .../swagger/ark/v1/service.swagger.json | 159 +- api-spec/protobuf/ark/v1/service.proto | 55 +- api-spec/protobuf/gen/ark/v1/service.pb.go | 1387 ++++++++++++----- api-spec/protobuf/gen/ark/v1/service.pb.gw.go | 154 ++ .../protobuf/gen/ark/v1/service_grpc.pb.go | 74 +- client/covenantless/claim.go | 18 +- client/covenantless/client.go | 144 ++ client/covenantless/onboard.go | 6 +- client/covenantless/redeem.go | 13 +- common/bitcointree/musig2.go | 236 ++- common/bitcointree/musig2_test.go | 55 + pkg/client-sdk/Makefile | 2 +- pkg/client-sdk/client/client.go | 27 +- pkg/client-sdk/client/grpc/client.go | 139 +- pkg/client-sdk/client/rest/client.go | 181 ++- .../ark_service/ark_service_client.go | 80 +- ...ark_service_send_tree_nonces_parameters.go | 150 ++ .../ark_service_send_tree_nonces_responses.go | 185 +++ ...service_send_tree_signatures_parameters.go | 150 ++ ..._service_send_tree_signatures_responses.go | 185 +++ .../models/v1_get_event_stream_response.go | 104 +- .../rest/service/models/v1_ping_response.go | 237 ++- .../models/v1_register_payment_request.go | 3 + .../service/models/v1_round_signing_event.go | 115 ++ ...v1_round_signing_nonces_generated_event.go | 53 + .../models/v1_send_tree_nonces_request.go | 56 + .../models/v1_send_tree_nonces_response.go | 11 + .../models/v1_send_tree_signatures_request.go | 56 + .../v1_send_tree_signatures_response.go | 11 + pkg/client-sdk/covenant_client.go | 4 +- pkg/client-sdk/covenantless_client.go | 134 +- server/internal/core/application/covenant.go | 41 +- .../internal/core/application/covenantless.go | 322 +++- .../core/application/covenantless_event.go | 43 + server/internal/core/application/sweeper.go | 1 - server/internal/core/application/types.go | 12 +- server/internal/core/application/utils.go | 41 +- server/internal/core/domain/events.go | 12 +- .../interface/grpc/handlers/arkservice.go | 192 ++- .../interface/grpc/permissions/permissions.go | 8 + 40 files changed, 4143 insertions(+), 713 deletions(-) create mode 100644 pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_nonces_parameters.go create mode 100644 pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_nonces_responses.go create mode 100644 pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_signatures_parameters.go create mode 100644 pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_signatures_responses.go create mode 100644 pkg/client-sdk/client/rest/service/models/v1_round_signing_event.go create mode 100644 pkg/client-sdk/client/rest/service/models/v1_round_signing_nonces_generated_event.go create mode 100644 pkg/client-sdk/client/rest/service/models/v1_send_tree_nonces_request.go create mode 100644 pkg/client-sdk/client/rest/service/models/v1_send_tree_nonces_response.go create mode 100644 pkg/client-sdk/client/rest/service/models/v1_send_tree_signatures_request.go create mode 100644 pkg/client-sdk/client/rest/service/models/v1_send_tree_signatures_response.go create mode 100644 server/internal/core/application/covenantless_event.go diff --git a/api-spec/openapi/swagger/ark/v1/service.swagger.json b/api-spec/openapi/swagger/ark/v1/service.swagger.json index 5c94faa..775531e 100644 --- a/api-spec/openapi/swagger/ark/v1/service.swagger.json +++ b/api-spec/openapi/swagger/ark/v1/service.swagger.json @@ -261,6 +261,70 @@ ] } }, + "/v1/payment/tree/nonces": { + "post": { + "operationId": "ArkService_SendTreeNonces", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1SendTreeNoncesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1SendTreeNoncesRequest" + } + } + ], + "tags": [ + "ArkService" + ] + } + }, + "/v1/payment/tree/signatures": { + "post": { + "operationId": "ArkService_SendTreeSignatures", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1SendTreeSignaturesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1SendTreeSignaturesRequest" + } + } + ], + "tags": [ + "ArkService" + ] + } + }, "/v1/ping/{paymentId}": { "get": { "operationId": "ArkService_Ping", @@ -323,7 +387,6 @@ }, "/v1/round/{txid}": { "get": { - "summary": "TODO BTC: signTree rpc", "operationId": "ArkService_GetRound", "responses": { "200": { @@ -502,14 +565,19 @@ "type": "object", "properties": { "roundFinalization": { - "$ref": "#/definitions/v1RoundFinalizationEvent", - "title": "TODO: BTC add \"signTree\" event" + "$ref": "#/definitions/v1RoundFinalizationEvent" }, "roundFinalized": { "$ref": "#/definitions/v1RoundFinalizedEvent" }, "roundFailed": { "$ref": "#/definitions/v1RoundFailed" + }, + "roundSigning": { + "$ref": "#/definitions/v1RoundSigningEvent" + }, + "roundSigningNoncesGenerated": { + "$ref": "#/definitions/v1RoundSigningNoncesGeneratedEvent" } } }, @@ -649,14 +717,20 @@ "v1PingResponse": { "type": "object", "properties": { - "forfeitTxs": { - "type": "array", - "items": { - "type": "string" - } - }, - "event": { + "roundFinalization": { "$ref": "#/definitions/v1RoundFinalizationEvent" + }, + "roundFinalized": { + "$ref": "#/definitions/v1RoundFinalizedEvent" + }, + "roundFailed": { + "$ref": "#/definitions/v1RoundFailed" + }, + "roundSigning": { + "$ref": "#/definitions/v1RoundSigningEvent" + }, + "roundSigningNoncesGenerated": { + "$ref": "#/definitions/v1RoundSigningNoncesGeneratedEvent" } } }, @@ -669,6 +743,9 @@ "type": "object", "$ref": "#/definitions/v1Input" } + }, + "ephemeralPubkey": { + "type": "string" } } }, @@ -766,6 +843,34 @@ } } }, + "v1RoundSigningEvent": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "cosignersPubkeys": { + "type": "array", + "items": { + "type": "string" + } + }, + "unsignedTree": { + "$ref": "#/definitions/v1Tree" + } + } + }, + "v1RoundSigningNoncesGeneratedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "treeNonces": { + "type": "string" + } + } + }, "v1RoundStage": { "type": "string", "enum": [ @@ -777,6 +882,40 @@ ], "default": "ROUND_STAGE_UNSPECIFIED" }, + "v1SendTreeNoncesRequest": { + "type": "object", + "properties": { + "roundId": { + "type": "string" + }, + "publicKey": { + "type": "string" + }, + "treeNonces": { + "type": "string" + } + } + }, + "v1SendTreeNoncesResponse": { + "type": "object" + }, + "v1SendTreeSignaturesRequest": { + "type": "object", + "properties": { + "roundId": { + "type": "string" + }, + "publicKey": { + "type": "string" + }, + "treeSignatures": { + "type": "string" + } + } + }, + "v1SendTreeSignaturesResponse": { + "type": "object" + }, "v1Tree": { "type": "object", "properties": { diff --git a/api-spec/protobuf/ark/v1/service.proto b/api-spec/protobuf/ark/v1/service.proto index 548ea55..65a926a 100755 --- a/api-spec/protobuf/ark/v1/service.proto +++ b/api-spec/protobuf/ark/v1/service.proto @@ -17,13 +17,24 @@ service ArkService { body: "*" }; }; + rpc SendTreeNonces(SendTreeNoncesRequest) returns (SendTreeNoncesResponse) { + option (google.api.http) = { + post: "/v1/payment/tree/nonces" + body: "*" + }; + } + rpc SendTreeSignatures(SendTreeSignaturesRequest) returns (SendTreeSignaturesResponse) { + option (google.api.http) = { + post: "/v1/payment/tree/signatures" + body: "*" + }; + } rpc FinalizePayment(FinalizePaymentRequest) returns (FinalizePaymentResponse) { option (google.api.http) = { post: "/v1/payment/finalize" body: "*" }; }; - // TODO BTC: signTree rpc rpc GetRound(GetRoundRequest) returns (GetRoundResponse) { option (google.api.http) = { get: "/v1/round/{txid}" @@ -91,6 +102,7 @@ message CompletePaymentResponse {} message RegisterPaymentRequest { repeated Input inputs = 1; + optional string ephemeral_pubkey = 2; } message RegisterPaymentResponse { // Mocks wabisabi's credentials. @@ -128,10 +140,11 @@ message GetRoundByIdResponse { message GetEventStreamRequest {} message GetEventStreamResponse { oneof event { - // TODO: BTC add "signTree" event RoundFinalizationEvent round_finalization = 1; RoundFinalizedEvent round_finalized = 2; RoundFailed round_failed = 3; + RoundSigningEvent round_signing = 4; + RoundSigningNoncesGeneratedEvent round_signing_nonces_generated = 5; } } @@ -139,8 +152,13 @@ message PingRequest { string payment_id = 1; } message PingResponse { - repeated string forfeit_txs = 1; - RoundFinalizationEvent event = 2; + oneof event { + RoundFinalizationEvent round_finalization = 1; + RoundFinalizedEvent round_finalized = 2; + RoundFailed round_failed = 3; + RoundSigningEvent round_signing = 4; + RoundSigningNoncesGeneratedEvent round_signing_nonces_generated = 5; + } } message ListVtxosRequest { @@ -189,6 +207,17 @@ message RoundFailed { string reason = 2; } +message RoundSigningEvent { + string id = 1; + repeated string cosigners_pubkeys = 2; + Tree unsigned_tree = 3; +} + +message RoundSigningNoncesGeneratedEvent { + string id = 1; + string tree_nonces = 2; +} + // TYPES enum RoundStage { @@ -251,4 +280,20 @@ message Vtxo { message PendingPayment { string redeem_tx = 1; repeated string unconditional_forfeit_txs =2; -} \ No newline at end of file +} + +message SendTreeNoncesRequest { + string round_id = 1; + string public_key = 2; + string tree_nonces = 3; +} + +message SendTreeNoncesResponse {} + +message SendTreeSignaturesRequest { + string round_id = 1; + string public_key = 2; + string tree_signatures = 3; +} + +message SendTreeSignaturesResponse {} \ No newline at end of file diff --git a/api-spec/protobuf/gen/ark/v1/service.pb.go b/api-spec/protobuf/gen/ark/v1/service.pb.go index af9e91f..de8e03d 100644 --- a/api-spec/protobuf/gen/ark/v1/service.pb.go +++ b/api-spec/protobuf/gen/ark/v1/service.pb.go @@ -284,7 +284,8 @@ type RegisterPaymentRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Inputs []*Input `protobuf:"bytes,1,rep,name=inputs,proto3" json:"inputs,omitempty"` + Inputs []*Input `protobuf:"bytes,1,rep,name=inputs,proto3" json:"inputs,omitempty"` + EphemeralPubkey *string `protobuf:"bytes,2,opt,name=ephemeral_pubkey,json=ephemeralPubkey,proto3,oneof" json:"ephemeral_pubkey,omitempty"` } func (x *RegisterPaymentRequest) Reset() { @@ -326,6 +327,13 @@ func (x *RegisterPaymentRequest) GetInputs() []*Input { return nil } +func (x *RegisterPaymentRequest) GetEphemeralPubkey() string { + if x != nil && x.EphemeralPubkey != nil { + return *x.EphemeralPubkey + } + return "" +} + type RegisterPaymentResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -791,6 +799,8 @@ type GetEventStreamResponse struct { // *GetEventStreamResponse_RoundFinalization // *GetEventStreamResponse_RoundFinalized // *GetEventStreamResponse_RoundFailed + // *GetEventStreamResponse_RoundSigning + // *GetEventStreamResponse_RoundSigningNoncesGenerated Event isGetEventStreamResponse_Event `protobuf_oneof:"event"` } @@ -854,12 +864,25 @@ func (x *GetEventStreamResponse) GetRoundFailed() *RoundFailed { return nil } +func (x *GetEventStreamResponse) GetRoundSigning() *RoundSigningEvent { + if x, ok := x.GetEvent().(*GetEventStreamResponse_RoundSigning); ok { + return x.RoundSigning + } + return nil +} + +func (x *GetEventStreamResponse) GetRoundSigningNoncesGenerated() *RoundSigningNoncesGeneratedEvent { + if x, ok := x.GetEvent().(*GetEventStreamResponse_RoundSigningNoncesGenerated); ok { + return x.RoundSigningNoncesGenerated + } + return nil +} + type isGetEventStreamResponse_Event interface { isGetEventStreamResponse_Event() } type GetEventStreamResponse_RoundFinalization struct { - // TODO: BTC add "signTree" event RoundFinalization *RoundFinalizationEvent `protobuf:"bytes,1,opt,name=round_finalization,json=roundFinalization,proto3,oneof"` } @@ -871,12 +894,24 @@ type GetEventStreamResponse_RoundFailed struct { RoundFailed *RoundFailed `protobuf:"bytes,3,opt,name=round_failed,json=roundFailed,proto3,oneof"` } +type GetEventStreamResponse_RoundSigning struct { + RoundSigning *RoundSigningEvent `protobuf:"bytes,4,opt,name=round_signing,json=roundSigning,proto3,oneof"` +} + +type GetEventStreamResponse_RoundSigningNoncesGenerated struct { + RoundSigningNoncesGenerated *RoundSigningNoncesGeneratedEvent `protobuf:"bytes,5,opt,name=round_signing_nonces_generated,json=roundSigningNoncesGenerated,proto3,oneof"` +} + func (*GetEventStreamResponse_RoundFinalization) isGetEventStreamResponse_Event() {} func (*GetEventStreamResponse_RoundFinalized) isGetEventStreamResponse_Event() {} func (*GetEventStreamResponse_RoundFailed) isGetEventStreamResponse_Event() {} +func (*GetEventStreamResponse_RoundSigning) isGetEventStreamResponse_Event() {} + +func (*GetEventStreamResponse_RoundSigningNoncesGenerated) isGetEventStreamResponse_Event() {} + type PingRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -929,8 +964,14 @@ type PingResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ForfeitTxs []string `protobuf:"bytes,1,rep,name=forfeit_txs,json=forfeitTxs,proto3" json:"forfeit_txs,omitempty"` - Event *RoundFinalizationEvent `protobuf:"bytes,2,opt,name=event,proto3" json:"event,omitempty"` + // Types that are assignable to Event: + // + // *PingResponse_RoundFinalization + // *PingResponse_RoundFinalized + // *PingResponse_RoundFailed + // *PingResponse_RoundSigning + // *PingResponse_RoundSigningNoncesGenerated + Event isPingResponse_Event `protobuf_oneof:"event"` } func (x *PingResponse) Reset() { @@ -965,20 +1006,82 @@ func (*PingResponse) Descriptor() ([]byte, []int) { return file_ark_v1_service_proto_rawDescGZIP(), []int{17} } -func (x *PingResponse) GetForfeitTxs() []string { - if x != nil { - return x.ForfeitTxs +func (m *PingResponse) GetEvent() isPingResponse_Event { + if m != nil { + return m.Event } return nil } -func (x *PingResponse) GetEvent() *RoundFinalizationEvent { - if x != nil { - return x.Event +func (x *PingResponse) GetRoundFinalization() *RoundFinalizationEvent { + if x, ok := x.GetEvent().(*PingResponse_RoundFinalization); ok { + return x.RoundFinalization } return nil } +func (x *PingResponse) GetRoundFinalized() *RoundFinalizedEvent { + if x, ok := x.GetEvent().(*PingResponse_RoundFinalized); ok { + return x.RoundFinalized + } + return nil +} + +func (x *PingResponse) GetRoundFailed() *RoundFailed { + if x, ok := x.GetEvent().(*PingResponse_RoundFailed); ok { + return x.RoundFailed + } + return nil +} + +func (x *PingResponse) GetRoundSigning() *RoundSigningEvent { + if x, ok := x.GetEvent().(*PingResponse_RoundSigning); ok { + return x.RoundSigning + } + return nil +} + +func (x *PingResponse) GetRoundSigningNoncesGenerated() *RoundSigningNoncesGeneratedEvent { + if x, ok := x.GetEvent().(*PingResponse_RoundSigningNoncesGenerated); ok { + return x.RoundSigningNoncesGenerated + } + return nil +} + +type isPingResponse_Event interface { + isPingResponse_Event() +} + +type PingResponse_RoundFinalization struct { + RoundFinalization *RoundFinalizationEvent `protobuf:"bytes,1,opt,name=round_finalization,json=roundFinalization,proto3,oneof"` +} + +type PingResponse_RoundFinalized struct { + RoundFinalized *RoundFinalizedEvent `protobuf:"bytes,2,opt,name=round_finalized,json=roundFinalized,proto3,oneof"` +} + +type PingResponse_RoundFailed struct { + RoundFailed *RoundFailed `protobuf:"bytes,3,opt,name=round_failed,json=roundFailed,proto3,oneof"` +} + +type PingResponse_RoundSigning struct { + RoundSigning *RoundSigningEvent `protobuf:"bytes,4,opt,name=round_signing,json=roundSigning,proto3,oneof"` +} + +type PingResponse_RoundSigningNoncesGenerated struct { + RoundSigningNoncesGenerated *RoundSigningNoncesGeneratedEvent `protobuf:"bytes,5,opt,name=round_signing_nonces_generated,json=roundSigningNoncesGenerated,proto3,oneof"` +} + +func (*PingResponse_RoundFinalization) isPingResponse_Event() {} + +func (*PingResponse_RoundFinalized) isPingResponse_Event() {} + +func (*PingResponse_RoundFailed) isPingResponse_Event() {} + +func (*PingResponse_RoundSigning) isPingResponse_Event() {} + +func (*PingResponse_RoundSigningNoncesGenerated) isPingResponse_Event() {} + type ListVtxosRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1496,6 +1599,124 @@ func (x *RoundFailed) GetReason() string { return "" } +type RoundSigningEvent struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + CosignersPubkeys []string `protobuf:"bytes,2,rep,name=cosigners_pubkeys,json=cosignersPubkeys,proto3" json:"cosigners_pubkeys,omitempty"` + UnsignedTree *Tree `protobuf:"bytes,3,opt,name=unsigned_tree,json=unsignedTree,proto3" json:"unsigned_tree,omitempty"` +} + +func (x *RoundSigningEvent) Reset() { + *x = RoundSigningEvent{} + if protoimpl.UnsafeEnabled { + mi := &file_ark_v1_service_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RoundSigningEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RoundSigningEvent) ProtoMessage() {} + +func (x *RoundSigningEvent) ProtoReflect() protoreflect.Message { + mi := &file_ark_v1_service_proto_msgTypes[27] + 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 RoundSigningEvent.ProtoReflect.Descriptor instead. +func (*RoundSigningEvent) Descriptor() ([]byte, []int) { + return file_ark_v1_service_proto_rawDescGZIP(), []int{27} +} + +func (x *RoundSigningEvent) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *RoundSigningEvent) GetCosignersPubkeys() []string { + if x != nil { + return x.CosignersPubkeys + } + return nil +} + +func (x *RoundSigningEvent) GetUnsignedTree() *Tree { + if x != nil { + return x.UnsignedTree + } + return nil +} + +type RoundSigningNoncesGeneratedEvent struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + TreeNonces string `protobuf:"bytes,2,opt,name=tree_nonces,json=treeNonces,proto3" json:"tree_nonces,omitempty"` +} + +func (x *RoundSigningNoncesGeneratedEvent) Reset() { + *x = RoundSigningNoncesGeneratedEvent{} + if protoimpl.UnsafeEnabled { + mi := &file_ark_v1_service_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RoundSigningNoncesGeneratedEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RoundSigningNoncesGeneratedEvent) ProtoMessage() {} + +func (x *RoundSigningNoncesGeneratedEvent) ProtoReflect() protoreflect.Message { + mi := &file_ark_v1_service_proto_msgTypes[28] + 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 RoundSigningNoncesGeneratedEvent.ProtoReflect.Descriptor instead. +func (*RoundSigningNoncesGeneratedEvent) Descriptor() ([]byte, []int) { + return file_ark_v1_service_proto_rawDescGZIP(), []int{28} +} + +func (x *RoundSigningNoncesGeneratedEvent) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *RoundSigningNoncesGeneratedEvent) GetTreeNonces() string { + if x != nil { + return x.TreeNonces + } + return "" +} + type Round struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1514,7 +1735,7 @@ type Round struct { func (x *Round) Reset() { *x = Round{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[27] + mi := &file_ark_v1_service_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1527,7 +1748,7 @@ func (x *Round) String() string { func (*Round) ProtoMessage() {} func (x *Round) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[27] + mi := &file_ark_v1_service_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1540,7 +1761,7 @@ func (x *Round) ProtoReflect() protoreflect.Message { // Deprecated: Use Round.ProtoReflect.Descriptor instead. func (*Round) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{27} + return file_ark_v1_service_proto_rawDescGZIP(), []int{29} } func (x *Round) GetId() string { @@ -1611,7 +1832,7 @@ type Input struct { func (x *Input) Reset() { *x = Input{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[28] + mi := &file_ark_v1_service_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1624,7 +1845,7 @@ func (x *Input) String() string { func (*Input) ProtoMessage() {} func (x *Input) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[28] + mi := &file_ark_v1_service_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1637,7 +1858,7 @@ func (x *Input) ProtoReflect() protoreflect.Message { // Deprecated: Use Input.ProtoReflect.Descriptor instead. func (*Input) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{28} + return file_ark_v1_service_proto_rawDescGZIP(), []int{30} } func (x *Input) GetTxid() string { @@ -1668,7 +1889,7 @@ type Output struct { func (x *Output) Reset() { *x = Output{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[29] + mi := &file_ark_v1_service_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1681,7 +1902,7 @@ func (x *Output) String() string { func (*Output) ProtoMessage() {} func (x *Output) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[29] + mi := &file_ark_v1_service_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1694,7 +1915,7 @@ func (x *Output) ProtoReflect() protoreflect.Message { // Deprecated: Use Output.ProtoReflect.Descriptor instead. func (*Output) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{29} + return file_ark_v1_service_proto_rawDescGZIP(), []int{31} } func (x *Output) GetAddress() string { @@ -1722,7 +1943,7 @@ type Tree struct { func (x *Tree) Reset() { *x = Tree{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[30] + mi := &file_ark_v1_service_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1735,7 +1956,7 @@ func (x *Tree) String() string { func (*Tree) ProtoMessage() {} func (x *Tree) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[30] + mi := &file_ark_v1_service_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1748,7 +1969,7 @@ func (x *Tree) ProtoReflect() protoreflect.Message { // Deprecated: Use Tree.ProtoReflect.Descriptor instead. func (*Tree) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{30} + return file_ark_v1_service_proto_rawDescGZIP(), []int{32} } func (x *Tree) GetLevels() []*TreeLevel { @@ -1769,7 +1990,7 @@ type TreeLevel struct { func (x *TreeLevel) Reset() { *x = TreeLevel{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[31] + mi := &file_ark_v1_service_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1782,7 +2003,7 @@ func (x *TreeLevel) String() string { func (*TreeLevel) ProtoMessage() {} func (x *TreeLevel) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[31] + mi := &file_ark_v1_service_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1795,7 +2016,7 @@ func (x *TreeLevel) ProtoReflect() protoreflect.Message { // Deprecated: Use TreeLevel.ProtoReflect.Descriptor instead. func (*TreeLevel) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{31} + return file_ark_v1_service_proto_rawDescGZIP(), []int{33} } func (x *TreeLevel) GetNodes() []*Node { @@ -1818,7 +2039,7 @@ type Node struct { func (x *Node) Reset() { *x = Node{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[32] + mi := &file_ark_v1_service_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1831,7 +2052,7 @@ func (x *Node) String() string { func (*Node) ProtoMessage() {} func (x *Node) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[32] + mi := &file_ark_v1_service_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1844,7 +2065,7 @@ func (x *Node) ProtoReflect() protoreflect.Message { // Deprecated: Use Node.ProtoReflect.Descriptor instead. func (*Node) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{32} + return file_ark_v1_service_proto_rawDescGZIP(), []int{34} } func (x *Node) GetTxid() string { @@ -1887,7 +2108,7 @@ type Vtxo struct { func (x *Vtxo) Reset() { *x = Vtxo{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[33] + mi := &file_ark_v1_service_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1900,7 +2121,7 @@ func (x *Vtxo) String() string { func (*Vtxo) ProtoMessage() {} func (x *Vtxo) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[33] + mi := &file_ark_v1_service_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1913,7 +2134,7 @@ func (x *Vtxo) ProtoReflect() protoreflect.Message { // Deprecated: Use Vtxo.ProtoReflect.Descriptor instead. func (*Vtxo) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{33} + return file_ark_v1_service_proto_rawDescGZIP(), []int{35} } func (x *Vtxo) GetOutpoint() *Input { @@ -1991,7 +2212,7 @@ type PendingPayment struct { func (x *PendingPayment) Reset() { *x = PendingPayment{} if protoimpl.UnsafeEnabled { - mi := &file_ark_v1_service_proto_msgTypes[34] + mi := &file_ark_v1_service_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2004,7 +2225,7 @@ func (x *PendingPayment) String() string { func (*PendingPayment) ProtoMessage() {} func (x *PendingPayment) ProtoReflect() protoreflect.Message { - mi := &file_ark_v1_service_proto_msgTypes[34] + mi := &file_ark_v1_service_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2017,7 +2238,7 @@ func (x *PendingPayment) ProtoReflect() protoreflect.Message { // Deprecated: Use PendingPayment.ProtoReflect.Descriptor instead. func (*PendingPayment) Descriptor() ([]byte, []int) { - return file_ark_v1_service_proto_rawDescGZIP(), []int{34} + return file_ark_v1_service_proto_rawDescGZIP(), []int{36} } func (x *PendingPayment) GetRedeemTx() string { @@ -2034,6 +2255,208 @@ func (x *PendingPayment) GetUnconditionalForfeitTxs() []string { return nil } +type SendTreeNoncesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RoundId string `protobuf:"bytes,1,opt,name=round_id,json=roundId,proto3" json:"round_id,omitempty"` + PublicKey string `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + TreeNonces string `protobuf:"bytes,3,opt,name=tree_nonces,json=treeNonces,proto3" json:"tree_nonces,omitempty"` +} + +func (x *SendTreeNoncesRequest) Reset() { + *x = SendTreeNoncesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_ark_v1_service_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SendTreeNoncesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendTreeNoncesRequest) ProtoMessage() {} + +func (x *SendTreeNoncesRequest) ProtoReflect() protoreflect.Message { + mi := &file_ark_v1_service_proto_msgTypes[37] + 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 SendTreeNoncesRequest.ProtoReflect.Descriptor instead. +func (*SendTreeNoncesRequest) Descriptor() ([]byte, []int) { + return file_ark_v1_service_proto_rawDescGZIP(), []int{37} +} + +func (x *SendTreeNoncesRequest) GetRoundId() string { + if x != nil { + return x.RoundId + } + return "" +} + +func (x *SendTreeNoncesRequest) GetPublicKey() string { + if x != nil { + return x.PublicKey + } + return "" +} + +func (x *SendTreeNoncesRequest) GetTreeNonces() string { + if x != nil { + return x.TreeNonces + } + return "" +} + +type SendTreeNoncesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SendTreeNoncesResponse) Reset() { + *x = SendTreeNoncesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ark_v1_service_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SendTreeNoncesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendTreeNoncesResponse) ProtoMessage() {} + +func (x *SendTreeNoncesResponse) ProtoReflect() protoreflect.Message { + mi := &file_ark_v1_service_proto_msgTypes[38] + 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 SendTreeNoncesResponse.ProtoReflect.Descriptor instead. +func (*SendTreeNoncesResponse) Descriptor() ([]byte, []int) { + return file_ark_v1_service_proto_rawDescGZIP(), []int{38} +} + +type SendTreeSignaturesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RoundId string `protobuf:"bytes,1,opt,name=round_id,json=roundId,proto3" json:"round_id,omitempty"` + PublicKey string `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + TreeSignatures string `protobuf:"bytes,3,opt,name=tree_signatures,json=treeSignatures,proto3" json:"tree_signatures,omitempty"` +} + +func (x *SendTreeSignaturesRequest) Reset() { + *x = SendTreeSignaturesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_ark_v1_service_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SendTreeSignaturesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendTreeSignaturesRequest) ProtoMessage() {} + +func (x *SendTreeSignaturesRequest) ProtoReflect() protoreflect.Message { + mi := &file_ark_v1_service_proto_msgTypes[39] + 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 SendTreeSignaturesRequest.ProtoReflect.Descriptor instead. +func (*SendTreeSignaturesRequest) Descriptor() ([]byte, []int) { + return file_ark_v1_service_proto_rawDescGZIP(), []int{39} +} + +func (x *SendTreeSignaturesRequest) GetRoundId() string { + if x != nil { + return x.RoundId + } + return "" +} + +func (x *SendTreeSignaturesRequest) GetPublicKey() string { + if x != nil { + return x.PublicKey + } + return "" +} + +func (x *SendTreeSignaturesRequest) GetTreeSignatures() string { + if x != nil { + return x.TreeSignatures + } + return "" +} + +type SendTreeSignaturesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SendTreeSignaturesResponse) Reset() { + *x = SendTreeSignaturesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ark_v1_service_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SendTreeSignaturesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendTreeSignaturesResponse) ProtoMessage() {} + +func (x *SendTreeSignaturesResponse) ProtoReflect() protoreflect.Message { + mi := &file_ark_v1_service_proto_msgTypes[40] + 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 SendTreeSignaturesResponse.ProtoReflect.Descriptor instead. +func (*SendTreeSignaturesResponse) Descriptor() ([]byte, []int) { + return file_ark_v1_service_proto_rawDescGZIP(), []int{40} +} + var File_ark_v1_service_proto protoreflect.FileDescriptor var file_ark_v1_service_proto_rawDesc = []byte{ @@ -2066,276 +2489,359 @@ var file_ark_v1_service_proto_rawDesc = []byte{ 0x03, 0x28, 0x09, 0x52, 0x1d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3f, 0x0a, - 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, - 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x22, 0x29, - 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x4f, 0x0a, 0x13, 0x43, 0x6c, 0x61, - 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x28, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x6c, - 0x61, 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x46, 0x0a, 0x16, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, - 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, - 0x78, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, - 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x46, 0x69, - 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x22, 0x37, 0x0a, 0x10, - 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x23, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x05, - 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x25, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, - 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, - 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, - 0x6e, 0x64, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x22, 0xf4, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, - 0x12, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, - 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x72, 0x6f, 0x75, - 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46, - 0x0a, 0x0f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, - 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x0c, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, - 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x61, - 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x61, 0x69, 0x6c, 0x65, - 0x64, 0x48, 0x00, 0x52, 0x0b, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, - 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x2c, 0x0a, 0x0b, 0x50, 0x69, 0x6e, - 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x65, 0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x67, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x72, 0x66, 0x65, - 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x6f, - 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x34, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x2c, - 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x79, 0x0a, 0x11, - 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x35, 0x0a, 0x0f, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, - 0x74, 0x78, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, - 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x74, 0x78, 0x6f, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, - 0x62, 0x6c, 0x65, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x2d, 0x0a, 0x0b, 0x73, 0x70, 0x65, 0x6e, - 0x74, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, - 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x74, 0x78, 0x6f, 0x52, 0x0a, 0x73, 0x70, 0x65, - 0x6e, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xe9, 0x01, 0x0a, 0x0f, 0x47, 0x65, - 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, - 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x6c, - 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, - 0x6f, 0x75, 0x6e, 0x64, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x15, - 0x75, 0x6e, 0x69, 0x6c, 0x61, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, - 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x75, 0x6e, 0x69, - 0x6c, 0x61, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x45, 0x78, 0x69, 0x74, 0x44, 0x65, 0x6c, 0x61, 0x79, - 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, - 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x66, - 0x65, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x6c, - 0x61, 0x79, 0x46, 0x65, 0x65, 0x22, 0x89, 0x01, 0x0a, 0x0e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6f, 0x61, 0x72, - 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, - 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, - 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, - 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, - 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, - 0x79, 0x22, 0x11, 0x0a, 0x0f, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xb9, 0x01, 0x0a, 0x16, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, - 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x17, 0x0a, 0x07, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x72, 0x66, - 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x66, - 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, - 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, - 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, - 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, - 0x22, 0x42, 0x0a, 0x13, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, - 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, - 0x74, 0x78, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x6f, 0x6c, - 0x54, 0x78, 0x69, 0x64, 0x22, 0x35, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x61, 0x69, - 0x6c, 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0xfa, 0x01, 0x0a, 0x05, - 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, - 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x17, 0x0a, - 0x07, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x74, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x52, 0x0e, 0x63, - 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, 0x12, 0x1f, 0x0a, - 0x0b, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x06, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0a, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x1e, - 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x07, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x28, - 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, - 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x67, - 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x22, 0x2f, 0x0a, 0x05, 0x49, 0x6e, 0x70, 0x75, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x76, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x04, 0x76, 0x6f, 0x75, 0x74, 0x22, 0x3a, 0x0a, 0x06, 0x4f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x31, 0x0a, 0x04, 0x54, 0x72, 0x65, 0x65, 0x12, 0x29, 0x0a, - 0x06, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, - 0x52, 0x06, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x73, 0x22, 0x2f, 0x0a, 0x09, 0x54, 0x72, 0x65, 0x65, - 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x22, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, - 0x64, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x4b, 0x0a, 0x04, 0x4e, 0x6f, 0x64, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x74, 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, - 0x74, 0x78, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x54, 0x78, 0x69, 0x64, 0x22, 0xb3, 0x02, 0x0a, 0x04, 0x56, 0x74, 0x78, 0x6f, 0x12, - 0x29, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, - 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x08, 0x72, 0x65, - 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, - 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x08, 0x72, 0x65, - 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, - 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x65, - 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x65, - 0x6e, 0x74, 0x42, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x61, - 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x77, 0x65, 0x70, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x05, 0x73, 0x77, 0x65, 0x70, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x12, 0x39, 0x0a, 0x0c, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, - 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, - 0x0b, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x22, 0x69, 0x0a, 0x0e, - 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1b, - 0x0a, 0x09, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x5f, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x12, 0x3a, 0x0a, 0x19, 0x75, - 0x6e, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x6f, 0x72, - 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, - 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x46, 0x6f, 0x72, - 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x2a, 0x98, 0x01, 0x0a, 0x0a, 0x52, 0x6f, 0x75, 0x6e, - 0x64, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, - 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, - 0x47, 0x45, 0x5f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, - 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, - 0x5f, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, - 0x19, 0x0a, 0x15, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, - 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x4f, - 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, - 0x10, 0x04, 0x32, 0xb3, 0x09, 0x0a, 0x0a, 0x41, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x73, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, - 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x72, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x67, 0x0a, 0x0c, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, - 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, 0x76, - 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x12, - 0x73, 0x0a, 0x0f, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x84, 0x01, + 0x0a, 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, + 0x31, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, + 0x2e, 0x0a, 0x10, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x62, + 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0f, 0x65, 0x70, 0x68, + 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x42, + 0x13, 0x0a, 0x11, 0x5f, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x70, 0x75, + 0x62, 0x6b, 0x65, 0x79, 0x22, 0x29, 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, + 0x4f, 0x0a, 0x13, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x28, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, + 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, + 0x22, 0x16, 0x0a, 0x14, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x46, 0x0a, 0x16, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x61, - 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, - 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x66, 0x69, 0x6e, 0x61, - 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x57, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, - 0x12, 0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, - 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, - 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x7b, 0x74, 0x78, 0x69, 0x64, 0x7d, 0x12, 0x64, 0x0a, - 0x0c, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x12, 0x1b, 0x2e, - 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, - 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x72, 0x6b, - 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, - 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x69, 0x64, 0x2f, 0x7b, - 0x69, 0x64, 0x7d, 0x12, 0x65, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, - 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, - 0x31, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x30, 0x01, 0x12, 0x50, 0x0a, 0x04, 0x50, 0x69, - 0x6e, 0x67, 0x12, 0x13, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, - 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x69, 0x6e, 0x67, 0x2f, - 0x7b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x5d, 0x0a, 0x09, - 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, - 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78, 0x6f, - 0x73, 0x2f, 0x7b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0x4c, 0x0a, 0x07, 0x47, - 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, - 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0a, 0x12, - 0x08, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x52, 0x0a, 0x07, 0x4f, 0x6e, 0x62, - 0x6f, 0x61, 0x72, 0x64, 0x12, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x6e, - 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, - 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, - 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x12, 0x64, 0x0a, - 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, - 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, - 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x12, 0x73, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, + 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x66, 0x6f, 0x72, + 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, + 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, + 0x22, 0x19, 0x0a, 0x17, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x0a, 0x0f, 0x47, + 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, + 0x69, 0x64, 0x22, 0x37, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x25, 0x0a, 0x13, 0x47, + 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, + 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x05, 0x72, 0x6f, + 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x22, + 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xa7, 0x03, 0x0a, 0x16, 0x47, 0x65, 0x74, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x12, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6e, + 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, + 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, + 0x00, 0x52, 0x11, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, 0x0f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x69, + 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, + 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x72, 0x6f, + 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x0c, + 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, + 0x64, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0b, 0x72, 0x6f, 0x75, 0x6e, 0x64, + 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12, 0x40, 0x0a, 0x0d, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, + 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x69, 0x67, 0x6e, + 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x72, 0x6f, 0x75, 0x6e, + 0x64, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x6f, 0x0a, 0x1e, 0x72, 0x6f, 0x75, 0x6e, + 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, + 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x28, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, + 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x47, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1b, 0x72, 0x6f, + 0x75, 0x6e, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, + 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x22, 0x2c, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, + 0x22, 0x9d, 0x03, 0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4f, 0x0a, 0x12, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, + 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, + 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, + 0x11, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x46, 0x0a, 0x0f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x61, + 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x72, + 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, + 0x7a, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x72, 0x6f, 0x75, 0x6e, + 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x0c, 0x72, 0x6f, + 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x13, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, + 0x61, 0x69, 0x6c, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0b, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x61, + 0x69, 0x6c, 0x65, 0x64, 0x12, 0x40, 0x0a, 0x0d, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x69, + 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x72, + 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, + 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x53, + 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x6f, 0x0a, 0x1e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, + 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x5f, 0x67, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, + 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x69, 0x67, + 0x6e, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1b, 0x72, 0x6f, 0x75, 0x6e, + 0x64, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x47, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x22, 0x2c, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x79, + 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x0f, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, + 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x74, 0x78, 0x6f, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, + 0x64, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x2d, 0x0a, 0x0b, 0x73, 0x70, + 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x74, 0x78, 0x6f, 0x52, 0x0a, 0x73, + 0x70, 0x65, 0x6e, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x47, 0x65, 0x74, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xe9, 0x01, 0x0a, 0x0f, + 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, + 0x5f, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0d, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x32, + 0x0a, 0x15, 0x75, 0x6e, 0x69, 0x6c, 0x61, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x69, + 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x75, + 0x6e, 0x69, 0x6c, 0x61, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x45, 0x78, 0x69, 0x74, 0x44, 0x65, 0x6c, + 0x61, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, 0x6f, 0x75, 0x6e, + 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, + 0x5f, 0x66, 0x65, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x46, 0x65, 0x65, 0x22, 0x89, 0x01, 0x0a, 0x0e, 0x4f, 0x6e, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x12, 0x35, 0x0a, 0x0f, 0x63, + 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, + 0x65, 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, + 0x65, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, + 0x6b, 0x65, 0x79, 0x22, 0x11, 0x0a, 0x0f, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xb9, 0x01, 0x0a, 0x16, 0x52, 0x6f, 0x75, 0x6e, 0x64, + 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, + 0x72, 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0a, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x35, 0x0a, 0x0f, 0x63, + 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, + 0x65, 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, + 0x65, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x73, 0x22, 0x42, 0x0a, 0x13, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, + 0x69, 0x7a, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6f, 0x6f, + 0x6c, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, + 0x6f, 0x6c, 0x54, 0x78, 0x69, 0x64, 0x22, 0x35, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, + 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x83, 0x01, + 0x0a, 0x11, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x63, 0x6f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x73, + 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, + 0x63, 0x6f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x73, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x73, + 0x12, 0x31, 0x0a, 0x0d, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x74, 0x72, 0x65, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, + 0x2e, 0x54, 0x72, 0x65, 0x65, 0x52, 0x0c, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, + 0x72, 0x65, 0x65, 0x22, 0x53, 0x0a, 0x20, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x69, 0x67, 0x6e, + 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x72, 0x65, 0x65, 0x5f, + 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x72, + 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x22, 0xfa, 0x01, 0x0a, 0x05, 0x52, 0x6f, 0x75, + 0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x6f, + 0x6f, 0x6c, 0x5f, 0x74, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x6f, + 0x6c, 0x54, 0x78, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, + 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x67, + 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, + 0x72, 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0a, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x28, 0x0a, 0x05, 0x73, + 0x74, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x61, 0x72, 0x6b, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x67, 0x65, 0x52, 0x05, + 0x73, 0x74, 0x61, 0x67, 0x65, 0x22, 0x2f, 0x0a, 0x05, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, + 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x76, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x04, 0x76, 0x6f, 0x75, 0x74, 0x22, 0x3a, 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x22, 0x31, 0x0a, 0x04, 0x54, 0x72, 0x65, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x6c, 0x65, + 0x76, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x61, 0x72, 0x6b, + 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x06, 0x6c, + 0x65, 0x76, 0x65, 0x6c, 0x73, 0x22, 0x2f, 0x0a, 0x09, 0x54, 0x72, 0x65, 0x65, 0x4c, 0x65, 0x76, + 0x65, 0x6c, 0x12, 0x22, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, + 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x4b, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, + 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x74, 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x78, 0x69, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x54, + 0x78, 0x69, 0x64, 0x22, 0xb3, 0x02, 0x0a, 0x04, 0x56, 0x74, 0x78, 0x6f, 0x12, 0x29, 0x0a, 0x08, + 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, + 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x08, 0x6f, + 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, + 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, + 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, + 0x76, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x05, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6f, 0x6f, + 0x6c, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, + 0x6f, 0x6c, 0x54, 0x78, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x5f, + 0x62, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x42, + 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x61, 0x74, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x74, 0x12, 0x14, + 0x0a, 0x05, 0x73, 0x77, 0x65, 0x70, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x73, + 0x77, 0x65, 0x70, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x39, + 0x0a, 0x0c, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x70, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x22, 0x69, 0x0a, 0x0e, 0x50, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, + 0x65, 0x64, 0x65, 0x65, 0x6d, 0x5f, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x12, 0x3a, 0x0a, 0x19, 0x75, 0x6e, 0x63, 0x6f, + 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, + 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x75, 0x6e, 0x63, + 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, + 0x74, 0x54, 0x78, 0x73, 0x22, 0x72, 0x0a, 0x15, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x72, 0x65, 0x65, + 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, + 0x08, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x72, 0x65, 0x65, 0x5f, + 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x72, + 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x53, 0x65, 0x6e, 0x64, + 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x7e, 0x0a, 0x19, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x19, 0x0a, 0x08, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x72, 0x65, + 0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x74, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x73, 0x22, 0x1c, 0x0a, 0x1a, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2a, 0x98, 0x01, 0x0a, 0x0a, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, + 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, + 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, + 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x45, 0x47, 0x49, + 0x53, 0x54, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x4f, + 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, + 0x5a, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x52, 0x4f, 0x55, 0x4e, + 0x44, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x45, + 0x44, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, + 0x47, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x32, 0xae, 0x0b, 0x0a, 0x0a, + 0x41, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x73, 0x0a, 0x0f, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, + 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, + 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, + 0x67, 0x0a, 0x0c, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, + 0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, + 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x2f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x12, 0x73, 0x0a, 0x0e, 0x53, 0x65, 0x6e, 0x64, + 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x61, 0x72, 0x6b, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1c, 0x3a, 0x01, 0x2a, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x2f, 0x74, 0x72, 0x65, 0x65, 0x2f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x83, 0x01, + 0x0a, 0x12, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x12, 0x21, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, + 0x6e, 0x64, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x2f, 0x74, 0x72, 0x65, 0x65, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x73, 0x12, 0x73, 0x0a, 0x0f, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, + 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, + 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, - 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x92, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, - 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x6b, 0x2d, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, - 0x61, 0x72, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x73, 0x70, 0x65, 0x63, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x72, 0x6b, 0x2f, 0x76, 0x31, - 0x3b, 0x61, 0x72, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x41, - 0x72, 0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, 0x41, 0x72, 0x6b, 0x5c, 0x56, 0x31, 0xe2, 0x02, - 0x12, 0x41, 0x72, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x41, 0x72, 0x6b, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x57, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x52, + 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, + 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, + 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x7b, 0x74, 0x78, 0x69, 0x64, + 0x7d, 0x12, 0x64, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, + 0x64, 0x12, 0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, + 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, + 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, + 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, + 0x69, 0x64, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x65, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, + 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x30, 0x01, 0x12, 0x50, + 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x13, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x72, + 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x70, + 0x69, 0x6e, 0x67, 0x2f, 0x7b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, + 0x12, 0x5d, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x18, 0x2e, + 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, + 0x76, 0x74, 0x78, 0x6f, 0x73, 0x2f, 0x7b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, + 0x4c, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x61, 0x72, 0x6b, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x0a, 0x12, 0x08, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x52, 0x0a, + 0x07, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x12, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, + 0x31, 0x2e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x10, 0x3a, 0x01, 0x2a, 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x12, 0x64, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x12, 0x1c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, + 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x73, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72, 0x6b, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72, 0x6b, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x92, 0x01, 0x0a, + 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x6b, 0x2d, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x2f, 0x61, 0x72, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x73, 0x70, 0x65, 0x63, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x72, + 0x6b, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x72, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, + 0xaa, 0x02, 0x06, 0x41, 0x72, 0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, 0x41, 0x72, 0x6b, 0x5c, + 0x56, 0x31, 0xe2, 0x02, 0x12, 0x41, 0x72, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x41, 0x72, 0x6b, 0x3a, 0x3a, 0x56, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2351,96 +2857,113 @@ func file_ark_v1_service_proto_rawDescGZIP() []byte { } var file_ark_v1_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_ark_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 35) +var file_ark_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 41) var file_ark_v1_service_proto_goTypes = []interface{}{ - (RoundStage)(0), // 0: ark.v1.RoundStage - (*CreatePaymentRequest)(nil), // 1: ark.v1.CreatePaymentRequest - (*CreatePaymentResponse)(nil), // 2: ark.v1.CreatePaymentResponse - (*CompletePaymentRequest)(nil), // 3: ark.v1.CompletePaymentRequest - (*CompletePaymentResponse)(nil), // 4: ark.v1.CompletePaymentResponse - (*RegisterPaymentRequest)(nil), // 5: ark.v1.RegisterPaymentRequest - (*RegisterPaymentResponse)(nil), // 6: ark.v1.RegisterPaymentResponse - (*ClaimPaymentRequest)(nil), // 7: ark.v1.ClaimPaymentRequest - (*ClaimPaymentResponse)(nil), // 8: ark.v1.ClaimPaymentResponse - (*FinalizePaymentRequest)(nil), // 9: ark.v1.FinalizePaymentRequest - (*FinalizePaymentResponse)(nil), // 10: ark.v1.FinalizePaymentResponse - (*GetRoundRequest)(nil), // 11: ark.v1.GetRoundRequest - (*GetRoundResponse)(nil), // 12: ark.v1.GetRoundResponse - (*GetRoundByIdRequest)(nil), // 13: ark.v1.GetRoundByIdRequest - (*GetRoundByIdResponse)(nil), // 14: ark.v1.GetRoundByIdResponse - (*GetEventStreamRequest)(nil), // 15: ark.v1.GetEventStreamRequest - (*GetEventStreamResponse)(nil), // 16: ark.v1.GetEventStreamResponse - (*PingRequest)(nil), // 17: ark.v1.PingRequest - (*PingResponse)(nil), // 18: ark.v1.PingResponse - (*ListVtxosRequest)(nil), // 19: ark.v1.ListVtxosRequest - (*ListVtxosResponse)(nil), // 20: ark.v1.ListVtxosResponse - (*GetInfoRequest)(nil), // 21: ark.v1.GetInfoRequest - (*GetInfoResponse)(nil), // 22: ark.v1.GetInfoResponse - (*OnboardRequest)(nil), // 23: ark.v1.OnboardRequest - (*OnboardResponse)(nil), // 24: ark.v1.OnboardResponse - (*RoundFinalizationEvent)(nil), // 25: ark.v1.RoundFinalizationEvent - (*RoundFinalizedEvent)(nil), // 26: ark.v1.RoundFinalizedEvent - (*RoundFailed)(nil), // 27: ark.v1.RoundFailed - (*Round)(nil), // 28: ark.v1.Round - (*Input)(nil), // 29: ark.v1.Input - (*Output)(nil), // 30: ark.v1.Output - (*Tree)(nil), // 31: ark.v1.Tree - (*TreeLevel)(nil), // 32: ark.v1.TreeLevel - (*Node)(nil), // 33: ark.v1.Node - (*Vtxo)(nil), // 34: ark.v1.Vtxo - (*PendingPayment)(nil), // 35: ark.v1.PendingPayment + (RoundStage)(0), // 0: ark.v1.RoundStage + (*CreatePaymentRequest)(nil), // 1: ark.v1.CreatePaymentRequest + (*CreatePaymentResponse)(nil), // 2: ark.v1.CreatePaymentResponse + (*CompletePaymentRequest)(nil), // 3: ark.v1.CompletePaymentRequest + (*CompletePaymentResponse)(nil), // 4: ark.v1.CompletePaymentResponse + (*RegisterPaymentRequest)(nil), // 5: ark.v1.RegisterPaymentRequest + (*RegisterPaymentResponse)(nil), // 6: ark.v1.RegisterPaymentResponse + (*ClaimPaymentRequest)(nil), // 7: ark.v1.ClaimPaymentRequest + (*ClaimPaymentResponse)(nil), // 8: ark.v1.ClaimPaymentResponse + (*FinalizePaymentRequest)(nil), // 9: ark.v1.FinalizePaymentRequest + (*FinalizePaymentResponse)(nil), // 10: ark.v1.FinalizePaymentResponse + (*GetRoundRequest)(nil), // 11: ark.v1.GetRoundRequest + (*GetRoundResponse)(nil), // 12: ark.v1.GetRoundResponse + (*GetRoundByIdRequest)(nil), // 13: ark.v1.GetRoundByIdRequest + (*GetRoundByIdResponse)(nil), // 14: ark.v1.GetRoundByIdResponse + (*GetEventStreamRequest)(nil), // 15: ark.v1.GetEventStreamRequest + (*GetEventStreamResponse)(nil), // 16: ark.v1.GetEventStreamResponse + (*PingRequest)(nil), // 17: ark.v1.PingRequest + (*PingResponse)(nil), // 18: ark.v1.PingResponse + (*ListVtxosRequest)(nil), // 19: ark.v1.ListVtxosRequest + (*ListVtxosResponse)(nil), // 20: ark.v1.ListVtxosResponse + (*GetInfoRequest)(nil), // 21: ark.v1.GetInfoRequest + (*GetInfoResponse)(nil), // 22: ark.v1.GetInfoResponse + (*OnboardRequest)(nil), // 23: ark.v1.OnboardRequest + (*OnboardResponse)(nil), // 24: ark.v1.OnboardResponse + (*RoundFinalizationEvent)(nil), // 25: ark.v1.RoundFinalizationEvent + (*RoundFinalizedEvent)(nil), // 26: ark.v1.RoundFinalizedEvent + (*RoundFailed)(nil), // 27: ark.v1.RoundFailed + (*RoundSigningEvent)(nil), // 28: ark.v1.RoundSigningEvent + (*RoundSigningNoncesGeneratedEvent)(nil), // 29: ark.v1.RoundSigningNoncesGeneratedEvent + (*Round)(nil), // 30: ark.v1.Round + (*Input)(nil), // 31: ark.v1.Input + (*Output)(nil), // 32: ark.v1.Output + (*Tree)(nil), // 33: ark.v1.Tree + (*TreeLevel)(nil), // 34: ark.v1.TreeLevel + (*Node)(nil), // 35: ark.v1.Node + (*Vtxo)(nil), // 36: ark.v1.Vtxo + (*PendingPayment)(nil), // 37: ark.v1.PendingPayment + (*SendTreeNoncesRequest)(nil), // 38: ark.v1.SendTreeNoncesRequest + (*SendTreeNoncesResponse)(nil), // 39: ark.v1.SendTreeNoncesResponse + (*SendTreeSignaturesRequest)(nil), // 40: ark.v1.SendTreeSignaturesRequest + (*SendTreeSignaturesResponse)(nil), // 41: ark.v1.SendTreeSignaturesResponse } var file_ark_v1_service_proto_depIdxs = []int32{ - 29, // 0: ark.v1.CreatePaymentRequest.inputs:type_name -> ark.v1.Input - 30, // 1: ark.v1.CreatePaymentRequest.outputs:type_name -> ark.v1.Output - 29, // 2: ark.v1.RegisterPaymentRequest.inputs:type_name -> ark.v1.Input - 30, // 3: ark.v1.ClaimPaymentRequest.outputs:type_name -> ark.v1.Output - 28, // 4: ark.v1.GetRoundResponse.round:type_name -> ark.v1.Round - 28, // 5: ark.v1.GetRoundByIdResponse.round:type_name -> ark.v1.Round + 31, // 0: ark.v1.CreatePaymentRequest.inputs:type_name -> ark.v1.Input + 32, // 1: ark.v1.CreatePaymentRequest.outputs:type_name -> ark.v1.Output + 31, // 2: ark.v1.RegisterPaymentRequest.inputs:type_name -> ark.v1.Input + 32, // 3: ark.v1.ClaimPaymentRequest.outputs:type_name -> ark.v1.Output + 30, // 4: ark.v1.GetRoundResponse.round:type_name -> ark.v1.Round + 30, // 5: ark.v1.GetRoundByIdResponse.round:type_name -> ark.v1.Round 25, // 6: ark.v1.GetEventStreamResponse.round_finalization:type_name -> ark.v1.RoundFinalizationEvent 26, // 7: ark.v1.GetEventStreamResponse.round_finalized:type_name -> ark.v1.RoundFinalizedEvent 27, // 8: ark.v1.GetEventStreamResponse.round_failed:type_name -> ark.v1.RoundFailed - 25, // 9: ark.v1.PingResponse.event:type_name -> ark.v1.RoundFinalizationEvent - 34, // 10: ark.v1.ListVtxosResponse.spendable_vtxos:type_name -> ark.v1.Vtxo - 34, // 11: ark.v1.ListVtxosResponse.spent_vtxos:type_name -> ark.v1.Vtxo - 31, // 12: ark.v1.OnboardRequest.congestion_tree:type_name -> ark.v1.Tree - 31, // 13: ark.v1.RoundFinalizationEvent.congestion_tree:type_name -> ark.v1.Tree - 31, // 14: ark.v1.Round.congestion_tree:type_name -> ark.v1.Tree - 0, // 15: ark.v1.Round.stage:type_name -> ark.v1.RoundStage - 32, // 16: ark.v1.Tree.levels:type_name -> ark.v1.TreeLevel - 33, // 17: ark.v1.TreeLevel.nodes:type_name -> ark.v1.Node - 29, // 18: ark.v1.Vtxo.outpoint:type_name -> ark.v1.Input - 30, // 19: ark.v1.Vtxo.receiver:type_name -> ark.v1.Output - 35, // 20: ark.v1.Vtxo.pending_data:type_name -> ark.v1.PendingPayment - 5, // 21: ark.v1.ArkService.RegisterPayment:input_type -> ark.v1.RegisterPaymentRequest - 7, // 22: ark.v1.ArkService.ClaimPayment:input_type -> ark.v1.ClaimPaymentRequest - 9, // 23: ark.v1.ArkService.FinalizePayment:input_type -> ark.v1.FinalizePaymentRequest - 11, // 24: ark.v1.ArkService.GetRound:input_type -> ark.v1.GetRoundRequest - 13, // 25: ark.v1.ArkService.GetRoundById:input_type -> ark.v1.GetRoundByIdRequest - 15, // 26: ark.v1.ArkService.GetEventStream:input_type -> ark.v1.GetEventStreamRequest - 17, // 27: ark.v1.ArkService.Ping:input_type -> ark.v1.PingRequest - 19, // 28: ark.v1.ArkService.ListVtxos:input_type -> ark.v1.ListVtxosRequest - 21, // 29: ark.v1.ArkService.GetInfo:input_type -> ark.v1.GetInfoRequest - 23, // 30: ark.v1.ArkService.Onboard:input_type -> ark.v1.OnboardRequest - 1, // 31: ark.v1.ArkService.CreatePayment:input_type -> ark.v1.CreatePaymentRequest - 3, // 32: ark.v1.ArkService.CompletePayment:input_type -> ark.v1.CompletePaymentRequest - 6, // 33: ark.v1.ArkService.RegisterPayment:output_type -> ark.v1.RegisterPaymentResponse - 8, // 34: ark.v1.ArkService.ClaimPayment:output_type -> ark.v1.ClaimPaymentResponse - 10, // 35: ark.v1.ArkService.FinalizePayment:output_type -> ark.v1.FinalizePaymentResponse - 12, // 36: ark.v1.ArkService.GetRound:output_type -> ark.v1.GetRoundResponse - 14, // 37: ark.v1.ArkService.GetRoundById:output_type -> ark.v1.GetRoundByIdResponse - 16, // 38: ark.v1.ArkService.GetEventStream:output_type -> ark.v1.GetEventStreamResponse - 18, // 39: ark.v1.ArkService.Ping:output_type -> ark.v1.PingResponse - 20, // 40: ark.v1.ArkService.ListVtxos:output_type -> ark.v1.ListVtxosResponse - 22, // 41: ark.v1.ArkService.GetInfo:output_type -> ark.v1.GetInfoResponse - 24, // 42: ark.v1.ArkService.Onboard:output_type -> ark.v1.OnboardResponse - 2, // 43: ark.v1.ArkService.CreatePayment:output_type -> ark.v1.CreatePaymentResponse - 4, // 44: ark.v1.ArkService.CompletePayment:output_type -> ark.v1.CompletePaymentResponse - 33, // [33:45] is the sub-list for method output_type - 21, // [21:33] is the sub-list for method input_type - 21, // [21:21] is the sub-list for extension type_name - 21, // [21:21] is the sub-list for extension extendee - 0, // [0:21] is the sub-list for field type_name + 28, // 9: ark.v1.GetEventStreamResponse.round_signing:type_name -> ark.v1.RoundSigningEvent + 29, // 10: ark.v1.GetEventStreamResponse.round_signing_nonces_generated:type_name -> ark.v1.RoundSigningNoncesGeneratedEvent + 25, // 11: ark.v1.PingResponse.round_finalization:type_name -> ark.v1.RoundFinalizationEvent + 26, // 12: ark.v1.PingResponse.round_finalized:type_name -> ark.v1.RoundFinalizedEvent + 27, // 13: ark.v1.PingResponse.round_failed:type_name -> ark.v1.RoundFailed + 28, // 14: ark.v1.PingResponse.round_signing:type_name -> ark.v1.RoundSigningEvent + 29, // 15: ark.v1.PingResponse.round_signing_nonces_generated:type_name -> ark.v1.RoundSigningNoncesGeneratedEvent + 36, // 16: ark.v1.ListVtxosResponse.spendable_vtxos:type_name -> ark.v1.Vtxo + 36, // 17: ark.v1.ListVtxosResponse.spent_vtxos:type_name -> ark.v1.Vtxo + 33, // 18: ark.v1.OnboardRequest.congestion_tree:type_name -> ark.v1.Tree + 33, // 19: ark.v1.RoundFinalizationEvent.congestion_tree:type_name -> ark.v1.Tree + 33, // 20: ark.v1.RoundSigningEvent.unsigned_tree:type_name -> ark.v1.Tree + 33, // 21: ark.v1.Round.congestion_tree:type_name -> ark.v1.Tree + 0, // 22: ark.v1.Round.stage:type_name -> ark.v1.RoundStage + 34, // 23: ark.v1.Tree.levels:type_name -> ark.v1.TreeLevel + 35, // 24: ark.v1.TreeLevel.nodes:type_name -> ark.v1.Node + 31, // 25: ark.v1.Vtxo.outpoint:type_name -> ark.v1.Input + 32, // 26: ark.v1.Vtxo.receiver:type_name -> ark.v1.Output + 37, // 27: ark.v1.Vtxo.pending_data:type_name -> ark.v1.PendingPayment + 5, // 28: ark.v1.ArkService.RegisterPayment:input_type -> ark.v1.RegisterPaymentRequest + 7, // 29: ark.v1.ArkService.ClaimPayment:input_type -> ark.v1.ClaimPaymentRequest + 38, // 30: ark.v1.ArkService.SendTreeNonces:input_type -> ark.v1.SendTreeNoncesRequest + 40, // 31: ark.v1.ArkService.SendTreeSignatures:input_type -> ark.v1.SendTreeSignaturesRequest + 9, // 32: ark.v1.ArkService.FinalizePayment:input_type -> ark.v1.FinalizePaymentRequest + 11, // 33: ark.v1.ArkService.GetRound:input_type -> ark.v1.GetRoundRequest + 13, // 34: ark.v1.ArkService.GetRoundById:input_type -> ark.v1.GetRoundByIdRequest + 15, // 35: ark.v1.ArkService.GetEventStream:input_type -> ark.v1.GetEventStreamRequest + 17, // 36: ark.v1.ArkService.Ping:input_type -> ark.v1.PingRequest + 19, // 37: ark.v1.ArkService.ListVtxos:input_type -> ark.v1.ListVtxosRequest + 21, // 38: ark.v1.ArkService.GetInfo:input_type -> ark.v1.GetInfoRequest + 23, // 39: ark.v1.ArkService.Onboard:input_type -> ark.v1.OnboardRequest + 1, // 40: ark.v1.ArkService.CreatePayment:input_type -> ark.v1.CreatePaymentRequest + 3, // 41: ark.v1.ArkService.CompletePayment:input_type -> ark.v1.CompletePaymentRequest + 6, // 42: ark.v1.ArkService.RegisterPayment:output_type -> ark.v1.RegisterPaymentResponse + 8, // 43: ark.v1.ArkService.ClaimPayment:output_type -> ark.v1.ClaimPaymentResponse + 39, // 44: ark.v1.ArkService.SendTreeNonces:output_type -> ark.v1.SendTreeNoncesResponse + 41, // 45: ark.v1.ArkService.SendTreeSignatures:output_type -> ark.v1.SendTreeSignaturesResponse + 10, // 46: ark.v1.ArkService.FinalizePayment:output_type -> ark.v1.FinalizePaymentResponse + 12, // 47: ark.v1.ArkService.GetRound:output_type -> ark.v1.GetRoundResponse + 14, // 48: ark.v1.ArkService.GetRoundById:output_type -> ark.v1.GetRoundByIdResponse + 16, // 49: ark.v1.ArkService.GetEventStream:output_type -> ark.v1.GetEventStreamResponse + 18, // 50: ark.v1.ArkService.Ping:output_type -> ark.v1.PingResponse + 20, // 51: ark.v1.ArkService.ListVtxos:output_type -> ark.v1.ListVtxosResponse + 22, // 52: ark.v1.ArkService.GetInfo:output_type -> ark.v1.GetInfoResponse + 24, // 53: ark.v1.ArkService.Onboard:output_type -> ark.v1.OnboardResponse + 2, // 54: ark.v1.ArkService.CreatePayment:output_type -> ark.v1.CreatePaymentResponse + 4, // 55: ark.v1.ArkService.CompletePayment:output_type -> ark.v1.CompletePaymentResponse + 42, // [42:56] is the sub-list for method output_type + 28, // [28:42] is the sub-list for method input_type + 28, // [28:28] is the sub-list for extension type_name + 28, // [28:28] is the sub-list for extension extendee + 0, // [0:28] is the sub-list for field type_name } func init() { file_ark_v1_service_proto_init() } @@ -2774,7 +3297,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Round); i { + switch v := v.(*RoundSigningEvent); i { case 0: return &v.state case 1: @@ -2786,7 +3309,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Input); i { + switch v := v.(*RoundSigningNoncesGeneratedEvent); i { case 0: return &v.state case 1: @@ -2798,7 +3321,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Output); i { + switch v := v.(*Round); i { case 0: return &v.state case 1: @@ -2810,7 +3333,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Tree); i { + switch v := v.(*Input); i { case 0: return &v.state case 1: @@ -2822,7 +3345,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TreeLevel); i { + switch v := v.(*Output); i { case 0: return &v.state case 1: @@ -2834,7 +3357,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Node); i { + switch v := v.(*Tree); i { case 0: return &v.state case 1: @@ -2846,7 +3369,7 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Vtxo); i { + switch v := v.(*TreeLevel); i { case 0: return &v.state case 1: @@ -2858,6 +3381,30 @@ func file_ark_v1_service_proto_init() { } } file_ark_v1_service_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Node); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ark_v1_service_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Vtxo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ark_v1_service_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PendingPayment); i { case 0: return &v.state @@ -2869,11 +3416,69 @@ func file_ark_v1_service_proto_init() { return nil } } + file_ark_v1_service_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendTreeNoncesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ark_v1_service_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendTreeNoncesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ark_v1_service_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendTreeSignaturesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ark_v1_service_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendTreeSignaturesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } + file_ark_v1_service_proto_msgTypes[4].OneofWrappers = []interface{}{} file_ark_v1_service_proto_msgTypes[15].OneofWrappers = []interface{}{ (*GetEventStreamResponse_RoundFinalization)(nil), (*GetEventStreamResponse_RoundFinalized)(nil), (*GetEventStreamResponse_RoundFailed)(nil), + (*GetEventStreamResponse_RoundSigning)(nil), + (*GetEventStreamResponse_RoundSigningNoncesGenerated)(nil), + } + file_ark_v1_service_proto_msgTypes[17].OneofWrappers = []interface{}{ + (*PingResponse_RoundFinalization)(nil), + (*PingResponse_RoundFinalized)(nil), + (*PingResponse_RoundFailed)(nil), + (*PingResponse_RoundSigning)(nil), + (*PingResponse_RoundSigningNoncesGenerated)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -2881,7 +3486,7 @@ func file_ark_v1_service_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_ark_v1_service_proto_rawDesc, NumEnums: 1, - NumMessages: 35, + NumMessages: 41, NumExtensions: 0, NumServices: 1, }, diff --git a/api-spec/protobuf/gen/ark/v1/service.pb.gw.go b/api-spec/protobuf/gen/ark/v1/service.pb.gw.go index ca025fb..f0d8300 100644 --- a/api-spec/protobuf/gen/ark/v1/service.pb.gw.go +++ b/api-spec/protobuf/gen/ark/v1/service.pb.gw.go @@ -83,6 +83,58 @@ func local_request_ArkService_ClaimPayment_0(ctx context.Context, marshaler runt } +func request_ArkService_SendTreeNonces_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SendTreeNoncesRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.SendTreeNonces(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_ArkService_SendTreeNonces_0(ctx context.Context, marshaler runtime.Marshaler, server ArkServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SendTreeNoncesRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.SendTreeNonces(ctx, &protoReq) + return msg, metadata, err + +} + +func request_ArkService_SendTreeSignatures_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SendTreeSignaturesRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.SendTreeSignatures(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_ArkService_SendTreeSignatures_0(ctx context.Context, marshaler runtime.Marshaler, server ArkServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SendTreeSignaturesRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.SendTreeSignatures(ctx, &protoReq) + return msg, metadata, err + +} + func request_ArkService_FinalizePayment_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq FinalizePaymentRequest var metadata runtime.ServerMetadata @@ -486,6 +538,56 @@ func RegisterArkServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, }) + mux.Handle("POST", pattern_ArkService_SendTreeNonces_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ark.v1.ArkService/SendTreeNonces", runtime.WithHTTPPathPattern("/v1/payment/tree/nonces")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ArkService_SendTreeNonces_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_ArkService_SendTreeNonces_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_ArkService_SendTreeSignatures_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ark.v1.ArkService/SendTreeSignatures", runtime.WithHTTPPathPattern("/v1/payment/tree/signatures")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ArkService_SendTreeSignatures_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_ArkService_SendTreeSignatures_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("POST", pattern_ArkService_FinalizePayment_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -803,6 +905,50 @@ func RegisterArkServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) + mux.Handle("POST", pattern_ArkService_SendTreeNonces_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ark.v1.ArkService/SendTreeNonces", runtime.WithHTTPPathPattern("/v1/payment/tree/nonces")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ArkService_SendTreeNonces_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_ArkService_SendTreeNonces_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_ArkService_SendTreeSignatures_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ark.v1.ArkService/SendTreeSignatures", runtime.WithHTTPPathPattern("/v1/payment/tree/signatures")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ArkService_SendTreeSignatures_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_ArkService_SendTreeSignatures_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("POST", pattern_ArkService_FinalizePayment_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1031,6 +1177,10 @@ var ( pattern_ArkService_ClaimPayment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "payment", "claim"}, "")) + pattern_ArkService_SendTreeNonces_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "payment", "tree", "nonces"}, "")) + + pattern_ArkService_SendTreeSignatures_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "payment", "tree", "signatures"}, "")) + pattern_ArkService_FinalizePayment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "payment", "finalize"}, "")) pattern_ArkService_GetRound_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "round", "txid"}, "")) @@ -1057,6 +1207,10 @@ var ( forward_ArkService_ClaimPayment_0 = runtime.ForwardResponseMessage + forward_ArkService_SendTreeNonces_0 = runtime.ForwardResponseMessage + + forward_ArkService_SendTreeSignatures_0 = runtime.ForwardResponseMessage + forward_ArkService_FinalizePayment_0 = runtime.ForwardResponseMessage forward_ArkService_GetRound_0 = runtime.ForwardResponseMessage diff --git a/api-spec/protobuf/gen/ark/v1/service_grpc.pb.go b/api-spec/protobuf/gen/ark/v1/service_grpc.pb.go index 8068e32..7fddef3 100644 --- a/api-spec/protobuf/gen/ark/v1/service_grpc.pb.go +++ b/api-spec/protobuf/gen/ark/v1/service_grpc.pb.go @@ -20,8 +20,9 @@ const _ = grpc.SupportPackageIsVersion7 type ArkServiceClient interface { RegisterPayment(ctx context.Context, in *RegisterPaymentRequest, opts ...grpc.CallOption) (*RegisterPaymentResponse, error) ClaimPayment(ctx context.Context, in *ClaimPaymentRequest, opts ...grpc.CallOption) (*ClaimPaymentResponse, error) + SendTreeNonces(ctx context.Context, in *SendTreeNoncesRequest, opts ...grpc.CallOption) (*SendTreeNoncesResponse, error) + SendTreeSignatures(ctx context.Context, in *SendTreeSignaturesRequest, opts ...grpc.CallOption) (*SendTreeSignaturesResponse, error) FinalizePayment(ctx context.Context, in *FinalizePaymentRequest, opts ...grpc.CallOption) (*FinalizePaymentResponse, error) - // TODO BTC: signTree rpc GetRound(ctx context.Context, in *GetRoundRequest, opts ...grpc.CallOption) (*GetRoundResponse, error) GetRoundById(ctx context.Context, in *GetRoundByIdRequest, opts ...grpc.CallOption) (*GetRoundByIdResponse, error) GetEventStream(ctx context.Context, in *GetEventStreamRequest, opts ...grpc.CallOption) (ArkService_GetEventStreamClient, error) @@ -59,6 +60,24 @@ func (c *arkServiceClient) ClaimPayment(ctx context.Context, in *ClaimPaymentReq return out, nil } +func (c *arkServiceClient) SendTreeNonces(ctx context.Context, in *SendTreeNoncesRequest, opts ...grpc.CallOption) (*SendTreeNoncesResponse, error) { + out := new(SendTreeNoncesResponse) + err := c.cc.Invoke(ctx, "/ark.v1.ArkService/SendTreeNonces", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *arkServiceClient) SendTreeSignatures(ctx context.Context, in *SendTreeSignaturesRequest, opts ...grpc.CallOption) (*SendTreeSignaturesResponse, error) { + out := new(SendTreeSignaturesResponse) + err := c.cc.Invoke(ctx, "/ark.v1.ArkService/SendTreeSignatures", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *arkServiceClient) FinalizePayment(ctx context.Context, in *FinalizePaymentRequest, opts ...grpc.CallOption) (*FinalizePaymentResponse, error) { out := new(FinalizePaymentResponse) err := c.cc.Invoke(ctx, "/ark.v1.ArkService/FinalizePayment", in, out, opts...) @@ -178,8 +197,9 @@ func (c *arkServiceClient) CompletePayment(ctx context.Context, in *CompletePaym type ArkServiceServer interface { RegisterPayment(context.Context, *RegisterPaymentRequest) (*RegisterPaymentResponse, error) ClaimPayment(context.Context, *ClaimPaymentRequest) (*ClaimPaymentResponse, error) + SendTreeNonces(context.Context, *SendTreeNoncesRequest) (*SendTreeNoncesResponse, error) + SendTreeSignatures(context.Context, *SendTreeSignaturesRequest) (*SendTreeSignaturesResponse, error) FinalizePayment(context.Context, *FinalizePaymentRequest) (*FinalizePaymentResponse, error) - // TODO BTC: signTree rpc GetRound(context.Context, *GetRoundRequest) (*GetRoundResponse, error) GetRoundById(context.Context, *GetRoundByIdRequest) (*GetRoundByIdResponse, error) GetEventStream(*GetEventStreamRequest, ArkService_GetEventStreamServer) error @@ -201,6 +221,12 @@ func (UnimplementedArkServiceServer) RegisterPayment(context.Context, *RegisterP func (UnimplementedArkServiceServer) ClaimPayment(context.Context, *ClaimPaymentRequest) (*ClaimPaymentResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ClaimPayment not implemented") } +func (UnimplementedArkServiceServer) SendTreeNonces(context.Context, *SendTreeNoncesRequest) (*SendTreeNoncesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendTreeNonces not implemented") +} +func (UnimplementedArkServiceServer) SendTreeSignatures(context.Context, *SendTreeSignaturesRequest) (*SendTreeSignaturesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendTreeSignatures not implemented") +} func (UnimplementedArkServiceServer) FinalizePayment(context.Context, *FinalizePaymentRequest) (*FinalizePaymentResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method FinalizePayment not implemented") } @@ -279,6 +305,42 @@ func _ArkService_ClaimPayment_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _ArkService_SendTreeNonces_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SendTreeNoncesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ArkServiceServer).SendTreeNonces(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ark.v1.ArkService/SendTreeNonces", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ArkServiceServer).SendTreeNonces(ctx, req.(*SendTreeNoncesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ArkService_SendTreeSignatures_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SendTreeSignaturesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ArkServiceServer).SendTreeSignatures(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ark.v1.ArkService/SendTreeSignatures", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ArkServiceServer).SendTreeSignatures(ctx, req.(*SendTreeSignaturesRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _ArkService_FinalizePayment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(FinalizePaymentRequest) if err := dec(in); err != nil { @@ -477,6 +539,14 @@ var ArkService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ClaimPayment", Handler: _ArkService_ClaimPayment_Handler, }, + { + MethodName: "SendTreeNonces", + Handler: _ArkService_SendTreeNonces_Handler, + }, + { + MethodName: "SendTreeSignatures", + Handler: _ArkService_SendTreeSignatures_Handler, + }, { MethodName: "FinalizePayment", Handler: _ArkService_FinalizePayment_Handler, diff --git a/client/covenantless/claim.go b/client/covenantless/claim.go index a8957fb..a6a5a0a 100644 --- a/client/covenantless/claim.go +++ b/client/covenantless/claim.go @@ -1,8 +1,11 @@ package covenantless import ( + "encoding/hex" + arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1" "github.com/ark-network/ark/client/utils" + "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/urfave/cli/v2" ) @@ -69,8 +72,19 @@ func selfTransferAllPendingPayments( return err } + ephemeralKey, err := secp256k1.GeneratePrivateKey() + if err != nil { + return err + } + + pubkey := hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed()) + registerResponse, err := client.RegisterPayment( - ctx.Context, &arkv1.RegisterPaymentRequest{Inputs: inputs}, + ctx.Context, + &arkv1.RegisterPaymentRequest{ + Inputs: inputs, + EphemeralPubkey: &pubkey, + }, ) if err != nil { return err @@ -86,7 +100,7 @@ func selfTransferAllPendingPayments( poolTxID, err := handleRoundStream( ctx, client, registerResponse.GetId(), - pendingVtxos, secKey, receiversOutput, + pendingVtxos, secKey, receiversOutput, ephemeralKey, ) if err != nil { return err diff --git a/client/covenantless/client.go b/client/covenantless/client.go index e17af52..1a8dc5f 100644 --- a/client/covenantless/client.go +++ b/client/covenantless/client.go @@ -3,6 +3,7 @@ package covenantless import ( "bytes" "context" + "encoding/hex" "fmt" "io" "strings" @@ -14,6 +15,7 @@ import ( "github.com/ark-network/ark/common/tree" "github.com/btcsuite/btcd/btcec/v2/schnorr" "github.com/btcsuite/btcd/btcutil/psbt" + "github.com/btcsuite/btcd/txscript" "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/urfave/cli/v2" "google.golang.org/grpc" @@ -220,12 +222,15 @@ func castCongestionTree(congestionTree tree.CongestionTree) *arkv1.Tree { func handleRoundStream( ctx *cli.Context, client arkv1.ArkServiceClient, paymentID string, vtxosToSign []vtxo, secKey *secp256k1.PrivateKey, receivers []*arkv1.Output, + ephemeralKey *secp256k1.PrivateKey, ) (poolTxID string, err error) { stream, err := client.GetEventStream(ctx.Context, &arkv1.GetEventStreamRequest{}) if err != nil { return "", err } + myEphemeralPublicKey := hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed()) + var pingStop func() pingReq := &arkv1.PingRequest{ PaymentId: paymentID, @@ -236,6 +241,8 @@ func handleRoundStream( defer pingStop() + var treeSignerSession bitcointree.SignerSession + for { event, err := stream.Recv() if err == io.EOF { @@ -250,6 +257,143 @@ func handleRoundStream( return "", fmt.Errorf("round failed: %s", e.GetReason()) } + if e := event.GetRoundSigning(); e != nil { + pingStop() + fmt.Println("tree created, generating nonces...") + + cosignersPubKeysHex := e.GetCosignersPubkeys() + + cosigners := make([]*secp256k1.PublicKey, 0, len(cosignersPubKeysHex)) + + for _, pubkeyHex := range cosignersPubKeysHex { + pubkeyBytes, err := hex.DecodeString(pubkeyHex) + if err != nil { + return "", err + } + + pubkey, err := secp256k1.ParsePubKey(pubkeyBytes) + if err != nil { + return "", err + } + + cosigners = append(cosigners, pubkey) + } + + congestionTree, err := toCongestionTree(e.GetUnsignedTree()) + if err != nil { + return "", err + } + + minRelayFee, err := utils.GetMinRelayFee(ctx) + if err != nil { + return "", err + } + + aspPubkey, err := utils.GetAspPublicKey(ctx) + if err != nil { + return "", err + } + + lifetime, err := utils.GetRoundLifetime(ctx) + if err != nil { + return "", err + } + + sweepClosure := bitcointree.CSVSigClosure{ + Pubkey: aspPubkey, + Seconds: uint(lifetime), + } + + sweepTapLeaf, err := sweepClosure.Leaf() + if err != nil { + return "", err + } + + sweepTapTree := txscript.AssembleTaprootScriptTree(*sweepTapLeaf) + root := sweepTapTree.RootNode.TapHash() + + treeSignerSession = bitcointree.NewTreeSignerSession( + ephemeralKey, congestionTree, int64(minRelayFee), root.CloneBytes(), + ) + + nonces, err := treeSignerSession.GetNonces() + if err != nil { + return "", err + } + + if err := treeSignerSession.SetKeys(cosigners); err != nil { + return "", err + } + + var nonceBuffer bytes.Buffer + + if err := nonces.Encode(&nonceBuffer); err != nil { + return "", err + } + + serializedNonces := hex.EncodeToString(nonceBuffer.Bytes()) + + if _, err := client.SendTreeNonces(ctx.Context, &arkv1.SendTreeNoncesRequest{ + RoundId: e.GetId(), + PublicKey: myEphemeralPublicKey, + TreeNonces: serializedNonces, + }); err != nil { + return "", err + } + + fmt.Println("nonces sent") + + continue + } + + if e := event.GetRoundSigningNoncesGenerated(); e != nil { + pingStop() + fmt.Println("nonces generated, signing the tree...") + + if treeSignerSession == nil { + return "", fmt.Errorf("tree signer session not set") + } + + combinedNoncesBytes, err := hex.DecodeString(e.GetTreeNonces()) + if err != nil { + return "", err + } + + combinedNonces, err := bitcointree.DecodeNonces(bytes.NewReader(combinedNoncesBytes)) + if err != nil { + return "", err + } + + if err := treeSignerSession.SetAggregatedNonces(combinedNonces); err != nil { + return "", err + } + + sigs, err := treeSignerSession.Sign() + if err != nil { + return "", err + } + + var sigBuffer bytes.Buffer + + if err := sigs.Encode(&sigBuffer); err != nil { + return "", err + } + + serializedSigs := hex.EncodeToString(sigBuffer.Bytes()) + + if _, err := client.SendTreeSignatures(ctx.Context, &arkv1.SendTreeSignaturesRequest{ + RoundId: e.GetId(), + TreeSignatures: serializedSigs, + PublicKey: myEphemeralPublicKey, + }); err != nil { + return "", err + } + + fmt.Println("tree signed") + + continue + } + if e := event.GetRoundFinalization(); e != nil { // stop pinging as soon as we receive some forfeit txs pingStop() diff --git a/client/covenantless/onboard.go b/client/covenantless/onboard.go index 0759aaf..3bd35ed 100644 --- a/client/covenantless/onboard.go +++ b/client/covenantless/onboard.go @@ -168,7 +168,11 @@ func (c *clArkBitcoinCLI) Onboard(ctx *cli.Context) error { return err } - if err := signer.SetKeys(cosigners, aggregatedNonces); err != nil { + if err := signer.SetKeys(cosigners); err != nil { + return err + } + + if err := signer.SetAggregatedNonces(aggregatedNonces); err != nil { return err } diff --git a/client/covenantless/redeem.go b/client/covenantless/redeem.go index 14e6939..13063c6 100644 --- a/client/covenantless/redeem.go +++ b/client/covenantless/redeem.go @@ -2,6 +2,7 @@ package covenantless import ( "bufio" + "encoding/hex" "fmt" "log" "os" @@ -11,6 +12,7 @@ import ( arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1" "github.com/ark-network/ark/client/utils" "github.com/btcsuite/btcd/btcutil" + "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/urfave/cli/v2" ) @@ -80,8 +82,16 @@ func collaborativeRedeem( return err } + ephemeralKey, err := secp256k1.GeneratePrivateKey() + if err != nil { + return err + } + + pubkey := hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed()) + registerResponse, err := client.RegisterPayment(ctx.Context, &arkv1.RegisterPaymentRequest{ - Inputs: inputs, + Inputs: inputs, + EphemeralPubkey: &pubkey, }) if err != nil { return err @@ -102,6 +112,7 @@ func collaborativeRedeem( selectedCoins, secKey, receivers, + ephemeralKey, ) if err != nil { return err diff --git a/common/bitcointree/musig2.go b/common/bitcointree/musig2.go index 1d2adc1..8418cad 100644 --- a/common/bitcointree/musig2.go +++ b/common/bitcointree/musig2.go @@ -1,7 +1,9 @@ package bitcointree import ( + "bytes" "errors" + "fmt" "io" "strings" @@ -12,20 +14,45 @@ import ( "github.com/btcsuite/btcd/btcutil/psbt" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" + "github.com/decred/dcrd/dcrec/secp256k1/v4" ) var ( ErrCongestionTreeNotSet = errors.New("congestion tree not set") ErrAggregateKeyNotSet = errors.New("aggregate key not set") + + columnSeparator = byte('|') + rowSeparator = byte('/') ) -type TreeNonces [][][66]byte // public nonces +type Musig2Nonce struct { + PubNonce [66]byte +} + +func (n *Musig2Nonce) Encode(w io.Writer) error { + _, err := w.Write(n.PubNonce[:]) + return err +} + +func (n *Musig2Nonce) Decode(r io.Reader) error { + bytes := make([]byte, 66) + _, err := r.Read(bytes) + if err != nil { + return err + } + + n.PubNonce = [66]byte(bytes) + return nil +} + +type TreeNonces [][]*Musig2Nonce // public nonces type TreePartialSigs [][]*musig2.PartialSignature type SignerSession interface { - GetNonces() (TreeNonces, error) // generate of return cached nonce for this session - SetKeys([]*btcec.PublicKey, TreeNonces) error // set the keys for this session (with the combined nonces) - Sign() (TreePartialSigs, error) // sign the tree + GetNonces() (TreeNonces, error) // generate tree nonces for this session + SetKeys([]*btcec.PublicKey) error // set the cosigner public keys for this session + SetAggregatedNonces(TreeNonces) error // set the aggregated nonces + Sign() (TreePartialSigs, error) // sign the tree } type CoordinatorSession interface { @@ -36,6 +63,34 @@ type CoordinatorSession interface { SignTree() (tree.CongestionTree, error) } +func (n TreeNonces) Encode(w io.Writer) error { + matrix, err := encodeMatrix(n) + if err != nil { + return err + } + + _, err = w.Write(matrix) + return err +} + +func DecodeNonces(r io.Reader) (TreeNonces, error) { + return decodeMatrix(func() *Musig2Nonce { return new(Musig2Nonce) }, r) +} + +func (s TreePartialSigs) Encode(w io.Writer) error { + matrix, err := encodeMatrix(s) + if err != nil { + return err + } + + _, err = w.Write(matrix) + return err +} + +func DecodeSignatures(r io.Reader) (TreePartialSigs, error) { + return decodeMatrix(func() *musig2.PartialSignature { return new(musig2.PartialSignature) }, r) +} + func AggregateKeys( pubkeys []*btcec.PublicKey, scriptRoot []byte, @@ -100,62 +155,6 @@ func ValidateTreeSigs( return nil } -func (n TreeNonces) Decode(r io.Reader, matrixFormat []int) error { - for i := 0; i < len(matrixFormat); i++ { - for j := 0; j < matrixFormat[i]; j++ { - // read 66 bytes - nonce := make([]byte, 66) - _, err := r.Read(nonce) - if err != nil { - return err - } - - n[i][j] = [66]byte(nonce) - } - } - - return nil -} - -func (n TreeNonces) Encode(w io.Writer) error { - for i := 0; i < len(n); i++ { - for j := 0; j < len(n[i]); j++ { - nonce := n[i][j][:] - _, err := w.Write(nonce) - if err != nil { - return err - } - } - } - - return nil -} - -func (n TreePartialSigs) Decode(r io.Reader, matrixFormat []int) error { - for i := 0; i < len(matrixFormat); i++ { - for j := 0; j < matrixFormat[i]; j++ { - sig := &musig2.PartialSignature{} - if err := sig.Decode(r); err != nil { - return err - } - } - } - - return nil -} - -func (n TreePartialSigs) Encode(w io.Writer) error { - for i := 0; i < len(n); i++ { - for j := 0; j < len(n[i]); j++ { - if err := n[i][j].Encode(w); err != nil { - return err - } - } - } - - return nil -} - func NewTreeSignerSession( signer *btcec.PrivateKey, congestionTree tree.CongestionTree, @@ -221,9 +220,9 @@ func (t *treeSignerSession) GetNonces() (TreeNonces, error) { nonces := make(TreeNonces, 0) for _, level := range t.myNonces { - levelNonces := make([][66]byte, 0) + levelNonces := make([]*Musig2Nonce, 0) for _, nonce := range level { - levelNonces = append(levelNonces, nonce.PubNonce) + levelNonces = append(levelNonces, &Musig2Nonce{nonce.PubNonce}) } nonces = append(nonces, levelNonces) } @@ -231,15 +230,11 @@ func (t *treeSignerSession) GetNonces() (TreeNonces, error) { return nonces, nil } -func (t *treeSignerSession) SetKeys(keys []*btcec.PublicKey, nonces TreeNonces) error { +func (t *treeSignerSession) SetKeys(keys []*btcec.PublicKey) error { if t.keys != nil { return errors.New("keys already set") } - if t.aggregateNonces != nil { - return errors.New("nonces already set") - } - aggregateKey, err := AggregateKeys(keys, t.scriptRoot) if err != nil { return err @@ -251,12 +246,20 @@ func (t *treeSignerSession) SetKeys(keys []*btcec.PublicKey, nonces TreeNonces) } t.prevoutFetcher = prevoutFetcher - t.aggregateNonces = nonces t.keys = keys return nil } +func (t *treeSignerSession) SetAggregatedNonces(nonces TreeNonces) error { + if t.aggregateNonces != nil { + return errors.New("nonces already set") + } + + t.aggregateNonces = nonces + return nil +} + func (t *treeSignerSession) Sign() (TreePartialSigs, error) { if t.tree == nil { return nil, ErrCongestionTreeNotSet @@ -313,7 +316,7 @@ func (t *treeSignerSession) signPartial(partialTx *psbt.Packet, posx int, posy i } return musig2.Sign( - myNonce.SecNonce, seckey, aggregatedNonce, t.keys, [32]byte(message), + myNonce.SecNonce, seckey, aggregatedNonce.PubNonce, t.keys, [32]byte(message), musig2.WithSortedKeys(), musig2.WithTaprootSignTweak(t.scriptRoot), ) } @@ -390,12 +393,11 @@ func (t *treeCoordinatorSession) AggregateNonces() (TreeNonces, error) { aggregatedNonces := make(TreeNonces, 0) for i, level := range t.tree { - levelNonces := make([][66]byte, 0) + levelNonces := make([]*Musig2Nonce, 0) for j := range level { - nonces := make([][66]byte, 0) for _, n := range t.nonces { - nonces = append(nonces, n[i][j]) + nonces = append(nonces, n[i][j].PubNonce) } aggregatedNonce, err := musig2.AggregateNonces(nonces) @@ -403,7 +405,7 @@ func (t *treeCoordinatorSession) AggregateNonces() (TreeNonces, error) { return nil, err } - levelNonces = append(levelNonces, aggregatedNonce) + levelNonces = append(levelNonces, &Musig2Nonce{aggregatedNonce}) } aggregatedNonces = append(aggregatedNonces, levelNonces) @@ -414,12 +416,17 @@ func (t *treeCoordinatorSession) AggregateNonces() (TreeNonces, error) { // SignTree implements CoordinatorSession. func (t *treeCoordinatorSession) SignTree() (tree.CongestionTree, error) { + var missingSigs int for _, sig := range t.sigs { if sig == nil { - return nil, errors.New("signatures not set") + missingSigs++ } } + if missingSigs > 0 { + return nil, fmt.Errorf("missing %d signature(s)", missingSigs) + } + aggregatedKey, err := AggregateKeys(t.keys, t.scriptRoot) if err != nil { return nil, err @@ -432,9 +439,18 @@ func (t *treeCoordinatorSession) SignTree() (tree.CongestionTree, error) { return nil, err } + var combinedNonce *secp256k1.PublicKey sigs := make([]*musig2.PartialSignature, 0) for _, sig := range t.sigs { - sigs = append(sigs, sig[i][j]) + s := sig[i][j] + if s.R != nil { + combinedNonce = s.R + } + sigs = append(sigs, s) + } + + if combinedNonce == nil { + return nil, errors.New("missing combined nonce") } inputFetcher := t.prevoutFetcher(partialTx) @@ -448,7 +464,7 @@ func (t *treeCoordinatorSession) SignTree() (tree.CongestionTree, error) { ) combinedSig := musig2.CombineSigs( - sigs[0].R, sigs, + combinedNonce, sigs, musig2.WithTaprootTweakedCombine([32]byte(message), t.keys, t.scriptRoot, true), ) if err != nil { @@ -507,3 +523,71 @@ type treePrevOutFetcher struct { func (f *treePrevOutFetcher) FetchPrevOutput(wire.OutPoint) *wire.TxOut { return f.prevout } + +type writable interface { + Encode(w io.Writer) error +} + +type readable interface { + Decode(r io.Reader) error +} + +// encodeMatrix encode a matrix of serializable objects into a byte stream +func encodeMatrix[T writable](matrix [][]T) ([]byte, error) { + var buf bytes.Buffer + + for _, row := range matrix { + for _, cell := range row { + if err := buf.WriteByte(columnSeparator); err != nil { + return nil, err + } + + if err := cell.Encode(&buf); err != nil { + return nil, err + } + } + + if err := buf.WriteByte(rowSeparator); err != nil { + return nil, err + } + } + + return buf.Bytes(), nil +} + +// decodeMatrix decode a byte stream into a matrix of serializable objects +func decodeMatrix[T readable](factory func() T, data io.Reader) ([][]T, error) { + matrix := make([][]T, 0) + row := make([]T, 0) + + for { + separator := make([]byte, 1) + + if _, err := data.Read(separator); err != nil { + if err == io.EOF { + break + } + return nil, err + } + + b := separator[0] + + if b == rowSeparator { + matrix = append(matrix, row) + row = make([]T, 0) + continue + } + + cell := factory() + + if err := cell.Decode(data); err != nil { + if err == io.EOF { + break + } + return nil, err + } + row = append(row, cell) + } + + return matrix, nil +} diff --git a/common/bitcointree/musig2_test.go b/common/bitcointree/musig2_test.go index 8e51619..e0c921f 100644 --- a/common/bitcointree/musig2_test.go +++ b/common/bitcointree/musig2_test.go @@ -1,7 +1,9 @@ package bitcointree_test import ( + "bytes" "encoding/json" + "fmt" "os" "testing" @@ -85,6 +87,31 @@ func TestRoundTripSignTree(t *testing.T) { aspNonces, err := aspSession.GetNonces() require.NoError(t, err) + s := bytes.NewBuffer(nil) + + err = aspNonces[0][0].Encode(s) + require.NoError(t, err) + + bitcointreeNonce := new(bitcointree.Musig2Nonce) + err = bitcointreeNonce.Decode(s) + require.NoError(t, err) + + require.Equal(t, aspNonces[0][0], bitcointreeNonce) + + var serializedNonces bytes.Buffer + + err = aspNonces.Encode(&serializedNonces) + require.NoError(t, err) + + decodedNonces, err := bitcointree.DecodeNonces(&serializedNonces) + require.NoError(t, err) + + for i, nonces := range aspNonces { + for j, nonce := range nonces { + require.Equal(t, nonce.PubNonce, decodedNonces[i][j].PubNonce, fmt.Sprintf("matrix nonce not equal at index i: %d, j: %d", i, j)) + } + } + err = aspCoordinator.AddNonce(alice.PubKey(), aliceNonces) require.NoError(t, err) @@ -101,18 +128,30 @@ func TestRoundTripSignTree(t *testing.T) { err = aliceSession.SetKeys( cosigners, + ) + require.NoError(t, err) + + err = aliceSession.SetAggregatedNonces( aggregatedNonce, ) require.NoError(t, err) err = bobSession.SetKeys( cosigners, + ) + require.NoError(t, err) + + err = bobSession.SetAggregatedNonces( aggregatedNonce, ) require.NoError(t, err) err = aspSession.SetKeys( cosigners, + ) + require.NoError(t, err) + + err = aspSession.SetAggregatedNonces( aggregatedNonce, ) require.NoError(t, err) @@ -126,6 +165,22 @@ func TestRoundTripSignTree(t *testing.T) { aspSig, err := aspSession.Sign() require.NoError(t, err) + // check that the sigs are serializable + + serializedSigs := bytes.NewBuffer(nil) + + err = aspSig.Encode(serializedSigs) + require.NoError(t, err) + + decodedSigs, err := bitcointree.DecodeSignatures(serializedSigs) + require.NoError(t, err) + + for i, sigs := range aspSig { + for j, sig := range sigs { + require.Equal(t, sig.S, decodedSigs[i][j].S, fmt.Sprintf("matrix sig not equal at index i: %d, j: %d", i, j)) + } + } + // coordinator receives the signatures and combines them err = aspCoordinator.AddSig(alice.PubKey(), aliceSig) require.NoError(t, err) diff --git a/pkg/client-sdk/Makefile b/pkg/client-sdk/Makefile index 9f3db96..ff4951c 100644 --- a/pkg/client-sdk/Makefile +++ b/pkg/client-sdk/Makefile @@ -3,7 +3,7 @@ ## genrest: compiles rest client from stub with https://github.com/go-swagger/go-swagger genrest: @echo "Generating rest client from stub..." - @swagger generate client -f ../../server/api-spec/openapi/swagger/ark/v1/service.swagger.json -t ./client/rest/service --client-package=arkservice + @swagger generate client -f ../../api-spec/openapi/swagger/ark/v1/service.swagger.json -t ./client/rest/service --client-package=arkservice ## test: runs unit tests test: diff --git a/pkg/client-sdk/client/client.go b/pkg/client-sdk/client/client.go index 7466735..c6b30c5 100644 --- a/pkg/client-sdk/client/client.go +++ b/pkg/client-sdk/client/client.go @@ -4,7 +4,9 @@ import ( "context" "time" + "github.com/ark-network/ark/common/bitcointree" "github.com/ark-network/ark/common/tree" + "github.com/decred/dcrd/dcrec/secp256k1/v4" ) const ( @@ -25,7 +27,7 @@ type ASPClient interface { ctx context.Context, tx, userPubkey string, congestionTree tree.CongestionTree, ) error RegisterPayment( - ctx context.Context, inputs []VtxoKey, + ctx context.Context, inputs []VtxoKey, ephemeralPublicKey string, ) (string, error) ClaimPayment( ctx context.Context, paymentID string, outputs []Output, @@ -33,7 +35,7 @@ type ASPClient interface { GetEventStream( ctx context.Context, paymentID string, ) (<-chan RoundEventChannel, error) - Ping(ctx context.Context, paymentID string) (*RoundFinalizationEvent, error) + Ping(ctx context.Context, paymentID string) (RoundEvent, error) FinalizePayment( ctx context.Context, signedForfeitTxs []string, ) error @@ -43,6 +45,12 @@ type ASPClient interface { CompletePayment( ctx context.Context, signedRedeemTx string, signedUnconditionalForfeitTxs []string, ) error + SendTreeNonces( + ctx context.Context, roundID, cosignerPubkey string, nonces bitcointree.TreeNonces, + ) error + SendTreeSignatures( + ctx context.Context, roundID, cosignerPubkey string, signatures bitcointree.TreePartialSigs, + ) error Close() } @@ -139,3 +147,18 @@ type RoundFailedEvent struct { } func (e RoundFailedEvent) isRoundEvent() {} + +type RoundSigningStartedEvent struct { + ID string + UnsignedTree tree.CongestionTree + CosignersPublicKeys []*secp256k1.PublicKey +} + +func (e RoundSigningStartedEvent) isRoundEvent() {} + +type RoundSigningNoncesGeneratedEvent struct { + ID string + Nonces bitcointree.TreeNonces +} + +func (e RoundSigningNoncesGeneratedEvent) isRoundEvent() {} diff --git a/pkg/client-sdk/client/grpc/client.go b/pkg/client-sdk/client/grpc/client.go index 73ae6c4..1ab1dd3 100644 --- a/pkg/client-sdk/client/grpc/client.go +++ b/pkg/client-sdk/client/grpc/client.go @@ -1,15 +1,19 @@ package grpcclient import ( + "bytes" "context" + "encoding/hex" "fmt" "strings" "time" arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1" + "github.com/ark-network/ark/common/bitcointree" "github.com/ark-network/ark/common/tree" "github.com/ark-network/ark/pkg/client-sdk/client" "github.com/ark-network/ark/pkg/client-sdk/internal/utils" + "github.com/decred/dcrd/dcrec/secp256k1/v4" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" @@ -73,7 +77,13 @@ func (a *grpcClient) GetEventStream( return } - a.eventsCh <- client.RoundEventChannel{Event: event{resp}.toRoundEvent()} + ev, err := event{resp}.toRoundEvent() + if err != nil { + a.eventsCh <- client.RoundEventChannel{Err: err} + return + } + + a.eventsCh <- client.RoundEventChannel{Event: ev} } }() @@ -146,11 +156,15 @@ func (a *grpcClient) Onboard( } func (a *grpcClient) RegisterPayment( - ctx context.Context, inputs []client.VtxoKey, + ctx context.Context, inputs []client.VtxoKey, ephemeralPublicKey string, ) (string, error) { req := &arkv1.RegisterPaymentRequest{ Inputs: ins(inputs).toProto(), } + if len(ephemeralPublicKey) > 0 { + req.EphemeralPubkey = &ephemeralPublicKey + } + resp, err := a.svc.RegisterPayment(ctx, req) if err != nil { return "", err @@ -171,7 +185,7 @@ func (a *grpcClient) ClaimPayment( func (a *grpcClient) Ping( ctx context.Context, paymentID string, -) (*client.RoundFinalizationEvent, error) { +) (client.RoundEvent, error) { req := &arkv1.PingRequest{ PaymentId: paymentID, } @@ -179,14 +193,8 @@ func (a *grpcClient) Ping( if err != nil { return nil, err } - event := resp.GetEvent() - return &client.RoundFinalizationEvent{ - ID: event.GetId(), - Tx: event.GetPoolTx(), - ForfeitTxs: event.GetForfeitTxs(), - Tree: treeFromProto{event.GetCongestionTree()}.parse(), - Connectors: event.GetConnectors(), - }, nil + + return event{resp}.toRoundEvent() } func (a *grpcClient) FinalizePayment( @@ -252,6 +260,54 @@ func (a *grpcClient) GetRoundByID( }, nil } +func (a *grpcClient) SendTreeNonces( + ctx context.Context, roundID, cosignerPubkey string, nonces bitcointree.TreeNonces, +) error { + var nonceBuffer bytes.Buffer + + if err := nonces.Encode(&nonceBuffer); err != nil { + return err + } + + serializedNonces := hex.EncodeToString(nonceBuffer.Bytes()) + + req := &arkv1.SendTreeNoncesRequest{ + RoundId: roundID, + PublicKey: cosignerPubkey, + TreeNonces: serializedNonces, + } + + if _, err := a.svc.SendTreeNonces(ctx, req); err != nil { + return err + } + + return nil +} + +func (a *grpcClient) SendTreeSignatures( + ctx context.Context, roundID, cosignerPubkey string, signatures bitcointree.TreePartialSigs, +) error { + var sigsBuffer bytes.Buffer + + if err := signatures.Encode(&sigsBuffer); err != nil { + return err + } + + serializedSigs := hex.EncodeToString(sigsBuffer.Bytes()) + + req := &arkv1.SendTreeSignaturesRequest{ + RoundId: roundID, + PublicKey: cosignerPubkey, + TreeSignatures: serializedSigs, + } + + if _, err := a.svc.SendTreeSignatures(ctx, req); err != nil { + return err + } + + return nil +} + type out client.Output func (o out) toProto() *arkv1.Output { @@ -271,16 +327,25 @@ func (o outs) toProto() []*arkv1.Output { return list } -type event struct { - *arkv1.GetEventStreamResponse +// wrapper for GetEventStreamResponse and PingResponse +type eventResponse interface { + GetRoundFailed() *arkv1.RoundFailed + GetRoundFinalization() *arkv1.RoundFinalizationEvent + GetRoundFinalized() *arkv1.RoundFinalizedEvent + GetRoundSigning() *arkv1.RoundSigningEvent + GetRoundSigningNoncesGenerated() *arkv1.RoundSigningNoncesGeneratedEvent } -func (e event) toRoundEvent() client.RoundEvent { +type event struct { + eventResponse +} + +func (e event) toRoundEvent() (client.RoundEvent, error) { if ee := e.GetRoundFailed(); ee != nil { return client.RoundFailedEvent{ ID: ee.GetId(), Reason: ee.GetReason(), - } + }, nil } if ee := e.GetRoundFinalization(); ee != nil { tree := treeFromProto{ee.GetCongestionTree()}.parse() @@ -290,13 +355,49 @@ func (e event) toRoundEvent() client.RoundEvent { ForfeitTxs: ee.GetForfeitTxs(), Tree: tree, Connectors: ee.GetConnectors(), + }, nil + } + + if ee := e.GetRoundFinalized(); ee != nil { + return client.RoundFinalizedEvent{ + ID: ee.GetId(), + Txid: ee.GetPoolTxid(), + }, nil + } + + if ee := e.GetRoundSigning(); ee != nil { + pubkeys := make([]*secp256k1.PublicKey, 0, len(ee.GetCosignersPubkeys())) + for _, pubkey := range ee.GetCosignersPubkeys() { + p, err := hex.DecodeString(pubkey) + if err != nil { + return nil, err + } + pk, err := secp256k1.ParsePubKey(p) + if err != nil { + return nil, err + } + pubkeys = append(pubkeys, pk) } + + return client.RoundSigningStartedEvent{ + ID: ee.GetId(), + UnsignedTree: treeFromProto{ee.GetUnsignedTree()}.parse(), + CosignersPublicKeys: pubkeys, + }, nil } - ee := e.GetRoundFinalized() - return client.RoundFinalizedEvent{ - ID: ee.GetId(), - Txid: ee.GetPoolTxid(), + + if ee := e.GetRoundSigningNoncesGenerated(); ee != nil { + nonces, err := bitcointree.DecodeNonces(hex.NewDecoder(strings.NewReader(ee.GetTreeNonces()))) + if err != nil { + return nil, err + } + return client.RoundSigningNoncesGeneratedEvent{ + ID: ee.GetId(), + Nonces: nonces, + }, nil } + + return nil, fmt.Errorf("unknown event") } type vtxo struct { diff --git a/pkg/client-sdk/client/rest/client.go b/pkg/client-sdk/client/rest/client.go index d7dc7c0..98c4ef2 100644 --- a/pkg/client-sdk/client/rest/client.go +++ b/pkg/client-sdk/client/rest/client.go @@ -1,7 +1,9 @@ package restclient import ( + "bytes" "context" + "encoding/hex" "fmt" "net/url" "strconv" @@ -9,16 +11,16 @@ import ( "time" arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1" + "github.com/ark-network/ark/common/bitcointree" "github.com/ark-network/ark/common/tree" "github.com/ark-network/ark/pkg/client-sdk/client" "github.com/ark-network/ark/pkg/client-sdk/client/rest/service/arkservice" "github.com/ark-network/ark/pkg/client-sdk/client/rest/service/arkservice/ark_service" "github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models" "github.com/ark-network/ark/pkg/client-sdk/internal/utils" - "github.com/btcsuite/btcd/btcutil/psbt" + "github.com/decred/dcrd/dcrec/secp256k1/v4" httptransport "github.com/go-openapi/runtime/client" "github.com/go-openapi/strfmt" - "github.com/vulpemventures/go-elements/psetv2" ) type restClient struct { @@ -71,39 +73,7 @@ func (a *restClient) GetEventStream( if event != nil { a.eventsCh <- client.RoundEventChannel{ - Event: *event, - } - - for { - roundID := event.ID - round, err := a.GetRoundByID(ctx, roundID) - if err != nil { - a.eventsCh <- client.RoundEventChannel{ - Err: err, - } - return - } - - if round.Stage == client.RoundStageFinalized { - a.eventsCh <- client.RoundEventChannel{ - Event: client.RoundFinalizedEvent{ - ID: roundID, - Txid: getTxid(round.Tx), - }, - } - return - } - - if round.Stage == client.RoundStageFailed { - a.eventsCh <- client.RoundEventChannel{ - Event: client.RoundFailedEvent{ - ID: roundID, - }, - } - return - } - - time.Sleep(1 * time.Second) + Event: event, } } @@ -286,7 +256,7 @@ func (a *restClient) Onboard( } func (a *restClient) RegisterPayment( - ctx context.Context, inputs []client.VtxoKey, + ctx context.Context, inputs []client.VtxoKey, ephemeralPublicKey string, ) (string, error) { ins := make([]*models.V1Input, 0, len(inputs)) for _, i := range inputs { @@ -295,11 +265,15 @@ func (a *restClient) RegisterPayment( Vout: int64(i.VOut), }) } - body := models.V1RegisterPaymentRequest{ + body := &models.V1RegisterPaymentRequest{ Inputs: ins, } + if len(ephemeralPublicKey) > 0 { + body.EphemeralPubkey = ephemeralPublicKey + } + resp, err := a.svc.ArkServiceRegisterPayment( - ark_service.NewArkServiceRegisterPaymentParams().WithBody(&body), + ark_service.NewArkServiceRegisterPaymentParams().WithBody(body), ) if err != nil { return "", err @@ -331,7 +305,7 @@ func (a *restClient) ClaimPayment( func (a *restClient) Ping( ctx context.Context, paymentID string, -) (*client.RoundFinalizationEvent, error) { +) (client.RoundEvent, error) { r := ark_service.NewArkServicePingParams() r.SetPaymentID(paymentID) resp, err := a.svc.ArkServicePing(r) @@ -339,18 +313,65 @@ func (a *restClient) Ping( return nil, err } - var event *client.RoundFinalizationEvent - if resp.Payload.Event != nil { - event = &client.RoundFinalizationEvent{ - ID: resp.Payload.Event.ID, - Tx: resp.Payload.Event.PoolTx, - ForfeitTxs: resp.Payload.Event.ForfeitTxs, - Tree: treeFromProto{resp.Payload.Event.CongestionTree}.parse(), - Connectors: resp.Payload.Event.Connectors, - } + payload := resp.Payload + + if e := payload.RoundFailed; e != nil { + return client.RoundFailedEvent{ + ID: e.ID, + Reason: e.Reason, + }, nil + } + if e := payload.RoundFinalization; e != nil { + tree := treeFromProto{e.CongestionTree}.parse() + return client.RoundFinalizationEvent{ + ID: e.ID, + Tx: e.PoolTx, + ForfeitTxs: e.ForfeitTxs, + Tree: tree, + Connectors: e.Connectors, + }, nil } - return event, nil + if e := payload.RoundFinalized; e != nil { + return client.RoundFinalizedEvent{ + ID: e.ID, + Txid: e.PoolTxid, + }, nil + } + + if e := payload.RoundSigning; e != nil { + pubkeys := make([]*secp256k1.PublicKey, 0, len(e.CosignersPubkeys)) + for _, pubkey := range e.CosignersPubkeys { + p, err := hex.DecodeString(pubkey) + if err != nil { + return nil, err + } + pk, err := secp256k1.ParsePubKey(p) + if err != nil { + return nil, err + } + pubkeys = append(pubkeys, pk) + } + + return client.RoundSigningStartedEvent{ + ID: e.ID, + UnsignedTree: treeFromProto{e.UnsignedTree}.parse(), + CosignersPublicKeys: pubkeys, + }, nil + } + + if e := payload.RoundSigningNoncesGenerated; e != nil { + nonces, err := bitcointree.DecodeNonces(hex.NewDecoder(strings.NewReader(e.TreeNonces))) + if err != nil { + return nil, err + } + return client.RoundSigningNoncesGeneratedEvent{ + ID: e.ID, + Nonces: nonces, + }, nil + } + + return nil, nil } func (a *restClient) FinalizePayment( @@ -454,6 +475,58 @@ func (a *restClient) GetRoundByID( }, nil } +func (a *restClient) SendTreeNonces( + ctx context.Context, roundID, cosignerPubkey string, nonces bitcointree.TreeNonces, +) error { + var nonceBuffer bytes.Buffer + + if err := nonces.Encode(&nonceBuffer); err != nil { + return err + } + + serializedNonces := hex.EncodeToString(nonceBuffer.Bytes()) + + body := &models.V1SendTreeNoncesRequest{ + RoundID: roundID, + PublicKey: cosignerPubkey, + TreeNonces: serializedNonces, + } + + if _, err := a.svc.ArkServiceSendTreeNonces( + ark_service.NewArkServiceSendTreeNoncesParams().WithBody(body), + ); err != nil { + return err + } + + return nil +} + +func (a *restClient) SendTreeSignatures( + ctx context.Context, roundID, cosignerPubkey string, signatures bitcointree.TreePartialSigs, +) error { + var sigsBuffer bytes.Buffer + + if err := signatures.Encode(&sigsBuffer); err != nil { + return err + } + + serializedSigs := hex.EncodeToString(sigsBuffer.Bytes()) + + body := &models.V1SendTreeSignaturesRequest{ + RoundID: roundID, + PublicKey: cosignerPubkey, + TreeSignatures: serializedSigs, + } + + if _, err := a.svc.ArkServiceSendTreeSignatures( + ark_service.NewArkServiceSendTreeSignaturesParams().WithBody(body), + ); err != nil { + return err + } + + return nil +} + func newRestClient( serviceURL string, ) (ark_service.ClientService, error) { @@ -551,13 +624,3 @@ func (t treeToProto) parse() *models.V1Tree { Levels: levels, } } - -func getTxid(tx string) string { - if ptx, _ := psetv2.NewPsetFromBase64(tx); ptx != nil { - utx, _ := ptx.UnsignedTx() - return utx.TxHash().String() - } - - ptx, _ := psbt.NewFromRawBytes(strings.NewReader(tx), true) - return ptx.UnsignedTx.TxID() -} diff --git a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_client.go b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_client.go index a36fbfa..94689fe 100644 --- a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_client.go +++ b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_client.go @@ -78,6 +78,10 @@ type ClientService interface { ArkServiceRegisterPayment(params *ArkServiceRegisterPaymentParams, opts ...ClientOption) (*ArkServiceRegisterPaymentOK, error) + ArkServiceSendTreeNonces(params *ArkServiceSendTreeNoncesParams, opts ...ClientOption) (*ArkServiceSendTreeNoncesOK, error) + + ArkServiceSendTreeSignatures(params *ArkServiceSendTreeSignaturesParams, opts ...ClientOption) (*ArkServiceSendTreeSignaturesOK, error) + SetTransport(transport runtime.ClientTransport) } @@ -304,7 +308,7 @@ func (a *Client) ArkServiceGetInfo(params *ArkServiceGetInfoParams, opts ...Clie } /* -ArkServiceGetRound ts o d o b t c sign tree rpc +ArkServiceGetRound ark service get round API */ func (a *Client) ArkServiceGetRound(params *ArkServiceGetRoundParams, opts ...ClientOption) (*ArkServiceGetRoundOK, error) { // TODO: Validate the params before sending @@ -525,6 +529,80 @@ func (a *Client) ArkServiceRegisterPayment(params *ArkServiceRegisterPaymentPara return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } +/* +ArkServiceSendTreeNonces ark service send tree nonces API +*/ +func (a *Client) ArkServiceSendTreeNonces(params *ArkServiceSendTreeNoncesParams, opts ...ClientOption) (*ArkServiceSendTreeNoncesOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewArkServiceSendTreeNoncesParams() + } + op := &runtime.ClientOperation{ + ID: "ArkService_SendTreeNonces", + Method: "POST", + PathPattern: "/v1/payment/tree/nonces", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &ArkServiceSendTreeNoncesReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + success, ok := result.(*ArkServiceSendTreeNoncesOK) + if ok { + return success, nil + } + // unexpected success response + unexpectedSuccess := result.(*ArkServiceSendTreeNoncesDefault) + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +ArkServiceSendTreeSignatures ark service send tree signatures API +*/ +func (a *Client) ArkServiceSendTreeSignatures(params *ArkServiceSendTreeSignaturesParams, opts ...ClientOption) (*ArkServiceSendTreeSignaturesOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewArkServiceSendTreeSignaturesParams() + } + op := &runtime.ClientOperation{ + ID: "ArkService_SendTreeSignatures", + Method: "POST", + PathPattern: "/v1/payment/tree/signatures", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &ArkServiceSendTreeSignaturesReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + success, ok := result.(*ArkServiceSendTreeSignaturesOK) + if ok { + return success, nil + } + // unexpected success response + unexpectedSuccess := result.(*ArkServiceSendTreeSignaturesDefault) + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + // SetTransport changes the transport on the client func (a *Client) SetTransport(transport runtime.ClientTransport) { a.transport = transport diff --git a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_nonces_parameters.go b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_nonces_parameters.go new file mode 100644 index 0000000..abb95c5 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_nonces_parameters.go @@ -0,0 +1,150 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ark_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + + "github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models" +) + +// NewArkServiceSendTreeNoncesParams creates a new ArkServiceSendTreeNoncesParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewArkServiceSendTreeNoncesParams() *ArkServiceSendTreeNoncesParams { + return &ArkServiceSendTreeNoncesParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewArkServiceSendTreeNoncesParamsWithTimeout creates a new ArkServiceSendTreeNoncesParams object +// with the ability to set a timeout on a request. +func NewArkServiceSendTreeNoncesParamsWithTimeout(timeout time.Duration) *ArkServiceSendTreeNoncesParams { + return &ArkServiceSendTreeNoncesParams{ + timeout: timeout, + } +} + +// NewArkServiceSendTreeNoncesParamsWithContext creates a new ArkServiceSendTreeNoncesParams object +// with the ability to set a context for a request. +func NewArkServiceSendTreeNoncesParamsWithContext(ctx context.Context) *ArkServiceSendTreeNoncesParams { + return &ArkServiceSendTreeNoncesParams{ + Context: ctx, + } +} + +// NewArkServiceSendTreeNoncesParamsWithHTTPClient creates a new ArkServiceSendTreeNoncesParams object +// with the ability to set a custom HTTPClient for a request. +func NewArkServiceSendTreeNoncesParamsWithHTTPClient(client *http.Client) *ArkServiceSendTreeNoncesParams { + return &ArkServiceSendTreeNoncesParams{ + HTTPClient: client, + } +} + +/* +ArkServiceSendTreeNoncesParams contains all the parameters to send to the API endpoint + + for the ark service send tree nonces operation. + + Typically these are written to a http.Request. +*/ +type ArkServiceSendTreeNoncesParams struct { + + // Body. + Body *models.V1SendTreeNoncesRequest + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the ark service send tree nonces params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ArkServiceSendTreeNoncesParams) WithDefaults() *ArkServiceSendTreeNoncesParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the ark service send tree nonces params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ArkServiceSendTreeNoncesParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the ark service send tree nonces params +func (o *ArkServiceSendTreeNoncesParams) WithTimeout(timeout time.Duration) *ArkServiceSendTreeNoncesParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the ark service send tree nonces params +func (o *ArkServiceSendTreeNoncesParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the ark service send tree nonces params +func (o *ArkServiceSendTreeNoncesParams) WithContext(ctx context.Context) *ArkServiceSendTreeNoncesParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the ark service send tree nonces params +func (o *ArkServiceSendTreeNoncesParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the ark service send tree nonces params +func (o *ArkServiceSendTreeNoncesParams) WithHTTPClient(client *http.Client) *ArkServiceSendTreeNoncesParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the ark service send tree nonces params +func (o *ArkServiceSendTreeNoncesParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the ark service send tree nonces params +func (o *ArkServiceSendTreeNoncesParams) WithBody(body *models.V1SendTreeNoncesRequest) *ArkServiceSendTreeNoncesParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the ark service send tree nonces params +func (o *ArkServiceSendTreeNoncesParams) SetBody(body *models.V1SendTreeNoncesRequest) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *ArkServiceSendTreeNoncesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if o.Body != nil { + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_nonces_responses.go b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_nonces_responses.go new file mode 100644 index 0000000..3e26786 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_nonces_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ark_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + "github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models" +) + +// ArkServiceSendTreeNoncesReader is a Reader for the ArkServiceSendTreeNonces structure. +type ArkServiceSendTreeNoncesReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ArkServiceSendTreeNoncesReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 200: + result := NewArkServiceSendTreeNoncesOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewArkServiceSendTreeNoncesDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewArkServiceSendTreeNoncesOK creates a ArkServiceSendTreeNoncesOK with default headers values +func NewArkServiceSendTreeNoncesOK() *ArkServiceSendTreeNoncesOK { + return &ArkServiceSendTreeNoncesOK{} +} + +/* +ArkServiceSendTreeNoncesOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type ArkServiceSendTreeNoncesOK struct { + Payload models.V1SendTreeNoncesResponse +} + +// IsSuccess returns true when this ark service send tree nonces o k response has a 2xx status code +func (o *ArkServiceSendTreeNoncesOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this ark service send tree nonces o k response has a 3xx status code +func (o *ArkServiceSendTreeNoncesOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this ark service send tree nonces o k response has a 4xx status code +func (o *ArkServiceSendTreeNoncesOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this ark service send tree nonces o k response has a 5xx status code +func (o *ArkServiceSendTreeNoncesOK) IsServerError() bool { + return false +} + +// IsCode returns true when this ark service send tree nonces o k response a status code equal to that given +func (o *ArkServiceSendTreeNoncesOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the ark service send tree nonces o k response +func (o *ArkServiceSendTreeNoncesOK) Code() int { + return 200 +} + +func (o *ArkServiceSendTreeNoncesOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment/tree/nonces][%d] arkServiceSendTreeNoncesOK %s", 200, payload) +} + +func (o *ArkServiceSendTreeNoncesOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment/tree/nonces][%d] arkServiceSendTreeNoncesOK %s", 200, payload) +} + +func (o *ArkServiceSendTreeNoncesOK) GetPayload() models.V1SendTreeNoncesResponse { + return o.Payload +} + +func (o *ArkServiceSendTreeNoncesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewArkServiceSendTreeNoncesDefault creates a ArkServiceSendTreeNoncesDefault with default headers values +func NewArkServiceSendTreeNoncesDefault(code int) *ArkServiceSendTreeNoncesDefault { + return &ArkServiceSendTreeNoncesDefault{ + _statusCode: code, + } +} + +/* +ArkServiceSendTreeNoncesDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type ArkServiceSendTreeNoncesDefault struct { + _statusCode int + + Payload *models.RPCStatus +} + +// IsSuccess returns true when this ark service send tree nonces default response has a 2xx status code +func (o *ArkServiceSendTreeNoncesDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this ark service send tree nonces default response has a 3xx status code +func (o *ArkServiceSendTreeNoncesDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this ark service send tree nonces default response has a 4xx status code +func (o *ArkServiceSendTreeNoncesDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this ark service send tree nonces default response has a 5xx status code +func (o *ArkServiceSendTreeNoncesDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this ark service send tree nonces default response a status code equal to that given +func (o *ArkServiceSendTreeNoncesDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the ark service send tree nonces default response +func (o *ArkServiceSendTreeNoncesDefault) Code() int { + return o._statusCode +} + +func (o *ArkServiceSendTreeNoncesDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment/tree/nonces][%d] ArkService_SendTreeNonces default %s", o._statusCode, payload) +} + +func (o *ArkServiceSendTreeNoncesDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment/tree/nonces][%d] ArkService_SendTreeNonces default %s", o._statusCode, payload) +} + +func (o *ArkServiceSendTreeNoncesDefault) GetPayload() *models.RPCStatus { + return o.Payload +} + +func (o *ArkServiceSendTreeNoncesDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.RPCStatus) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_signatures_parameters.go b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_signatures_parameters.go new file mode 100644 index 0000000..a0207a3 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_signatures_parameters.go @@ -0,0 +1,150 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ark_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + + "github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models" +) + +// NewArkServiceSendTreeSignaturesParams creates a new ArkServiceSendTreeSignaturesParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewArkServiceSendTreeSignaturesParams() *ArkServiceSendTreeSignaturesParams { + return &ArkServiceSendTreeSignaturesParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewArkServiceSendTreeSignaturesParamsWithTimeout creates a new ArkServiceSendTreeSignaturesParams object +// with the ability to set a timeout on a request. +func NewArkServiceSendTreeSignaturesParamsWithTimeout(timeout time.Duration) *ArkServiceSendTreeSignaturesParams { + return &ArkServiceSendTreeSignaturesParams{ + timeout: timeout, + } +} + +// NewArkServiceSendTreeSignaturesParamsWithContext creates a new ArkServiceSendTreeSignaturesParams object +// with the ability to set a context for a request. +func NewArkServiceSendTreeSignaturesParamsWithContext(ctx context.Context) *ArkServiceSendTreeSignaturesParams { + return &ArkServiceSendTreeSignaturesParams{ + Context: ctx, + } +} + +// NewArkServiceSendTreeSignaturesParamsWithHTTPClient creates a new ArkServiceSendTreeSignaturesParams object +// with the ability to set a custom HTTPClient for a request. +func NewArkServiceSendTreeSignaturesParamsWithHTTPClient(client *http.Client) *ArkServiceSendTreeSignaturesParams { + return &ArkServiceSendTreeSignaturesParams{ + HTTPClient: client, + } +} + +/* +ArkServiceSendTreeSignaturesParams contains all the parameters to send to the API endpoint + + for the ark service send tree signatures operation. + + Typically these are written to a http.Request. +*/ +type ArkServiceSendTreeSignaturesParams struct { + + // Body. + Body *models.V1SendTreeSignaturesRequest + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the ark service send tree signatures params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ArkServiceSendTreeSignaturesParams) WithDefaults() *ArkServiceSendTreeSignaturesParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the ark service send tree signatures params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ArkServiceSendTreeSignaturesParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the ark service send tree signatures params +func (o *ArkServiceSendTreeSignaturesParams) WithTimeout(timeout time.Duration) *ArkServiceSendTreeSignaturesParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the ark service send tree signatures params +func (o *ArkServiceSendTreeSignaturesParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the ark service send tree signatures params +func (o *ArkServiceSendTreeSignaturesParams) WithContext(ctx context.Context) *ArkServiceSendTreeSignaturesParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the ark service send tree signatures params +func (o *ArkServiceSendTreeSignaturesParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the ark service send tree signatures params +func (o *ArkServiceSendTreeSignaturesParams) WithHTTPClient(client *http.Client) *ArkServiceSendTreeSignaturesParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the ark service send tree signatures params +func (o *ArkServiceSendTreeSignaturesParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the ark service send tree signatures params +func (o *ArkServiceSendTreeSignaturesParams) WithBody(body *models.V1SendTreeSignaturesRequest) *ArkServiceSendTreeSignaturesParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the ark service send tree signatures params +func (o *ArkServiceSendTreeSignaturesParams) SetBody(body *models.V1SendTreeSignaturesRequest) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *ArkServiceSendTreeSignaturesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if o.Body != nil { + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_signatures_responses.go b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_signatures_responses.go new file mode 100644 index 0000000..402b481 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_send_tree_signatures_responses.go @@ -0,0 +1,185 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ark_service + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + "github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models" +) + +// ArkServiceSendTreeSignaturesReader is a Reader for the ArkServiceSendTreeSignatures structure. +type ArkServiceSendTreeSignaturesReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ArkServiceSendTreeSignaturesReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 200: + result := NewArkServiceSendTreeSignaturesOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewArkServiceSendTreeSignaturesDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewArkServiceSendTreeSignaturesOK creates a ArkServiceSendTreeSignaturesOK with default headers values +func NewArkServiceSendTreeSignaturesOK() *ArkServiceSendTreeSignaturesOK { + return &ArkServiceSendTreeSignaturesOK{} +} + +/* +ArkServiceSendTreeSignaturesOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type ArkServiceSendTreeSignaturesOK struct { + Payload models.V1SendTreeSignaturesResponse +} + +// IsSuccess returns true when this ark service send tree signatures o k response has a 2xx status code +func (o *ArkServiceSendTreeSignaturesOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this ark service send tree signatures o k response has a 3xx status code +func (o *ArkServiceSendTreeSignaturesOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this ark service send tree signatures o k response has a 4xx status code +func (o *ArkServiceSendTreeSignaturesOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this ark service send tree signatures o k response has a 5xx status code +func (o *ArkServiceSendTreeSignaturesOK) IsServerError() bool { + return false +} + +// IsCode returns true when this ark service send tree signatures o k response a status code equal to that given +func (o *ArkServiceSendTreeSignaturesOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the ark service send tree signatures o k response +func (o *ArkServiceSendTreeSignaturesOK) Code() int { + return 200 +} + +func (o *ArkServiceSendTreeSignaturesOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment/tree/signatures][%d] arkServiceSendTreeSignaturesOK %s", 200, payload) +} + +func (o *ArkServiceSendTreeSignaturesOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment/tree/signatures][%d] arkServiceSendTreeSignaturesOK %s", 200, payload) +} + +func (o *ArkServiceSendTreeSignaturesOK) GetPayload() models.V1SendTreeSignaturesResponse { + return o.Payload +} + +func (o *ArkServiceSendTreeSignaturesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewArkServiceSendTreeSignaturesDefault creates a ArkServiceSendTreeSignaturesDefault with default headers values +func NewArkServiceSendTreeSignaturesDefault(code int) *ArkServiceSendTreeSignaturesDefault { + return &ArkServiceSendTreeSignaturesDefault{ + _statusCode: code, + } +} + +/* +ArkServiceSendTreeSignaturesDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type ArkServiceSendTreeSignaturesDefault struct { + _statusCode int + + Payload *models.RPCStatus +} + +// IsSuccess returns true when this ark service send tree signatures default response has a 2xx status code +func (o *ArkServiceSendTreeSignaturesDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this ark service send tree signatures default response has a 3xx status code +func (o *ArkServiceSendTreeSignaturesDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this ark service send tree signatures default response has a 4xx status code +func (o *ArkServiceSendTreeSignaturesDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this ark service send tree signatures default response has a 5xx status code +func (o *ArkServiceSendTreeSignaturesDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this ark service send tree signatures default response a status code equal to that given +func (o *ArkServiceSendTreeSignaturesDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the ark service send tree signatures default response +func (o *ArkServiceSendTreeSignaturesDefault) Code() int { + return o._statusCode +} + +func (o *ArkServiceSendTreeSignaturesDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment/tree/signatures][%d] ArkService_SendTreeSignatures default %s", o._statusCode, payload) +} + +func (o *ArkServiceSendTreeSignaturesDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/payment/tree/signatures][%d] ArkService_SendTreeSignatures default %s", o._statusCode, payload) +} + +func (o *ArkServiceSendTreeSignaturesDefault) GetPayload() *models.RPCStatus { + return o.Payload +} + +func (o *ArkServiceSendTreeSignaturesDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.RPCStatus) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/pkg/client-sdk/client/rest/service/models/v1_get_event_stream_response.go b/pkg/client-sdk/client/rest/service/models/v1_get_event_stream_response.go index 887bae1..1068aa0 100644 --- a/pkg/client-sdk/client/rest/service/models/v1_get_event_stream_response.go +++ b/pkg/client-sdk/client/rest/service/models/v1_get_event_stream_response.go @@ -21,11 +21,17 @@ type V1GetEventStreamResponse struct { // round failed RoundFailed *V1RoundFailed `json:"roundFailed,omitempty"` - // TODO: BTC add "signTree" event + // round finalization RoundFinalization *V1RoundFinalizationEvent `json:"roundFinalization,omitempty"` // round finalized RoundFinalized *V1RoundFinalizedEvent `json:"roundFinalized,omitempty"` + + // round signing + RoundSigning *V1RoundSigningEvent `json:"roundSigning,omitempty"` + + // round signing nonces generated + RoundSigningNoncesGenerated *V1RoundSigningNoncesGeneratedEvent `json:"roundSigningNoncesGenerated,omitempty"` } // Validate validates this v1 get event stream response @@ -44,6 +50,14 @@ func (m *V1GetEventStreamResponse) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateRoundSigning(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRoundSigningNoncesGenerated(formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -107,6 +121,44 @@ func (m *V1GetEventStreamResponse) validateRoundFinalized(formats strfmt.Registr return nil } +func (m *V1GetEventStreamResponse) validateRoundSigning(formats strfmt.Registry) error { + if swag.IsZero(m.RoundSigning) { // not required + return nil + } + + if m.RoundSigning != nil { + if err := m.RoundSigning.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("roundSigning") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("roundSigning") + } + return err + } + } + + return nil +} + +func (m *V1GetEventStreamResponse) validateRoundSigningNoncesGenerated(formats strfmt.Registry) error { + if swag.IsZero(m.RoundSigningNoncesGenerated) { // not required + return nil + } + + if m.RoundSigningNoncesGenerated != nil { + if err := m.RoundSigningNoncesGenerated.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("roundSigningNoncesGenerated") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("roundSigningNoncesGenerated") + } + return err + } + } + + return nil +} + // ContextValidate validate this v1 get event stream response based on the context it is used func (m *V1GetEventStreamResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error { var res []error @@ -123,6 +175,14 @@ func (m *V1GetEventStreamResponse) ContextValidate(ctx context.Context, formats res = append(res, err) } + if err := m.contextValidateRoundSigning(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRoundSigningNoncesGenerated(ctx, formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -192,6 +252,48 @@ func (m *V1GetEventStreamResponse) contextValidateRoundFinalized(ctx context.Con return nil } +func (m *V1GetEventStreamResponse) contextValidateRoundSigning(ctx context.Context, formats strfmt.Registry) error { + + if m.RoundSigning != nil { + + if swag.IsZero(m.RoundSigning) { // not required + return nil + } + + if err := m.RoundSigning.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("roundSigning") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("roundSigning") + } + return err + } + } + + return nil +} + +func (m *V1GetEventStreamResponse) contextValidateRoundSigningNoncesGenerated(ctx context.Context, formats strfmt.Registry) error { + + if m.RoundSigningNoncesGenerated != nil { + + if swag.IsZero(m.RoundSigningNoncesGenerated) { // not required + return nil + } + + if err := m.RoundSigningNoncesGenerated.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("roundSigningNoncesGenerated") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("roundSigningNoncesGenerated") + } + return err + } + } + + return nil +} + // MarshalBinary interface implementation func (m *V1GetEventStreamResponse) MarshalBinary() ([]byte, error) { if m == nil { diff --git a/pkg/client-sdk/client/rest/service/models/v1_ping_response.go b/pkg/client-sdk/client/rest/service/models/v1_ping_response.go index ea37603..4a685cf 100644 --- a/pkg/client-sdk/client/rest/service/models/v1_ping_response.go +++ b/pkg/client-sdk/client/rest/service/models/v1_ping_response.go @@ -18,18 +18,43 @@ import ( // swagger:model v1PingResponse type V1PingResponse struct { - // event - Event *V1RoundFinalizationEvent `json:"event,omitempty"` + // round failed + RoundFailed *V1RoundFailed `json:"roundFailed,omitempty"` - // forfeit txs - ForfeitTxs []string `json:"forfeitTxs"` + // round finalization + RoundFinalization *V1RoundFinalizationEvent `json:"roundFinalization,omitempty"` + + // round finalized + RoundFinalized *V1RoundFinalizedEvent `json:"roundFinalized,omitempty"` + + // round signing + RoundSigning *V1RoundSigningEvent `json:"roundSigning,omitempty"` + + // round signing nonces generated + RoundSigningNoncesGenerated *V1RoundSigningNoncesGeneratedEvent `json:"roundSigningNoncesGenerated,omitempty"` } // Validate validates this v1 ping response func (m *V1PingResponse) Validate(formats strfmt.Registry) error { var res []error - if err := m.validateEvent(formats); err != nil { + if err := m.validateRoundFailed(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRoundFinalization(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRoundFinalized(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRoundSigning(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRoundSigningNoncesGenerated(formats); err != nil { res = append(res, err) } @@ -39,17 +64,93 @@ func (m *V1PingResponse) Validate(formats strfmt.Registry) error { return nil } -func (m *V1PingResponse) validateEvent(formats strfmt.Registry) error { - if swag.IsZero(m.Event) { // not required +func (m *V1PingResponse) validateRoundFailed(formats strfmt.Registry) error { + if swag.IsZero(m.RoundFailed) { // not required return nil } - if m.Event != nil { - if err := m.Event.Validate(formats); err != nil { + if m.RoundFailed != nil { + if err := m.RoundFailed.Validate(formats); err != nil { if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("event") + return ve.ValidateName("roundFailed") } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("event") + return ce.ValidateName("roundFailed") + } + return err + } + } + + return nil +} + +func (m *V1PingResponse) validateRoundFinalization(formats strfmt.Registry) error { + if swag.IsZero(m.RoundFinalization) { // not required + return nil + } + + if m.RoundFinalization != nil { + if err := m.RoundFinalization.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("roundFinalization") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("roundFinalization") + } + return err + } + } + + return nil +} + +func (m *V1PingResponse) validateRoundFinalized(formats strfmt.Registry) error { + if swag.IsZero(m.RoundFinalized) { // not required + return nil + } + + if m.RoundFinalized != nil { + if err := m.RoundFinalized.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("roundFinalized") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("roundFinalized") + } + return err + } + } + + return nil +} + +func (m *V1PingResponse) validateRoundSigning(formats strfmt.Registry) error { + if swag.IsZero(m.RoundSigning) { // not required + return nil + } + + if m.RoundSigning != nil { + if err := m.RoundSigning.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("roundSigning") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("roundSigning") + } + return err + } + } + + return nil +} + +func (m *V1PingResponse) validateRoundSigningNoncesGenerated(formats strfmt.Registry) error { + if swag.IsZero(m.RoundSigningNoncesGenerated) { // not required + return nil + } + + if m.RoundSigningNoncesGenerated != nil { + if err := m.RoundSigningNoncesGenerated.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("roundSigningNoncesGenerated") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("roundSigningNoncesGenerated") } return err } @@ -62,7 +163,23 @@ func (m *V1PingResponse) validateEvent(formats strfmt.Registry) error { func (m *V1PingResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error { var res []error - if err := m.contextValidateEvent(ctx, formats); err != nil { + if err := m.contextValidateRoundFailed(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRoundFinalization(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRoundFinalized(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRoundSigning(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRoundSigningNoncesGenerated(ctx, formats); err != nil { res = append(res, err) } @@ -72,19 +189,103 @@ func (m *V1PingResponse) ContextValidate(ctx context.Context, formats strfmt.Reg return nil } -func (m *V1PingResponse) contextValidateEvent(ctx context.Context, formats strfmt.Registry) error { +func (m *V1PingResponse) contextValidateRoundFailed(ctx context.Context, formats strfmt.Registry) error { - if m.Event != nil { + if m.RoundFailed != nil { - if swag.IsZero(m.Event) { // not required + if swag.IsZero(m.RoundFailed) { // not required return nil } - if err := m.Event.ContextValidate(ctx, formats); err != nil { + if err := m.RoundFailed.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("event") + return ve.ValidateName("roundFailed") } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("event") + return ce.ValidateName("roundFailed") + } + return err + } + } + + return nil +} + +func (m *V1PingResponse) contextValidateRoundFinalization(ctx context.Context, formats strfmt.Registry) error { + + if m.RoundFinalization != nil { + + if swag.IsZero(m.RoundFinalization) { // not required + return nil + } + + if err := m.RoundFinalization.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("roundFinalization") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("roundFinalization") + } + return err + } + } + + return nil +} + +func (m *V1PingResponse) contextValidateRoundFinalized(ctx context.Context, formats strfmt.Registry) error { + + if m.RoundFinalized != nil { + + if swag.IsZero(m.RoundFinalized) { // not required + return nil + } + + if err := m.RoundFinalized.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("roundFinalized") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("roundFinalized") + } + return err + } + } + + return nil +} + +func (m *V1PingResponse) contextValidateRoundSigning(ctx context.Context, formats strfmt.Registry) error { + + if m.RoundSigning != nil { + + if swag.IsZero(m.RoundSigning) { // not required + return nil + } + + if err := m.RoundSigning.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("roundSigning") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("roundSigning") + } + return err + } + } + + return nil +} + +func (m *V1PingResponse) contextValidateRoundSigningNoncesGenerated(ctx context.Context, formats strfmt.Registry) error { + + if m.RoundSigningNoncesGenerated != nil { + + if swag.IsZero(m.RoundSigningNoncesGenerated) { // not required + return nil + } + + if err := m.RoundSigningNoncesGenerated.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("roundSigningNoncesGenerated") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("roundSigningNoncesGenerated") } return err } diff --git a/pkg/client-sdk/client/rest/service/models/v1_register_payment_request.go b/pkg/client-sdk/client/rest/service/models/v1_register_payment_request.go index ed252a8..70ee637 100644 --- a/pkg/client-sdk/client/rest/service/models/v1_register_payment_request.go +++ b/pkg/client-sdk/client/rest/service/models/v1_register_payment_request.go @@ -19,6 +19,9 @@ import ( // swagger:model v1RegisterPaymentRequest type V1RegisterPaymentRequest struct { + // ephemeral pubkey + EphemeralPubkey string `json:"ephemeralPubkey,omitempty"` + // inputs Inputs []*V1Input `json:"inputs"` } diff --git a/pkg/client-sdk/client/rest/service/models/v1_round_signing_event.go b/pkg/client-sdk/client/rest/service/models/v1_round_signing_event.go new file mode 100644 index 0000000..4ed6ef5 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/models/v1_round_signing_event.go @@ -0,0 +1,115 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1RoundSigningEvent v1 round signing event +// +// swagger:model v1RoundSigningEvent +type V1RoundSigningEvent struct { + + // cosigners pubkeys + CosignersPubkeys []string `json:"cosignersPubkeys"` + + // id + ID string `json:"id,omitempty"` + + // unsigned tree + UnsignedTree *V1Tree `json:"unsignedTree,omitempty"` +} + +// Validate validates this v1 round signing event +func (m *V1RoundSigningEvent) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateUnsignedTree(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1RoundSigningEvent) validateUnsignedTree(formats strfmt.Registry) error { + if swag.IsZero(m.UnsignedTree) { // not required + return nil + } + + if m.UnsignedTree != nil { + if err := m.UnsignedTree.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("unsignedTree") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("unsignedTree") + } + return err + } + } + + return nil +} + +// ContextValidate validate this v1 round signing event based on the context it is used +func (m *V1RoundSigningEvent) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateUnsignedTree(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1RoundSigningEvent) contextValidateUnsignedTree(ctx context.Context, formats strfmt.Registry) error { + + if m.UnsignedTree != nil { + + if swag.IsZero(m.UnsignedTree) { // not required + return nil + } + + if err := m.UnsignedTree.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("unsignedTree") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("unsignedTree") + } + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1RoundSigningEvent) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1RoundSigningEvent) UnmarshalBinary(b []byte) error { + var res V1RoundSigningEvent + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client-sdk/client/rest/service/models/v1_round_signing_nonces_generated_event.go b/pkg/client-sdk/client/rest/service/models/v1_round_signing_nonces_generated_event.go new file mode 100644 index 0000000..eec5859 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/models/v1_round_signing_nonces_generated_event.go @@ -0,0 +1,53 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1RoundSigningNoncesGeneratedEvent v1 round signing nonces generated event +// +// swagger:model v1RoundSigningNoncesGeneratedEvent +type V1RoundSigningNoncesGeneratedEvent struct { + + // id + ID string `json:"id,omitempty"` + + // tree nonces + TreeNonces string `json:"treeNonces,omitempty"` +} + +// Validate validates this v1 round signing nonces generated event +func (m *V1RoundSigningNoncesGeneratedEvent) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 round signing nonces generated event based on context it is used +func (m *V1RoundSigningNoncesGeneratedEvent) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1RoundSigningNoncesGeneratedEvent) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1RoundSigningNoncesGeneratedEvent) UnmarshalBinary(b []byte) error { + var res V1RoundSigningNoncesGeneratedEvent + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client-sdk/client/rest/service/models/v1_send_tree_nonces_request.go b/pkg/client-sdk/client/rest/service/models/v1_send_tree_nonces_request.go new file mode 100644 index 0000000..d2b9386 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/models/v1_send_tree_nonces_request.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1SendTreeNoncesRequest v1 send tree nonces request +// +// swagger:model v1SendTreeNoncesRequest +type V1SendTreeNoncesRequest struct { + + // public key + PublicKey string `json:"publicKey,omitempty"` + + // round Id + RoundID string `json:"roundId,omitempty"` + + // tree nonces + TreeNonces string `json:"treeNonces,omitempty"` +} + +// Validate validates this v1 send tree nonces request +func (m *V1SendTreeNoncesRequest) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 send tree nonces request based on context it is used +func (m *V1SendTreeNoncesRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1SendTreeNoncesRequest) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1SendTreeNoncesRequest) UnmarshalBinary(b []byte) error { + var res V1SendTreeNoncesRequest + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client-sdk/client/rest/service/models/v1_send_tree_nonces_response.go b/pkg/client-sdk/client/rest/service/models/v1_send_tree_nonces_response.go new file mode 100644 index 0000000..734b54c --- /dev/null +++ b/pkg/client-sdk/client/rest/service/models/v1_send_tree_nonces_response.go @@ -0,0 +1,11 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// V1SendTreeNoncesResponse v1 send tree nonces response +// +// swagger:model v1SendTreeNoncesResponse +type V1SendTreeNoncesResponse interface{} diff --git a/pkg/client-sdk/client/rest/service/models/v1_send_tree_signatures_request.go b/pkg/client-sdk/client/rest/service/models/v1_send_tree_signatures_request.go new file mode 100644 index 0000000..c08ecf9 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/models/v1_send_tree_signatures_request.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1SendTreeSignaturesRequest v1 send tree signatures request +// +// swagger:model v1SendTreeSignaturesRequest +type V1SendTreeSignaturesRequest struct { + + // public key + PublicKey string `json:"publicKey,omitempty"` + + // round Id + RoundID string `json:"roundId,omitempty"` + + // tree signatures + TreeSignatures string `json:"treeSignatures,omitempty"` +} + +// Validate validates this v1 send tree signatures request +func (m *V1SendTreeSignaturesRequest) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 send tree signatures request based on context it is used +func (m *V1SendTreeSignaturesRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1SendTreeSignaturesRequest) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1SendTreeSignaturesRequest) UnmarshalBinary(b []byte) error { + var res V1SendTreeSignaturesRequest + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client-sdk/client/rest/service/models/v1_send_tree_signatures_response.go b/pkg/client-sdk/client/rest/service/models/v1_send_tree_signatures_response.go new file mode 100644 index 0000000..a299076 --- /dev/null +++ b/pkg/client-sdk/client/rest/service/models/v1_send_tree_signatures_response.go @@ -0,0 +1,11 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// V1SendTreeSignaturesResponse v1 send tree signatures response +// +// swagger:model v1SendTreeSignaturesResponse +type V1SendTreeSignaturesResponse interface{} diff --git a/pkg/client-sdk/covenant_client.go b/pkg/client-sdk/covenant_client.go index ed3655a..49ce456 100644 --- a/pkg/client-sdk/covenant_client.go +++ b/pkg/client-sdk/covenant_client.go @@ -528,7 +528,7 @@ func (a *covenantArkClient) CollaborativeRedeem( }) } - paymentID, err := a.client.RegisterPayment(ctx, inputs) + paymentID, err := a.client.RegisterPayment(ctx, inputs, "") // ephemeralPublicKey is not required for covenant if err != nil { return "", err } @@ -796,7 +796,7 @@ func (a *covenantArkClient) sendOffchain( } paymentID, err := a.client.RegisterPayment( - ctx, inputs, + ctx, inputs, "", // ephemeralPublicKey is not required for covenant ) if err != nil { return "", err diff --git a/pkg/client-sdk/covenantless_client.go b/pkg/client-sdk/covenantless_client.go index 616ad18..087b942 100644 --- a/pkg/client-sdk/covenantless_client.go +++ b/pkg/client-sdk/covenantless_client.go @@ -262,7 +262,11 @@ func (a *covenantlessArkClient) Onboard( return "", err } - if err := signer.SetKeys(cosigners, aggregatedNonces); err != nil { + if err := signer.SetKeys(cosigners); err != nil { + return "", err + } + + if err := signer.SetAggregatedNonces(aggregatedNonces); err != nil { return "", err } @@ -608,7 +612,16 @@ func (a *covenantlessArkClient) CollaborativeRedeem( }) } - paymentID, err := a.client.RegisterPayment(ctx, inputs) + roundEphemeralKey, err := secp256k1.GeneratePrivateKey() + if err != nil { + return "", err + } + + paymentID, err := a.client.RegisterPayment( + ctx, + inputs, + hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()), + ) if err != nil { return "", err } @@ -618,7 +631,7 @@ func (a *covenantlessArkClient) CollaborativeRedeem( } poolTxID, err := a.handleRoundStream( - ctx, paymentID, selectedCoins, receivers, + ctx, paymentID, selectedCoins, receivers, roundEphemeralKey, ) if err != nil { return "", err @@ -990,8 +1003,13 @@ func (a *covenantlessArkClient) sendOffchain( }) } + roundEphemeralKey, err := secp256k1.GeneratePrivateKey() + if err != nil { + return "", err + } + paymentID, err := a.client.RegisterPayment( - ctx, inputs, + ctx, inputs, hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()), ) if err != nil { return "", err @@ -1006,7 +1024,7 @@ func (a *covenantlessArkClient) sendOffchain( log.Infof("payment registered with id: %s", paymentID) poolTxID, err := a.handleRoundStream( - ctx, paymentID, selectedCoins, receiversOutput, + ctx, paymentID, selectedCoins, receiversOutput, roundEphemeralKey, ) if err != nil { return "", err @@ -1144,7 +1162,10 @@ func (a *covenantlessArkClient) addVtxoInput( func (a *covenantlessArkClient) handleRoundStream( ctx context.Context, - paymentID string, vtxosToSign []client.Vtxo, receivers []client.Output, + paymentID string, + vtxosToSign []client.Vtxo, + receivers []client.Output, + roundEphemeralKey *secp256k1.PrivateKey, ) (string, error) { eventsCh, err := a.client.GetEventStream(ctx, paymentID) if err != nil { @@ -1158,6 +1179,8 @@ func (a *covenantlessArkClient) handleRoundStream( defer pingStop() + var signerSession bitcointree.SignerSession + for { select { case <-ctx.Done(): @@ -1172,6 +1195,25 @@ func (a *covenantlessArkClient) handleRoundStream( return event.(client.RoundFinalizedEvent).Txid, nil case client.RoundFailedEvent: return "", fmt.Errorf("round failed: %s", event.(client.RoundFailedEvent).Reason) + case client.RoundSigningStartedEvent: + pingStop() + log.Info("a round signing started") + signerSession, err = a.handleRoundSigningStarted( + ctx, roundEphemeralKey, event.(client.RoundSigningStartedEvent), + ) + if err != nil { + return "", err + } + continue + case client.RoundSigningNoncesGeneratedEvent: + pingStop() + log.Info("round combined nonces generated") + if err := a.handleRoundSigningNoncesGenerated( + ctx, event.(client.RoundSigningNoncesGeneratedEvent), roundEphemeralKey, signerSession, + ); err != nil { + return "", err + } + continue case client.RoundFinalizationEvent: pingStop() log.Info("a round finalization started") @@ -1200,6 +1242,73 @@ func (a *covenantlessArkClient) handleRoundStream( } } +func (a *covenantlessArkClient) handleRoundSigningStarted( + ctx context.Context, ephemeralKey *secp256k1.PrivateKey, event client.RoundSigningStartedEvent, +) (signerSession bitcointree.SignerSession, err error) { + sweepClosure := bitcointree.CSVSigClosure{ + Pubkey: a.AspPubkey, + Seconds: uint(a.RoundLifetime), + } + + sweepTapLeaf, err := sweepClosure.Leaf() + if err != nil { + return + } + + sweepTapTree := txscript.AssembleTaprootScriptTree(*sweepTapLeaf) + root := sweepTapTree.RootNode.TapHash() + + signerSession = bitcointree.NewTreeSignerSession( + ephemeralKey, event.UnsignedTree, int64(a.MinRelayFee), root.CloneBytes(), + ) + + if err = signerSession.SetKeys(event.CosignersPublicKeys); err != nil { + return + } + + nonces, err := signerSession.GetNonces() + if err != nil { + return + } + + myPubKey := hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed()) + + err = a.arkClient.client.SendTreeNonces(ctx, event.ID, myPubKey, nonces) + + return +} + +func (a *covenantlessArkClient) handleRoundSigningNoncesGenerated( + ctx context.Context, + event client.RoundSigningNoncesGeneratedEvent, + ephemeralKey *secp256k1.PrivateKey, + signerSession bitcointree.SignerSession, +) error { + if signerSession == nil { + return fmt.Errorf("tree signer session not set") + } + + if err := signerSession.SetAggregatedNonces(event.Nonces); err != nil { + return err + } + + sigs, err := signerSession.Sign() + if err != nil { + return err + } + + if err := a.arkClient.client.SendTreeSignatures( + ctx, + event.ID, + hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed()), + sigs, + ); err != nil { + return err + } + + return nil +} + func (a *covenantlessArkClient) handleRoundFinalization( ctx context.Context, event client.RoundFinalizationEvent, vtxos []client.Vtxo, receivers []client.Output, @@ -1619,7 +1728,16 @@ func (a *covenantlessArkClient) selfTransferAllPendingPayments( outputs := []client.Output{myself} - paymentID, err := a.client.RegisterPayment(ctx, inputs) + roundEphemeralKey, err := secp256k1.GeneratePrivateKey() + if err != nil { + return "", err + } + + paymentID, err := a.client.RegisterPayment( + ctx, + inputs, + hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()), + ) if err != nil { return "", err } @@ -1629,7 +1747,7 @@ func (a *covenantlessArkClient) selfTransferAllPendingPayments( } roundTxid, err := a.handleRoundStream( - ctx, paymentID, pendingVtxos, outputs, + ctx, paymentID, pendingVtxos, outputs, roundEphemeralKey, ) if err != nil { return "", err diff --git a/server/internal/core/application/covenant.go b/server/internal/core/application/covenant.go index 16f9ebf..f97ad68 100644 --- a/server/internal/core/application/covenant.go +++ b/server/internal/core/application/covenant.go @@ -20,6 +20,10 @@ import ( "github.com/vulpemventures/go-elements/psetv2" ) +var ( + ErrTreeSigningNotRequired = fmt.Errorf("tree signing is not required on this ark (covenant)") +) + type covenantService struct { network common.Network pubkey *secp256k1.PublicKey @@ -40,6 +44,7 @@ type covenantService struct { eventsCh chan domain.RoundEvent onboardingCh chan onboarding + lastEvent domain.RoundEvent currentRound *domain.Round } @@ -66,7 +71,7 @@ func NewCovenantService( network, pubkey, roundLifetime, roundInterval, unilateralExitDelay, minRelayFee, walletSvc, repoManager, builder, scanner, sweeper, - paymentRequests, forfeitTxs, eventsCh, onboardingCh, nil, + paymentRequests, forfeitTxs, eventsCh, onboardingCh, nil, nil, } repoManager.RegisterEventsHandler( func(round *domain.Round) { @@ -148,17 +153,17 @@ func (s *covenantService) ClaimVtxos(ctx context.Context, creds string, receiver return s.paymentRequests.update(*payment) } -func (s *covenantService) UpdatePaymentStatus(_ context.Context, id string) ([]string, *domain.Round, error) { +func (s *covenantService) UpdatePaymentStatus(_ context.Context, id string) (domain.RoundEvent, error) { err := s.paymentRequests.updatePingTimestamp(id) if err != nil { if _, ok := err.(errPaymentNotFound); ok { - return s.forfeitTxs.view(), s.currentRound, nil + return s.lastEvent, nil } - return nil, nil, err + return nil, err } - return nil, nil, nil + return s.lastEvent, nil } func (s *covenantService) CompleteAsyncPayment(ctx context.Context, redeemTx string, unconditionalForfeitTxs []string) error { @@ -248,6 +253,24 @@ func (s *covenantService) Onboard( return nil } +func (s *covenantService) RegisterCosignerPubkey(ctx context.Context, paymentId string, _ string) error { + // if the user sends an ephemeral pubkey, something is going wrong client-side + // we should delete the associated payment + if err := s.paymentRequests.delete(paymentId); err != nil { + log.WithError(err).Warn("failed to delete payment") + } + + return ErrTreeSigningNotRequired +} + +func (s *covenantService) RegisterCosignerNonces(context.Context, string, *secp256k1.PublicKey, string) error { + return ErrTreeSigningNotRequired +} + +func (s *covenantService) RegisterCosignerSignatures(context.Context, string, *secp256k1.PublicKey, string) error { + return ErrTreeSigningNotRequired +} + func (s *covenantService) start() { s.startRound() } @@ -256,6 +279,7 @@ func (s *covenantService) startRound() { round := domain.NewRound(dustAmount) //nolint:all round.StartRegistration() + s.lastEvent = nil s.currentRound = round defer func() { @@ -305,7 +329,7 @@ func (s *covenantService) startFinalization() { if num > paymentsThreshold { num = paymentsThreshold } - payments := s.paymentRequests.pop(num) + payments, _ := s.paymentRequests.pop(num) if _, err := round.RegisterPayments(payments); err != nil { round.Fail(fmt.Errorf("failed to register payments: %s", err)) log.WithError(err).Warn("failed to register payments") @@ -670,14 +694,17 @@ func (s *covenantService) propagateEvents(round *domain.Round) { switch e := lastEvent.(type) { case domain.RoundFinalizationStarted: forfeitTxs := s.forfeitTxs.view() - s.eventsCh <- domain.RoundFinalizationStarted{ + ev := domain.RoundFinalizationStarted{ Id: e.Id, CongestionTree: e.CongestionTree, Connectors: e.Connectors, PoolTx: e.PoolTx, UnsignedForfeitTxs: forfeitTxs, } + s.lastEvent = ev + s.eventsCh <- ev case domain.RoundFinalized, domain.RoundFailed: + s.lastEvent = e s.eventsCh <- e } } diff --git a/server/internal/core/application/covenantless.go b/server/internal/core/application/covenantless.go index 3384d7f..e89cccb 100644 --- a/server/internal/core/application/covenantless.go +++ b/server/internal/core/application/covenantless.go @@ -41,9 +41,11 @@ type covenantlessService struct { eventsCh chan domain.RoundEvent onboardingCh chan onboarding - currentRound *domain.Round - - asyncPaymentsCache map[domain.VtxoKey]struct { + // cached data for the current round + lastEvent domain.RoundEvent + currentRound *domain.Round + treeSigningSessions map[string]*musigSigningSession + asyncPaymentsCache map[domain.VtxoKey]struct { receivers []domain.Receiver expireAt int64 } @@ -89,6 +91,7 @@ func NewCovenantlessService( eventsCh: eventsCh, onboardingCh: onboardingCh, asyncPaymentsCache: asyncPaymentsCache, + treeSigningSessions: make(map[string]*musigSigningSession), } repoManager.RegisterEventsHandler( @@ -273,17 +276,17 @@ func (s *covenantlessService) ClaimVtxos(ctx context.Context, creds string, rece return s.paymentRequests.update(*payment) } -func (s *covenantlessService) UpdatePaymentStatus(_ context.Context, id string) ([]string, *domain.Round, error) { +func (s *covenantlessService) UpdatePaymentStatus(_ context.Context, id string) (domain.RoundEvent, error) { err := s.paymentRequests.updatePingTimestamp(id) if err != nil { if _, ok := err.(errPaymentNotFound); ok { - return s.forfeitTxs.view(), s.currentRound, nil + return s.lastEvent, nil } - return nil, nil, err + return nil, err } - return nil, nil, nil + return s.lastEvent, nil } func (s *covenantlessService) SignVtxos(ctx context.Context, forfeitTxs []string) error { @@ -367,6 +370,78 @@ func (s *covenantlessService) Onboard( return nil } +func (s *covenantlessService) RegisterCosignerPubkey(ctx context.Context, paymentId string, pubkey string) error { + pubkeyBytes, err := hex.DecodeString(pubkey) + if err != nil { + return fmt.Errorf("failed to decode hex pubkey: %s", err) + } + + ephemeralPublicKey, err := secp256k1.ParsePubKey(pubkeyBytes) + if err != nil { + return fmt.Errorf("failed to parse pubkey: %s", err) + } + + return s.paymentRequests.pushEphemeralKey(paymentId, ephemeralPublicKey) +} + +func (s *covenantlessService) RegisterCosignerNonces( + ctx context.Context, roundID string, pubkey *secp256k1.PublicKey, encodedNonces string, +) error { + session, ok := s.treeSigningSessions[roundID] + if !ok { + return fmt.Errorf(`signing session not found for round "%s"`, roundID) + } + + nonces, err := bitcointree.DecodeNonces(hex.NewDecoder(strings.NewReader(encodedNonces))) + if err != nil { + return fmt.Errorf("failed to decode nonces: %s", err) + } + + session.lock.Lock() + defer session.lock.Unlock() + + if _, ok := session.nonces[pubkey]; ok { + return nil // skip if we already have nonces for this pubkey + } + + session.nonces[pubkey] = nonces + + if len(session.nonces) == session.nbCosigners-1 { // exclude the ASP + session.nonceDoneC <- struct{}{} + } + + return nil +} + +func (s *covenantlessService) RegisterCosignerSignatures( + ctx context.Context, roundID string, pubkey *secp256k1.PublicKey, encodedSignatures string, +) error { + session, ok := s.treeSigningSessions[roundID] + if !ok { + return fmt.Errorf(`signing session not found for round "%s"`, roundID) + } + + signatures, err := bitcointree.DecodeSignatures(hex.NewDecoder(strings.NewReader(encodedSignatures))) + if err != nil { + return fmt.Errorf("failed to decode signatures: %s", err) + } + + session.lock.Lock() + defer session.lock.Unlock() + + if _, ok := session.signatures[pubkey]; ok { + return nil // skip if we already have signatures for this pubkey + } + + session.signatures[pubkey] = signatures + + if len(session.signatures) == session.nbCosigners-1 { // exclude the ASP + session.sigDoneC <- struct{}{} + } + + return nil +} + func (s *covenantlessService) start() { s.startRound() } @@ -375,6 +450,7 @@ func (s *covenantlessService) startRound() { round := domain.NewRound(dustAmount) // TODO dynamic dust amount? //nolint:all round.StartRegistration() + s.lastEvent = nil s.currentRound = round defer func() { @@ -389,8 +465,12 @@ func (s *covenantlessService) startFinalization() { ctx := context.Background() round := s.currentRound + roundRemainingDuration := time.Duration(s.roundInterval/2-1) * time.Second + thirdOfRemainingDuration := time.Duration(roundRemainingDuration / 3) + var roundAborted bool defer func() { + delete(s.treeSigningSessions, round.Id) if roundAborted { s.startRound() return @@ -404,7 +484,7 @@ func (s *covenantlessService) startFinalization() { s.startRound() return } - time.Sleep(time.Duration((s.roundInterval/2)-1) * time.Second) + time.Sleep(thirdOfRemainingDuration) s.finalizeRound() }() @@ -424,7 +504,14 @@ func (s *covenantlessService) startFinalization() { if num > paymentsThreshold { num = paymentsThreshold } - payments := s.paymentRequests.pop(num) + payments, cosigners := s.paymentRequests.pop(num) + if len(payments) > len(cosigners) { + err := fmt.Errorf("missing ephemeral key for payments") + round.Fail(fmt.Errorf("round aborted: %s", err)) + log.WithError(err).Debugf("round %s aborted", round.Id) + return + } + if _, err := round.RegisterPayments(payments); err != nil { round.Fail(fmt.Errorf("failed to register payments: %s", err)) log.WithError(err).Warn("failed to register payments") @@ -438,32 +525,16 @@ func (s *covenantlessService) startFinalization() { return } - cosigners := make([]*secp256k1.PrivateKey, 0) - cosignersPubKeys := make([]*secp256k1.PublicKey, 0, len(cosigners)) - for range payments { - // TODO sender should provide the ephemeral *public* key - ephemeralKey, err := secp256k1.GeneratePrivateKey() - if err != nil { - round.Fail(fmt.Errorf("failed to generate ephemeral key: %s", err)) - log.WithError(err).Warn("failed to generate ephemeral key") - return - } - - cosigners = append(cosigners, ephemeralKey) - cosignersPubKeys = append(cosignersPubKeys, ephemeralKey.PubKey()) - } - - aspSigningKey, err := secp256k1.GeneratePrivateKey() + ephemeralKey, err := secp256k1.GeneratePrivateKey() if err != nil { - round.Fail(fmt.Errorf("failed to generate asp signing key: %s", err)) - log.WithError(err).Warn("failed to generate asp signing key") + round.Fail(fmt.Errorf("failed to generate ephemeral key: %s", err)) + log.WithError(err).Warn("failed to generate ephemeral key") return } - cosigners = append(cosigners, aspSigningKey) - cosignersPubKeys = append(cosignersPubKeys, aspSigningKey.PubKey()) + cosigners = append(cosigners, ephemeralKey.PubKey()) - unsignedPoolTx, tree, connectorAddress, err := s.builder.BuildPoolTx(s.pubkey, payments, s.minRelayFee, sweptRounds, cosignersPubKeys...) + unsignedPoolTx, tree, connectorAddress, err := s.builder.BuildPoolTx(s.pubkey, payments, s.minRelayFee, sweptRounds, cosigners...) if err != nil { round.Fail(fmt.Errorf("failed to create pool tx: %s", err)) log.WithError(err).Warn("failed to create pool tx") @@ -472,6 +543,16 @@ func (s *covenantlessService) startFinalization() { log.Debugf("pool tx created for round %s", round.Id) if len(tree) > 0 { + log.Debugf("signing congestion tree for round %s", round.Id) + + signingSession := newMusigSigningSession(len(cosigners)) + s.treeSigningSessions[round.Id] = signingSession + + log.Debugf("signing session created for round %s", round.Id) + + // send back the unsigned tree & all cosigners pubkeys + s.propagateRoundSigningStartedEvent(tree, cosigners) + sweepClosure := bitcointree.CSVSigClosure{ Pubkey: s.pubkey, Seconds: uint(s.roundLifetime), @@ -485,37 +566,50 @@ func (s *covenantlessService) startFinalization() { sweepTapTree := txscript.AssembleTaprootScriptTree(*sweepTapLeaf) root := sweepTapTree.RootNode.TapHash() - coordinator, err := s.createTreeCoordinatorSession(tree, cosignersPubKeys, root) + coordinator, err := s.createTreeCoordinatorSession(tree, cosigners, root) if err != nil { round.Fail(fmt.Errorf("failed to create tree coordinator: %s", err)) log.WithError(err).Warn("failed to create tree coordinator") return } - signers := make([]bitcointree.SignerSession, 0) + aspSignerSession := bitcointree.NewTreeSignerSession( + ephemeralKey, tree, int64(s.minRelayFee), root.CloneBytes(), + ) - for _, seckey := range cosigners { - signer := bitcointree.NewTreeSignerSession( - seckey, tree, int64(s.minRelayFee), root.CloneBytes(), - ) - - // TODO nonces should be sent by the sender - nonces, err := signer.GetNonces() - if err != nil { - round.Fail(fmt.Errorf("failed to get nonces: %s", err)) - log.WithError(err).Warn("failed to get nonces") - return - } - - if err := coordinator.AddNonce(seckey.PubKey(), nonces); err != nil { - round.Fail(fmt.Errorf("failed to add nonce: %s", err)) - log.WithError(err).Warn("failed to add nonce") - return - } - - signers = append(signers, signer) + nonces, err := aspSignerSession.GetNonces() + if err != nil { + round.Fail(fmt.Errorf("failed to get nonces: %s", err)) + log.WithError(err).Warn("failed to get nonces") + return } + if err := coordinator.AddNonce(ephemeralKey.PubKey(), nonces); err != nil { + round.Fail(fmt.Errorf("failed to add nonce: %s", err)) + log.WithError(err).Warn("failed to add nonce") + return + } + + noncesTimer := time.NewTimer(thirdOfRemainingDuration) + + select { + case <-noncesTimer.C: + round.Fail(fmt.Errorf("musig2 signing session timed out (nonce collection)")) + log.Warn("musig2 signing session timed out (nonce collection)") + return + case <-signingSession.nonceDoneC: + noncesTimer.Stop() + for pubkey, nonce := range signingSession.nonces { + if err := coordinator.AddNonce(pubkey, nonce); err != nil { + round.Fail(fmt.Errorf("failed to add nonce: %s", err)) + log.WithError(err).Warn("failed to add nonce") + return + } + } + } + + log.Debugf("nonces collected for round %s", round.Id) + aggragatedNonces, err := coordinator.AggregateNonces() if err != nil { round.Fail(fmt.Errorf("failed to aggregate nonces: %s", err)) @@ -523,36 +617,69 @@ func (s *covenantlessService) startFinalization() { return } - // TODO aggragated nonces and public keys should be sent back to signer - // TODO signing should be done client-side (except for the ASP) - for i, signer := range signers { - if err := signer.SetKeys(cosignersPubKeys, aggragatedNonces); err != nil { - round.Fail(fmt.Errorf("failed to set keys: %s", err)) - log.WithError(err).Warn("failed to set keys") - return - } + log.Debugf("nonces aggregated for round %s", round.Id) - sig, err := signer.Sign() - if err != nil { - round.Fail(fmt.Errorf("failed to sign: %s", err)) - log.WithError(err).Warn("failed to sign") - return - } + s.propagateRoundSigningNoncesGeneratedEvent(aggragatedNonces) - if err := coordinator.AddSig(cosignersPubKeys[i], sig); err != nil { - round.Fail(fmt.Errorf("failed to add sig: %s", err)) - log.WithError(err).Warn("failed to add sig") - return - } + if err := aspSignerSession.SetKeys(cosigners); err != nil { + round.Fail(fmt.Errorf("failed to set keys: %s", err)) + log.WithError(err).Warn("failed to set keys") + return } - signedTree, err := coordinator.SignTree() + if err := aspSignerSession.SetAggregatedNonces(aggragatedNonces); err != nil { + round.Fail(fmt.Errorf("failed to set aggregated nonces: %s", err)) + log.WithError(err).Warn("failed to set aggregated nonces") + return + } + + // sign the tree as ASP + aspTreeSigs, err := aspSignerSession.Sign() if err != nil { round.Fail(fmt.Errorf("failed to sign tree: %s", err)) log.WithError(err).Warn("failed to sign tree") return } + if err := coordinator.AddSig(ephemeralKey.PubKey(), aspTreeSigs); err != nil { + round.Fail(fmt.Errorf("failed to add signature: %s", err)) + log.WithError(err).Warn("failed to add signature") + return + } + + log.Debugf("ASP tree signed for round %s", round.Id) + + signaturesTimer := time.NewTimer(thirdOfRemainingDuration) + + log.Debugf("waiting for cosigners to sign the tree") + + select { + case <-signaturesTimer.C: + round.Fail(fmt.Errorf("musig2 signing session timed out (signatures)")) + log.Warn("musig2 signing session timed out (signatures)") + return + case <-signingSession.sigDoneC: + signaturesTimer.Stop() + for pubkey, sig := range signingSession.signatures { + if err := coordinator.AddSig(pubkey, sig); err != nil { + round.Fail(fmt.Errorf("failed to add signature: %s", err)) + log.WithError(err).Warn("failed to add signature") + return + } + } + } + + log.Debugf("signatures collected for round %s", round.Id) + + signedTree, err := coordinator.SignTree() + if err != nil { + round.Fail(fmt.Errorf("failed to aggragate tree signatures: %s", err)) + log.WithError(err).Warn("failed aggragate tree signatures") + return + } + + log.Debugf("congestion tree signed for round %s", round.Id) + tree = signedTree } @@ -578,6 +705,29 @@ func (s *covenantlessService) startFinalization() { log.Debugf("started finalization stage for round: %s", round.Id) } +func (s *covenantlessService) propagateRoundSigningStartedEvent( + unsignedCongestionTree tree.CongestionTree, cosigners []*secp256k1.PublicKey, +) { + ev := RoundSigningStarted{ + Id: s.currentRound.Id, + UnsignedVtxoTree: unsignedCongestionTree, + Cosigners: cosigners, + } + + s.lastEvent = ev + s.eventsCh <- ev +} + +func (s *covenantlessService) propagateRoundSigningNoncesGeneratedEvent(combinedNonces bitcointree.TreeNonces) { + ev := RoundSigningNoncesGenerated{ + Id: s.currentRound.Id, + Nonces: combinedNonces, + } + + s.lastEvent = ev + s.eventsCh <- ev +} + func (s *covenantlessService) createTreeCoordinatorSession( congestionTree tree.CongestionTree, cosigners []*secp256k1.PublicKey, root chainhash.Hash, ) (bitcointree.CoordinatorSession, error) { @@ -900,14 +1050,17 @@ func (s *covenantlessService) propagateEvents(round *domain.Round) { switch e := lastEvent.(type) { case domain.RoundFinalizationStarted: forfeitTxs := s.forfeitTxs.view() - s.eventsCh <- domain.RoundFinalizationStarted{ + ev := domain.RoundFinalizationStarted{ Id: e.Id, CongestionTree: e.CongestionTree, Connectors: e.Connectors, PoolTx: e.PoolTx, UnsignedForfeitTxs: forfeitTxs, } + s.lastEvent = ev + s.eventsCh <- ev case domain.RoundFinalized, domain.RoundFailed: + s.lastEvent = e s.eventsCh <- e } } @@ -1118,3 +1271,26 @@ func findForfeitTxBitcoin( return "", fmt.Errorf("forfeit tx not found") } + +// musigSigningSession holds the state of ephemeral nonces and signatures in order to coordinate the signing of the tree +type musigSigningSession struct { + lock sync.Mutex + nbCosigners int + nonces map[*secp256k1.PublicKey]bitcointree.TreeNonces + nonceDoneC chan struct{} + + signatures map[*secp256k1.PublicKey]bitcointree.TreePartialSigs + sigDoneC chan struct{} +} + +func newMusigSigningSession(nbCosigners int) *musigSigningSession { + return &musigSigningSession{ + nonces: make(map[*secp256k1.PublicKey]bitcointree.TreeNonces), + nonceDoneC: make(chan struct{}), + + signatures: make(map[*secp256k1.PublicKey]bitcointree.TreePartialSigs), + sigDoneC: make(chan struct{}), + lock: sync.Mutex{}, + nbCosigners: nbCosigners, + } +} diff --git a/server/internal/core/application/covenantless_event.go b/server/internal/core/application/covenantless_event.go new file mode 100644 index 0000000..485a76c --- /dev/null +++ b/server/internal/core/application/covenantless_event.go @@ -0,0 +1,43 @@ +/* +* This package contains intermediary events that are used only by the covenantless version +* they let to sign the congestion tree using musig2 algorithm +* they are not included in domain because they don't mutate the Round state and should not be persisted + */ +package application + +import ( + "bytes" + "encoding/hex" + + "github.com/ark-network/ark/common/bitcointree" + "github.com/ark-network/ark/common/tree" + "github.com/decred/dcrd/dcrec/secp256k1/v4" +) + +// signer should react to this event by generating a musig2 nonce for each transaction in the tree +type RoundSigningStarted struct { + Id string + UnsignedVtxoTree tree.CongestionTree + Cosigners []*secp256k1.PublicKey +} + +// signer should react to this event by partially signing the vtxo tree transactions +// then, delete its ephemeral key +type RoundSigningNoncesGenerated struct { + Id string + Nonces bitcointree.TreeNonces // aggregated nonces +} + +func (e RoundSigningNoncesGenerated) SerializeNonces() (string, error) { + var serialized bytes.Buffer + + if err := e.Nonces.Encode(&serialized); err != nil { + return "", err + } + + return hex.EncodeToString(serialized.Bytes()), nil +} + +// implement domain.RoundEvent interface +func (r RoundSigningStarted) IsEvent() {} +func (r RoundSigningNoncesGenerated) IsEvent() {} diff --git a/server/internal/core/application/sweeper.go b/server/internal/core/application/sweeper.go index 10674c9..33ddb38 100644 --- a/server/internal/core/application/sweeper.go +++ b/server/internal/core/application/sweeper.go @@ -149,7 +149,6 @@ func (s *sweeper) createTask( for _, input := range inputs { // sweepableVtxos related to the sweep input sweepableVtxos := make([]domain.VtxoKey, 0) - fmt.Println("input", input.GetHash().String(), input.GetIndex()) // check if input is the vtxo itself vtxos, _ := s.repoManager.Vtxos().GetVtxos( diff --git a/server/internal/core/application/types.go b/server/internal/core/application/types.go index c8c8cd1..45bb569 100644 --- a/server/internal/core/application/types.go +++ b/server/internal/core/application/types.go @@ -25,7 +25,7 @@ type Service interface { GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent UpdatePaymentStatus( ctx context.Context, paymentId string, - ) (unsignedForfeitTxs []string, currentRound *domain.Round, err error) + ) (lastEvent domain.RoundEvent, err error) ListVtxos( ctx context.Context, pubkey *secp256k1.PublicKey, ) (spendableVtxos, spentVtxos []domain.Vtxo, err error) @@ -41,6 +41,16 @@ type Service interface { CompleteAsyncPayment( ctx context.Context, redeemTx string, unconditionalForfeitTxs []string, ) error + // Tree signing methods + RegisterCosignerPubkey(ctx context.Context, paymentId string, ephemeralPublicKey string) error + RegisterCosignerNonces( + ctx context.Context, roundID string, + pubkey *secp256k1.PublicKey, nonces string, + ) error + RegisterCosignerSignatures( + ctx context.Context, roundID string, + pubkey *secp256k1.PublicKey, signatures string, + ) error } type ServiceInfo struct { diff --git a/server/internal/core/application/utils.go b/server/internal/core/application/utils.go index 93ede52..6cf1922 100644 --- a/server/internal/core/application/utils.go +++ b/server/internal/core/application/utils.go @@ -10,6 +10,7 @@ import ( "github.com/ark-network/ark/common/tree" "github.com/ark-network/ark/server/internal/core/domain" "github.com/ark-network/ark/server/internal/core/ports" + "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/sirupsen/logrus" ) @@ -20,8 +21,9 @@ type timedPayment struct { } type paymentsMap struct { - lock *sync.RWMutex - payments map[string]*timedPayment + lock *sync.RWMutex + payments map[string]*timedPayment + ephemeralKeys map[string]*secp256k1.PublicKey } func newPaymentsMap(payments []domain.Payment) *paymentsMap { @@ -30,7 +32,7 @@ func newPaymentsMap(payments []domain.Payment) *paymentsMap { paymentsById[p.Id] = &timedPayment{p, time.Now(), time.Time{}} } lock := &sync.RWMutex{} - return &paymentsMap{lock, paymentsById} + return &paymentsMap{lock, paymentsById, make(map[string]*secp256k1.PublicKey)} } func (m *paymentsMap) len() int64 { @@ -46,6 +48,18 @@ func (m *paymentsMap) len() int64 { return count } +func (m *paymentsMap) delete(id string) error { + m.lock.Lock() + defer m.lock.Unlock() + + if _, ok := m.payments[id]; !ok { + return errPaymentNotFound{id} + } + + delete(m.payments, id) + return nil +} + func (m *paymentsMap) push(payment domain.Payment) error { m.lock.Lock() defer m.lock.Unlock() @@ -58,7 +72,19 @@ func (m *paymentsMap) push(payment domain.Payment) error { return nil } -func (m *paymentsMap) pop(num int64) []domain.Payment { +func (m *paymentsMap) pushEphemeralKey(paymentId string, pubkey *secp256k1.PublicKey) error { + m.lock.Lock() + defer m.lock.Unlock() + + if _, ok := m.payments[paymentId]; !ok { + return fmt.Errorf("payment %s not found, cannot register signing ephemeral public key", paymentId) + } + + m.ephemeralKeys[paymentId] = pubkey + return nil +} + +func (m *paymentsMap) pop(num int64) ([]domain.Payment, []*secp256k1.PublicKey) { m.lock.Lock() defer m.lock.Unlock() @@ -83,11 +109,16 @@ func (m *paymentsMap) pop(num int64) []domain.Payment { } payments := make([]domain.Payment, 0, num) + cosigners := make([]*secp256k1.PublicKey, 0, num) for _, p := range paymentsByTime[:num] { payments = append(payments, p.Payment) + if pubkey, ok := m.ephemeralKeys[p.Payment.Id]; ok { + cosigners = append(cosigners, pubkey) + delete(m.ephemeralKeys, p.Payment.Id) + } delete(m.payments, p.Id) } - return payments + return payments, cosigners } func (m *paymentsMap) update(payment domain.Payment) error { diff --git a/server/internal/core/domain/events.go b/server/internal/core/domain/events.go index 2bd0ca7..9a2b14a 100644 --- a/server/internal/core/domain/events.go +++ b/server/internal/core/domain/events.go @@ -3,14 +3,14 @@ package domain import "github.com/ark-network/ark/common/tree" type RoundEvent interface { - isEvent() + IsEvent() } -func (r RoundStarted) isEvent() {} -func (r RoundFinalizationStarted) isEvent() {} -func (r RoundFinalized) isEvent() {} -func (r RoundFailed) isEvent() {} -func (r PaymentsRegistered) isEvent() {} +func (r RoundStarted) IsEvent() {} +func (r RoundFinalizationStarted) IsEvent() {} +func (r RoundFinalized) IsEvent() {} +func (r RoundFailed) IsEvent() {} +func (r PaymentsRegistered) IsEvent() {} type RoundStarted struct { Id string diff --git a/server/internal/interface/grpc/handlers/arkservice.go b/server/internal/interface/grpc/handlers/arkservice.go index f27b97c..434ab78 100644 --- a/server/internal/interface/grpc/handlers/arkservice.go +++ b/server/internal/interface/grpc/handlers/arkservice.go @@ -12,6 +12,7 @@ import ( "github.com/ark-network/ark/server/internal/core/domain" "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/google/uuid" + "github.com/sirupsen/logrus" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -118,25 +119,77 @@ func (h *handler) Ping(ctx context.Context, req *arkv1.PingRequest) (*arkv1.Ping return nil, status.Error(codes.InvalidArgument, "missing payment id") } - forfeits, round, err := h.svc.UpdatePaymentStatus(ctx, req.GetPaymentId()) + lastEvent, err := h.svc.UpdatePaymentStatus(ctx, req.GetPaymentId()) if err != nil { return nil, err } - var event *arkv1.RoundFinalizationEvent - if round != nil { - event = &arkv1.RoundFinalizationEvent{ - Id: round.Id, - PoolTx: round.UnsignedTx, - ForfeitTxs: forfeits, - CongestionTree: castCongestionTree(round.CongestionTree), - Connectors: round.Connectors, + var resp *arkv1.PingResponse + + switch e := lastEvent.(type) { + case domain.RoundFinalizationStarted: + resp = &arkv1.PingResponse{ + Event: &arkv1.PingResponse_RoundFinalization{ + RoundFinalization: &arkv1.RoundFinalizationEvent{ + Id: e.Id, + PoolTx: e.PoolTx, + CongestionTree: castCongestionTree(e.CongestionTree), + ForfeitTxs: e.UnsignedForfeitTxs, + Connectors: e.Connectors, + }, + }, + } + case domain.RoundFinalized: + resp = &arkv1.PingResponse{ + Event: &arkv1.PingResponse_RoundFinalized{ + RoundFinalized: &arkv1.RoundFinalizedEvent{ + Id: e.Id, + PoolTxid: e.Txid, + }, + }, + } + case domain.RoundFailed: + resp = &arkv1.PingResponse{ + Event: &arkv1.PingResponse_RoundFailed{ + RoundFailed: &arkv1.RoundFailed{ + Id: e.Id, + Reason: e.Err, + }, + }, + } + case application.RoundSigningStarted: + cosignersKeys := make([]string, 0, len(e.Cosigners)) + for _, key := range e.Cosigners { + cosignersKeys = append(cosignersKeys, hex.EncodeToString(key.SerializeCompressed())) + } + + resp = &arkv1.PingResponse{ + Event: &arkv1.PingResponse_RoundSigning{ + RoundSigning: &arkv1.RoundSigningEvent{ + Id: e.Id, + CosignersPubkeys: cosignersKeys, + UnsignedTree: castCongestionTree(e.UnsignedVtxoTree), + }, + }, + } + case application.RoundSigningNoncesGenerated: + serialized, err := e.SerializeNonces() + if err != nil { + logrus.WithError(err).Error("failed to serialize nonces") + return nil, status.Error(codes.Internal, "failed to serialize nonces") + } + + resp = &arkv1.PingResponse{ + Event: &arkv1.PingResponse_RoundSigningNoncesGenerated{ + RoundSigningNoncesGenerated: &arkv1.RoundSigningNoncesGeneratedEvent{ + Id: e.Id, + TreeNonces: serialized, + }, + }, } } - return &arkv1.PingResponse{ - ForfeitTxs: forfeits, - Event: event, - }, nil + + return resp, nil } func (h *handler) RegisterPayment(ctx context.Context, req *arkv1.RegisterPaymentRequest) (*arkv1.RegisterPaymentResponse, error) { @@ -150,6 +203,13 @@ func (h *handler) RegisterPayment(ctx context.Context, req *arkv1.RegisterPaymen return nil, err } + pubkey := req.GetEphemeralPubkey() + if len(pubkey) > 0 { + if err := h.svc.RegisterCosignerPubkey(ctx, id, pubkey); err != nil { + return nil, err + } + } + return &arkv1.RegisterPaymentResponse{ Id: id, }, nil @@ -267,14 +327,6 @@ func (h *handler) GetEventStream(_ *arkv1.GetEventStreamRequest, stream arkv1.Ar if err := stream.Send(ev); err != nil { return err } - - switch ev.Event.(type) { - case *arkv1.GetEventStreamResponse_RoundFinalized, *arkv1.GetEventStreamResponse_RoundFailed: - if err := stream.Send(ev); err != nil { - return err - } - return nil - } } } } @@ -312,6 +364,74 @@ func (h *handler) GetInfo(ctx context.Context, req *arkv1.GetInfoRequest) (*arkv }, nil } +func (h *handler) SendTreeNonces(ctx context.Context, req *arkv1.SendTreeNoncesRequest) (*arkv1.SendTreeNoncesResponse, error) { + pubkey := req.GetPublicKey() + encodedNonces := req.GetTreeNonces() + roundID := req.GetRoundId() + + if len(pubkey) <= 0 { + return nil, status.Error(codes.InvalidArgument, "missing cosigner public key") + } + + if len(encodedNonces) <= 0 { + return nil, status.Error(codes.InvalidArgument, "missing tree nonces") + } + + if len(roundID) <= 0 { + return nil, status.Error(codes.InvalidArgument, "missing round id") + } + + pubkeyBytes, err := hex.DecodeString(pubkey) + if err != nil { + return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key") + } + + cosignerPublicKey, err := secp256k1.ParsePubKey(pubkeyBytes) + if err != nil { + return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key") + } + + if err := h.svc.RegisterCosignerNonces(ctx, roundID, cosignerPublicKey, encodedNonces); err != nil { + return nil, err + } + + return &arkv1.SendTreeNoncesResponse{}, nil +} + +func (h *handler) SendTreeSignatures(ctx context.Context, req *arkv1.SendTreeSignaturesRequest) (*arkv1.SendTreeSignaturesResponse, error) { + roundID := req.GetRoundId() + pubkey := req.GetPublicKey() + encodedSignatures := req.GetTreeSignatures() + + if len(pubkey) <= 0 { + return nil, status.Error(codes.InvalidArgument, "missing cosigner public key") + } + + if len(encodedSignatures) <= 0 { + return nil, status.Error(codes.InvalidArgument, "missing tree signatures") + } + + if len(roundID) <= 0 { + return nil, status.Error(codes.InvalidArgument, "missing round id") + } + + pubkeyBytes, err := hex.DecodeString(pubkey) + if err != nil { + return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key") + } + + cosignerPublicKey, err := secp256k1.ParsePubKey(pubkeyBytes) + if err != nil { + return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key") + } + + if err := h.svc.RegisterCosignerSignatures(ctx, roundID, cosignerPublicKey, encodedSignatures); err != nil { + return nil, err + } + + return &arkv1.SendTreeSignaturesResponse{}, nil +} + func (h *handler) pushListener(l *listener) { h.listenersLock.Lock() defer h.listenersLock.Unlock() @@ -368,6 +488,36 @@ func (h *handler) listenToEvents() { }, }, } + case application.RoundSigningStarted: + cosignersKeys := make([]string, 0, len(e.Cosigners)) + for _, key := range e.Cosigners { + cosignersKeys = append(cosignersKeys, hex.EncodeToString(key.SerializeCompressed())) + } + + ev = &arkv1.GetEventStreamResponse{ + Event: &arkv1.GetEventStreamResponse_RoundSigning{ + RoundSigning: &arkv1.RoundSigningEvent{ + Id: e.Id, + CosignersPubkeys: cosignersKeys, + UnsignedTree: castCongestionTree(e.UnsignedVtxoTree), + }, + }, + } + case application.RoundSigningNoncesGenerated: + serialized, err := e.SerializeNonces() + if err != nil { + logrus.WithError(err).Error("failed to serialize nonces") + continue + } + + ev = &arkv1.GetEventStreamResponse{ + Event: &arkv1.GetEventStreamResponse_RoundSigningNoncesGenerated{ + RoundSigningNoncesGenerated: &arkv1.RoundSigningNoncesGeneratedEvent{ + Id: e.Id, + TreeNonces: serialized, + }, + }, + } } if ev != nil { diff --git a/server/internal/interface/grpc/permissions/permissions.go b/server/internal/interface/grpc/permissions/permissions.go index 8aded4a..dfa4336 100644 --- a/server/internal/interface/grpc/permissions/permissions.go +++ b/server/internal/interface/grpc/permissions/permissions.go @@ -161,6 +161,14 @@ func Whitelist() map[string][]bakery.Op { Entity: EntityHealth, Action: "read", }}, + fmt.Sprintf("/%s/SendTreeNonces", arkv1.ArkService_ServiceDesc.ServiceName): {{ + Entity: EntityArk, + Action: "write", + }}, + fmt.Sprintf("/%s/SendTreeSignatures", arkv1.ArkService_ServiceDesc.ServiceName): {{ + Entity: EntityArk, + Action: "write", + }}, } }