From 7f937e84181f9c3f8fa3770b12d78ce562a147e9 Mon Sep 17 00:00:00 2001 From: Pietralberto Mazza <18440657+altafan@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:57:16 +0100 Subject: [PATCH] Vars and fields renaming (#387) * Rename asp > server * Rename pool > round * Consolidate naming for pubkey/prvkey vars and types * Fix * Fix * Fix wasm * Rename congestionTree > vtxoTree * Fix wasm * Rename payment > request * Rename congestionTree > vtxoTree after syncing with master * Fix Send API in SDK * Fix wasm * Fix wasm * Fixes * Fixes after review * Fix * Fix naming * Fix * Fix e2e tests --- README.md | 6 +- .../swagger/ark/v1/service.swagger.json | 21 +- api-spec/protobuf/ark/v1/service.proto | 23 +- api-spec/protobuf/gen/ark/v1/service.pb.go | 877 +++++++++--------- api-spec/protobuf/gen/ark/v1/service.pb.gw.go | 22 +- client/main.go | 59 +- common/bitcointree/builder.go | 30 +- common/bitcointree/forfeit.go | 29 +- common/bitcointree/musig2.go | 28 +- common/bitcointree/musig2_test.go | 40 +- common/bitcointree/validation.go | 95 +- common/bitcointree/vtxo.go | 4 +- common/connectors.go | 8 +- common/descriptor/ark.go | 8 +- common/encoding.go | 16 +- common/encoding_test.go | 10 +- common/fees.go | 6 +- common/fixtures/encoding.json | 2 +- common/tree/builder.go | 32 +- common/tree/congestion_tree.go | 32 +- common/tree/forfeit.go | 12 +- common/tree/script.go | 6 +- common/tree/script_test.go | 78 +- common/tree/type.go | 4 +- common/tree/validation.go | 116 +-- common/tree/vtxo.go | 14 +- common/vtxo.go | 2 +- pkg/client-sdk/ark_sdk.go | 1 - pkg/client-sdk/client.go | 50 +- pkg/client-sdk/client/client.go | 30 +- pkg/client-sdk/client/grpc/client.go | 44 +- pkg/client-sdk/client/grpc/types.go | 14 +- pkg/client-sdk/client/rest/client.go | 56 +- .../ark_service/ark_service_client.go | 2 +- .../ark_service_ping_parameters.go | 23 +- .../ark_service/ark_service_ping_responses.go | 8 +- .../rest/service/models/v1_ownership_proof.go | 2 +- ...register_inputs_for_next_round_response.go | 4 +- ...register_outputs_for_next_round_request.go | 8 +- .../v1_submit_signed_forfeit_txs_request.go | 2 +- pkg/client-sdk/covenant_client.go | 93 +- pkg/client-sdk/covenantless_client.go | 342 ++++--- .../example/covenant/alice_to_bob.go | 6 +- .../example/covenant/wasm/index.html | 20 +- .../example/covenantless/alice_to_bob.go | 8 +- .../example/covenantless/wasm/index.html | 20 +- pkg/client-sdk/internal/utils/types.go | 2 +- pkg/client-sdk/internal/utils/utils.go | 4 +- pkg/client-sdk/redemption/covenant_redeem.go | 10 +- .../redemption/covenantless_redeem.go | 10 +- pkg/client-sdk/store/file/config_store.go | 4 +- pkg/client-sdk/store/file/types.go | 20 +- pkg/client-sdk/store/service_test.go | 4 +- pkg/client-sdk/test/wasm/wasm_test.go | 23 +- pkg/client-sdk/types.go | 12 +- pkg/client-sdk/types/types.go | 4 +- .../wallet/singlekey/bitcoin_wallet.go | 14 +- .../wallet/singlekey/liquid_wallet.go | 14 +- .../wallet/singlekey/store/file/store.go | 10 +- .../wallet/singlekey/store/store.go | 2 +- .../wallet/singlekey/store/store_test.go | 2 +- pkg/client-sdk/wallet/singlekey/wallet.go | 10 +- pkg/client-sdk/wallet/wallet_test.go | 4 +- pkg/client-sdk/wasm/browser/config_store.go | 16 +- pkg/client-sdk/wasm/browser/exports.go | 5 +- pkg/client-sdk/wasm/browser/wallet_store.go | 10 +- pkg/client-sdk/wasm/browser/wrappers.go | 42 +- server/README.md | 2 +- server/internal/core/application/admin.go | 10 +- server/internal/core/application/covenant.go | 90 +- .../internal/core/application/covenantless.go | 173 ++-- .../core/application/covenantless_event.go | 4 +- server/internal/core/application/errors.go | 6 +- server/internal/core/application/proof.go | 2 +- server/internal/core/application/sweeper.go | 58 +- server/internal/core/application/types.go | 12 +- server/internal/core/application/utils.go | 164 ++-- server/internal/core/domain/events.go | 10 +- server/internal/core/domain/payment.go | 48 +- server/internal/core/domain/payment_test.go | 32 +- server/internal/core/domain/round.go | 70 +- server/internal/core/domain/round_test.go | 150 +-- server/internal/core/ports/tx_builder.go | 10 +- .../infrastructure/db/badger/utils.go | 4 +- .../infrastructure/db/badger/vtxo_repo.go | 4 +- .../infrastructure/db/service_test.go | 60 +- .../migration/20240703120550_init.down.sql | 2 +- .../migration/20240703120550_init.up.sql | 32 +- .../infrastructure/db/sqlite/round_repo.go | 157 ++-- .../db/sqlite/sqlc/queries/models.go | 36 +- .../db/sqlite/sqlc/queries/query.sql.go | 326 +++---- .../infrastructure/db/sqlite/sqlc/query.sql | 68 +- .../infrastructure/db/sqlite/vtxo_repo.go | 10 +- .../tx-builder/covenant/builder.go | 82 +- .../tx-builder/covenant/builder_test.go | 40 +- .../covenant/testdata/fixtures.json | 16 +- .../tx-builder/covenant/utils.go | 30 +- .../tx-builder/covenantless/builder.go | 50 +- .../tx-builder/covenantless/builder_test.go | 42 +- .../covenantless/testdata/fixtures.json | 16 +- .../tx-builder/covenantless/utils.go | 26 +- .../wallet/btc-embedded/psbt.go | 2 +- .../wallet/btc-embedded/wallet.go | 66 +- .../interface/grpc/handlers/adminservice.go | 11 +- .../interface/grpc/handlers/arkservice.go | 75 +- .../interface/grpc/handlers/parser.go | 29 +- server/test/e2e/covenant/e2e_test.go | 12 +- server/test/e2e/covenantless/e2e_test.go | 39 +- server/test/e2e/test_utils.go | 6 +- 109 files changed, 2292 insertions(+), 2325 deletions(-) diff --git a/README.md b/README.md index cd4fae2..d8b9855 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,10 @@ For a quick-start with Docker, head over to our [Quick Start guide](https://arkd ## Repository Structure - [`api-spec`](./api-spec/): Ark Protocol Buffer API specification -- [`client`](./client/): `ark` Single-key wallet CLI for interacting with the ASP +- [`client`](./client/): `ark` Single-key wallet CLI for interacting with the server - [`common`](./common/): Shared code between the server and client -- [`pkg/client-sdk`](./pkg/client-sdk/): Go SDK for interacting with ASPs running the Ark protocol. It offers WASM bindings to interact with the SDK from the browser and other environments. -- [`server`](./server/): `arkd` Ark Service Provider (ASP) - the always-on daemon +- [`pkg/client-sdk`](./pkg/client-sdk/): Go SDK for interacting with servers running the Ark protocol. It offers WASM bindings to interact with the SDK from the browser and other environments. +- [`server`](./server/): `arkd` Ark server - the always-on daemon ## Development diff --git a/api-spec/openapi/swagger/ark/v1/service.swagger.json b/api-spec/openapi/swagger/ark/v1/service.swagger.json index 4e0ad2e..24d4dcb 100644 --- a/api-spec/openapi/swagger/ark/v1/service.swagger.json +++ b/api-spec/openapi/swagger/ark/v1/service.swagger.json @@ -163,7 +163,7 @@ ] } }, - "/v1/round/ping/{paymentId}": { + "/v1/round/ping/{requestId}": { "get": { "operationId": "ArkService_Ping", "responses": { @@ -182,7 +182,8 @@ }, "parameters": [ { - "name": "paymentId", + "name": "requestId", + "description": "The id used to register inputs and ouptuts.", "in": "path", "required": true, "type": "string" @@ -770,7 +771,7 @@ "title": "VTXO outpoint signed with script's secret key" } }, - "description": "This message is used to prove to the ASP that the user controls the vtxo without revealing the whole VTXO taproot tree." + "description": "This message is used to prove to the server that the user controls the vtxo without revealing the whole VTXO taproot tree." }, "v1PingResponse": { "type": "object" @@ -821,18 +822,16 @@ "v1RegisterInputsForNextRoundResponse": { "type": "object", "properties": { - "id": { - "type": "string", - "description": "Mocks wabisabi's blinded credentials." + "requestId": { + "type": "string" } } }, "v1RegisterOutputsForNextRoundRequest": { "type": "object", "properties": { - "id": { - "type": "string", - "description": "Mocks wabisabi's blinded credentials." + "requestId": { + "type": "string" }, "outputs": { "type": "array", @@ -840,7 +839,7 @@ "type": "object", "$ref": "#/definitions/v1Output" }, - "description": "List of receivers for a registered payment." + "description": "List of receivers for to convert to leaves in the next VTXO tree." } } }, @@ -1058,7 +1057,7 @@ }, "signedRoundTx": { "type": "string", - "description": "If payment has boarding input, the user must sign the associated inputs." + "description": "The user has to sign also the round tx if he registerd a boarding UTXO." } } }, diff --git a/api-spec/protobuf/ark/v1/service.proto b/api-spec/protobuf/ark/v1/service.proto index 9b1c42c..bc200b7 100755 --- a/api-spec/protobuf/ark/v1/service.proto +++ b/api-spec/protobuf/ark/v1/service.proto @@ -19,7 +19,7 @@ service ArkService { }; }; - /* In-Round Payment APIs */ + /* In-Round Transaction APIs */ rpc RegisterInputsForNextRound(RegisterInputsForNextRoundRequest) returns (RegisterInputsForNextRoundResponse) { option (google.api.http) = { @@ -58,10 +58,12 @@ service ArkService { }; rpc Ping(PingRequest) returns (PingResponse) { option (google.api.http) = { - get: "/v1/round/ping/{payment_id}" + get: "/v1/round/ping/{request_id}" }; }; + /* Out-of-Round Transaction APIs */ + rpc SubmitRedeemTx(SubmitRedeemTxRequest) returns (SubmitRedeemTxResponse) { option (google.api.http) = { post: "/v1/redeem-tx" @@ -134,7 +136,7 @@ message GetBoardingAddressResponse { } } -/* In-Round Payment API messages */ +/* In-Round Transaction API messages */ message RegisterInputsForNextRoundRequest { repeated Input inputs = 1; @@ -142,14 +144,12 @@ message RegisterInputsForNextRoundRequest { repeated string notes = 3; } message RegisterInputsForNextRoundResponse { - // Mocks wabisabi's blinded credentials. - string id = 1; + string request_id = 1; } message RegisterOutputsForNextRoundRequest { - // Mocks wabisabi's blinded credentials. - string id = 1; - // List of receivers for a registered payment. + string request_id = 1; + // List of receivers for to convert to leaves in the next VTXO tree. repeated Output outputs = 2; } message RegisterOutputsForNextRoundResponse {} @@ -171,7 +171,7 @@ message SubmitTreeSignaturesResponse {} message SubmitSignedForfeitTxsRequest { // Forfeit txs signed by the user. repeated string signed_forfeit_txs = 1; - // If payment has boarding input, the user must sign the associated inputs. + // The user has to sign also the round tx if he registerd a boarding UTXO. optional string signed_round_tx = 2; } message SubmitSignedForfeitTxsResponse {} @@ -188,7 +188,8 @@ message GetEventStreamResponse { } message PingRequest { - string payment_id = 1; + // The id used to register inputs and ouptuts. + string request_id = 1; } message PingResponse {} @@ -343,7 +344,7 @@ message RedeemTransaction { repeated Vtxo spendable_vtxos = 3; } -// This message is used to prove to the ASP that the user controls the vtxo without revealing the whole VTXO taproot tree. +// This message is used to prove to the server that the user controls the vtxo without revealing the whole VTXO taproot tree. message OwnershipProof { string control_block = 1; string script = 2; diff --git a/api-spec/protobuf/gen/ark/v1/service.pb.go b/api-spec/protobuf/gen/ark/v1/service.pb.go index b165c52..941ee40 100644 --- a/api-spec/protobuf/gen/ark/v1/service.pb.go +++ b/api-spec/protobuf/gen/ark/v1/service.pb.go @@ -439,8 +439,7 @@ type RegisterInputsForNextRoundResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Mocks wabisabi's blinded credentials. - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` } func (x *RegisterInputsForNextRoundResponse) Reset() { @@ -475,9 +474,9 @@ func (*RegisterInputsForNextRoundResponse) Descriptor() ([]byte, []int) { return file_ark_v1_service_proto_rawDescGZIP(), []int{5} } -func (x *RegisterInputsForNextRoundResponse) GetId() string { +func (x *RegisterInputsForNextRoundResponse) GetRequestId() string { if x != nil { - return x.Id + return x.RequestId } return "" } @@ -487,9 +486,8 @@ type RegisterOutputsForNextRoundRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Mocks wabisabi's blinded credentials. - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - // List of receivers for a registered payment. + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + // List of receivers for to convert to leaves in the next VTXO tree. Outputs []*Output `protobuf:"bytes,2,rep,name=outputs,proto3" json:"outputs,omitempty"` } @@ -525,9 +523,9 @@ func (*RegisterOutputsForNextRoundRequest) Descriptor() ([]byte, []int) { return file_ark_v1_service_proto_rawDescGZIP(), []int{6} } -func (x *RegisterOutputsForNextRoundRequest) GetId() string { +func (x *RegisterOutputsForNextRoundRequest) GetRequestId() string { if x != nil { - return x.Id + return x.RequestId } return "" } @@ -786,7 +784,7 @@ type SubmitSignedForfeitTxsRequest struct { // Forfeit txs signed by the user. SignedForfeitTxs []string `protobuf:"bytes,1,rep,name=signed_forfeit_txs,json=signedForfeitTxs,proto3" json:"signed_forfeit_txs,omitempty"` - // If payment has boarding input, the user must sign the associated inputs. + // The user has to sign also the round tx if he registerd a boarding UTXO. SignedRoundTx *string `protobuf:"bytes,2,opt,name=signed_round_tx,json=signedRoundTx,proto3,oneof" json:"signed_round_tx,omitempty"` } @@ -1040,7 +1038,8 @@ type PingRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - PaymentId string `protobuf:"bytes,1,opt,name=payment_id,json=paymentId,proto3" json:"payment_id,omitempty"` + // The id used to register inputs and ouptuts. + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` } func (x *PingRequest) Reset() { @@ -1075,9 +1074,9 @@ func (*PingRequest) Descriptor() ([]byte, []int) { return file_ark_v1_service_proto_rawDescGZIP(), []int{16} } -func (x *PingRequest) GetPaymentId() string { +func (x *PingRequest) GetRequestId() string { if x != nil { - return x.PaymentId + return x.RequestId } return "" } @@ -2658,7 +2657,7 @@ func (x *RedeemTransaction) GetSpendableVtxos() []*Vtxo { return nil } -// This message is used to prove to the ASP that the user controls the vtxo without revealing the whole VTXO taproot tree. +// This message is used to prove to the server that the user controls the vtxo without revealing the whole VTXO taproot tree. type OwnershipProof struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3136,433 +3135,435 @@ var file_ark_v1_service_proto_rawDesc = []byte{ 0x6c, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x70, - 0x75, 0x62, 0x6b, 0x65, 0x79, 0x22, 0x34, 0x0a, 0x22, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x75, 0x62, 0x6b, 0x65, 0x79, 0x22, 0x43, 0x0a, 0x22, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, - 0x75, 0x6e, 0x64, 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, 0x5e, 0x0a, 0x22, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, - 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 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, 0x25, 0x0a, 0x23, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, - 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x6d, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 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, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, - 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 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, 0x1a, 0x0a, 0x18, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, - 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x79, 0x0a, - 0x1b, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 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, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 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, 0x1e, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x6d, - 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8e, 0x01, 0x0a, 0x1d, 0x53, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, - 0x54, 0x78, 0x73, 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, 0x12, 0x2b, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x48, 0x00, 0x52, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x6e, 0x64, - 0x54, 0x78, 0x88, 0x01, 0x01, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, - 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, 0x22, 0x20, 0x0a, 0x1e, 0x53, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, - 0x54, 0x78, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 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, 0x0e, 0x0a, 0x0c, - 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x34, 0x0a, 0x15, - 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 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, 0x22, 0x42, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x64, 0x65, - 0x65, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x10, - 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x5f, 0x74, 0x78, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x52, 0x65, - 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 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, 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, 0xbb, 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, 0x19, - 0x0a, 0x08, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x78, 0x12, 0x29, 0x0a, 0x09, 0x76, 0x74, 0x78, - 0x6f, 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, 0x08, 0x76, 0x74, 0x78, 0x6f, - 0x54, 0x72, 0x65, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x73, 0x12, 0x2b, 0x0a, 0x12, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x6c, 0x61, - 0x79, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x65, 0x65, 0x52, 0x61, 0x74, - 0x65, 0x22, 0x44, 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, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x6e, - 0x64, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x6f, - 0x75, 0x6e, 0x64, 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, 0xb8, - 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, 0x3a, 0x0a, 0x12, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x76, 0x74, - 0x78, 0x6f, 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, 0x10, 0x75, 0x6e, 0x73, - 0x69, 0x67, 0x6e, 0x65, 0x64, 0x56, 0x74, 0x78, 0x6f, 0x54, 0x72, 0x65, 0x65, 0x12, 0x2a, 0x0a, - 0x11, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, - 0x74, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x64, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x78, 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, 0xf0, - 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, 0x19, 0x0a, 0x08, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x78, 0x12, 0x29, 0x0a, 0x09, 0x76, - 0x74, 0x78, 0x6f, 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, 0x08, 0x76, 0x74, - 0x78, 0x6f, 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, 0x32, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 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, 0x9d, 0x01, 0x0a, 0x05, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, - 0x2c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x20, 0x0a, - 0x0a, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, - 0x34, 0x0a, 0x0a, 0x74, 0x61, 0x70, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x70, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x48, 0x00, 0x52, 0x0a, 0x74, 0x61, 0x70, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x73, 0x42, 0x0e, 0x0a, 0x0c, 0x74, 0x61, 0x70, 0x72, 0x6f, 0x6f, 0x74, - 0x5f, 0x74, 0x72, 0x65, 0x65, 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, 0xc2, 0x02, 0x0a, 0x04, 0x56, 0x74, 0x78, 0x6f, 0x12, 0x2c, 0x0a, 0x08, 0x6f, - 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, - 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, - 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x70, 0x65, - 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x78, 0x69, 0x64, 0x12, 0x19, - 0x0a, 0x08, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x04, 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, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x65, 0x78, - 0x70, 0x69, 0x72, 0x65, 0x41, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x77, 0x65, 0x70, 0x74, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x73, 0x77, 0x65, 0x70, 0x74, 0x12, 0x1d, 0x0a, 0x0a, - 0x69, 0x73, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x09, 0x69, 0x73, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x72, - 0x65, 0x64, 0x65, 0x65, 0x6d, 0x5f, 0x74, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x1e, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8c, 0x01, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x72, 0x6f, 0x75, - 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x33, 0x0a, 0x06, 0x72, - 0x65, 0x64, 0x65, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x72, - 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, - 0x42, 0x04, 0x0a, 0x02, 0x74, 0x78, 0x22, 0xd8, 0x01, 0x0a, 0x10, 0x52, 0x6f, 0x75, 0x6e, 0x64, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, - 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, - 0x31, 0x0a, 0x0b, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, - 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x56, 0x74, 0x78, - 0x6f, 0x73, 0x12, 0x35, 0x0a, 0x0f, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, - 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x03, 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, 0x46, 0x0a, 0x16, 0x63, 0x6c, 0x61, - 0x69, 0x6d, 0x65, 0x64, 0x5f, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x74, - 0x78, 0x6f, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, - 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x14, 0x63, 0x6c, 0x61, - 0x69, 0x6d, 0x65, 0x64, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x22, 0x91, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x31, 0x0a, 0x0b, 0x73, - 0x70, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x52, 0x0a, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x35, - 0x0a, 0x0f, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x74, 0x78, 0x6f, - 0x73, 0x18, 0x03, 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, 0x22, 0x6b, 0x0a, 0x0e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, - 0x69, 0x70, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x16, 0x0a, 0x06, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x22, 0x70, 0x0a, 0x12, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x56, 0x74, 0x78, 0x6f, - 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, - 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, - 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, - 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x05, 0x70, - 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x75, 0x0a, 0x18, 0x53, 0x65, 0x74, 0x4e, 0x6f, 0x73, 0x74, 0x72, - 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x73, 0x74, 0x72, 0x5f, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, - 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6e, 0x6f, 0x73, 0x74, 0x72, - 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x74, 0x78, - 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x56, 0x74, 0x78, 0x6f, 0x4f, 0x75, 0x74, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x1b, 0x0a, 0x19, 0x53, - 0x65, 0x74, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4f, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x74, 0x78, 0x6f, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x56, 0x74, 0x78, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x52, 0x05, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x1e, 0x0a, 0x1c, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x0a, 0x0a, 0x54, 0x61, 0x70, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x73, 0x22, 0x85, 0x02, 0x0a, 0x0a, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x48, 0x6f, 0x75, 0x72, - 0x12, 0x42, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x65, 0x6e, 0x64, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x6e, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x64, - 0x54, 0x69, 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x40, 0x0a, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, - 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x72, 0x6f, 0x75, 0x6e, - 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 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, 0xf0, 0x0e, 0x0a, 0x0a, 0x41, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 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, 0x74, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x21, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x72, 0x6b, - 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x3a, 0x01, 0x2a, 0x22, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x62, - 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x98, 0x01, 0x0a, 0x1a, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, - 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x29, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, - 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2a, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, - 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x3a, 0x01, 0x2a, 0x22, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, - 0x75, 0x6e, 0x64, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, - 0x74, 0x73, 0x12, 0x9c, 0x01, 0x0a, 0x1b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, - 0x6e, 0x64, 0x12, 0x2a, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, - 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, - 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, - 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, - 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x1e, 0x3a, 0x01, 0x2a, 0x22, 0x19, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, - 0x64, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x73, 0x12, 0x7d, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, - 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 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, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x74, - 0x72, 0x65, 0x65, 0x2f, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, - 0x12, 0x8d, 0x01, 0x0a, 0x14, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x61, 0x72, 0x6b, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, - 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, - 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x3a, 0x01, 0x2a, 0x22, - 0x1f, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x74, 0x72, 0x65, 0x65, 0x2f, - 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, - 0x12, 0x8e, 0x01, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, - 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x25, 0x2e, 0x61, 0x72, - 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, - 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, - 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, - 0x78, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x1f, 0x3a, 0x01, 0x2a, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, - 0x2f, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, - 0x73, 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, + 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x6d, 0x0a, 0x22, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, + 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 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, 0x25, 0x0a, 0x23, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, + 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x6d, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 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, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 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, + 0x1a, 0x0a, 0x18, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, + 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x79, 0x0a, 0x1b, 0x53, + 0x75, 0x62, 0x6d, 0x69, 0x74, 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, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 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, 0x1e, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8e, 0x01, 0x0a, 0x1d, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, + 0x73, 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, 0x12, 0x2b, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x00, 0x52, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x78, + 0x88, 0x01, 0x01, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x72, + 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, 0x22, 0x20, 0x0a, 0x1e, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 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, 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, 0x56, 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, 0x23, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x70, - 0x69, 0x6e, 0x67, 0x2f, 0x7b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, - 0x12, 0x69, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, - 0x54, 0x78, 0x12, 0x1d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, - 0x69, 0x74, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, - 0x74, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x76, - 0x31, 0x2f, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x2d, 0x74, 0x78, 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, 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, 0x80, 0x01, 0x0a, 0x15, 0x47, 0x65, - 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x12, 0x24, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x72, 0x6b, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x30, 0x01, 0x12, 0x73, 0x0a, 0x11, - 0x53, 0x65, 0x74, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, - 0x74, 0x12, 0x20, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4e, 0x6f, - 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, + 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, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x0e, 0x0a, 0x0c, 0x50, 0x69, + 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x34, 0x0a, 0x15, 0x53, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 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, + 0x22, 0x42, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, + 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x69, + 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x5f, 0x74, 0x78, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x52, 0x65, 0x64, 0x65, + 0x65, 0x6d, 0x54, 0x78, 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, 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, 0xbb, 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, 0x19, 0x0a, 0x08, + 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x78, 0x12, 0x29, 0x0a, 0x09, 0x76, 0x74, 0x78, 0x6f, 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, 0x08, 0x76, 0x74, 0x78, 0x6f, 0x54, 0x72, + 0x65, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x73, 0x12, 0x2b, 0x0a, 0x12, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, + 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, + 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x22, + 0x44, 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, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, + 0x74, 0x78, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x6e, + 0x64, 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, 0xb8, 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, + 0x3a, 0x0a, 0x12, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x76, 0x74, 0x78, 0x6f, + 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, 0x10, 0x75, 0x6e, 0x73, 0x69, 0x67, + 0x6e, 0x65, 0x64, 0x56, 0x74, 0x78, 0x6f, 0x54, 0x72, 0x65, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x75, + 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x78, 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, 0xf0, 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, 0x19, + 0x0a, 0x08, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x78, 0x12, 0x29, 0x0a, 0x09, 0x76, 0x74, 0x78, + 0x6f, 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, 0x08, 0x76, 0x74, 0x78, 0x6f, + 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, + 0x32, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 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, 0x9d, 0x01, 0x0a, 0x05, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x2c, 0x0a, + 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0a, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x00, 0x52, 0x0a, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x34, 0x0a, + 0x0a, 0x74, 0x61, 0x70, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x70, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x73, 0x48, 0x00, 0x52, 0x0a, 0x74, 0x61, 0x70, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x73, 0x42, 0x0e, 0x0a, 0x0c, 0x74, 0x61, 0x70, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x74, + 0x72, 0x65, 0x65, 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, 0xc2, 0x02, 0x0a, 0x04, 0x56, 0x74, 0x78, 0x6f, 0x12, 0x2c, 0x0a, 0x08, 0x6f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, + 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, + 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, + 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x78, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, + 0x73, 0x70, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x04, 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, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x65, 0x78, 0x70, 0x69, + 0x72, 0x65, 0x41, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x77, 0x65, 0x70, 0x74, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x05, 0x73, 0x77, 0x65, 0x70, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, + 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, + 0x69, 0x73, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x64, + 0x65, 0x65, 0x6d, 0x5f, 0x74, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, + 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x1e, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8c, 0x01, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x48, 0x00, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x33, 0x0a, 0x06, 0x72, 0x65, 0x64, + 0x65, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x72, 0x6b, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x42, 0x04, + 0x0a, 0x02, 0x74, 0x78, 0x22, 0xd8, 0x01, 0x0a, 0x10, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x31, 0x0a, + 0x0b, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, + 0x12, 0x35, 0x0a, 0x0f, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x74, + 0x78, 0x6f, 0x73, 0x18, 0x03, 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, 0x46, 0x0a, 0x16, 0x63, 0x6c, 0x61, 0x69, 0x6d, + 0x65, 0x64, 0x5f, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x74, 0x78, 0x6f, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, + 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x14, 0x63, 0x6c, 0x61, 0x69, 0x6d, + 0x65, 0x64, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x22, + 0x91, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x31, 0x0a, 0x0b, 0x73, 0x70, 0x65, + 0x6e, 0x74, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x52, 0x0a, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x35, 0x0a, 0x0f, + 0x73, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, + 0x03, 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, 0x22, 0x6b, 0x0a, 0x0e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x22, 0x70, 0x0a, 0x12, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x56, 0x74, 0x78, 0x6f, 0x4f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, + 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x77, 0x6e, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x05, 0x70, 0x72, 0x6f, + 0x6f, 0x66, 0x22, 0x75, 0x0a, 0x18, 0x53, 0x65, 0x74, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, + 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, + 0x0a, 0x0f, 0x6e, 0x6f, 0x73, 0x74, 0x72, 0x5f, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, + 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x74, 0x78, 0x6f, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x56, 0x74, 0x78, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x52, 0x05, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x1b, 0x0a, 0x19, 0x53, 0x65, 0x74, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, - 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78, 0x6f, 0x2f, 0x6e, 0x6f, 0x73, 0x74, - 0x72, 0x12, 0x83, 0x01, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x73, 0x74, - 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x61, 0x72, 0x6b, - 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, - 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x24, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, - 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, - 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78, 0x6f, 0x2f, 0x6e, 0x6f, 0x73, 0x74, 0x72, - 0x2f, 0x64, 0x65, 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, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4f, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, + 0x67, 0x6e, 0x65, 0x64, 0x56, 0x74, 0x78, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x52, 0x05, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x1e, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x0a, 0x0a, 0x54, 0x61, 0x70, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x22, + 0x85, 0x02, 0x0a, 0x0a, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x48, 0x6f, 0x75, 0x72, 0x12, 0x42, + 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x6e, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x64, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x70, + 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x40, 0x0a, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 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, 0xf0, 0x0e, 0x0a, 0x0a, 0x41, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 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, + 0x74, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x21, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, + 0x65, 0x74, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x11, 0x3a, 0x01, 0x2a, 0x22, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x98, 0x01, 0x0a, 0x1a, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, + 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x29, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, + 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2a, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, + 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x1d, 0x3a, 0x01, 0x2a, 0x22, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, + 0x64, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, + 0x12, 0x9c, 0x01, 0x0a, 0x1b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, + 0x12, 0x2a, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, + 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x61, + 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1e, 0x3a, 0x01, 0x2a, 0x22, 0x19, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, + 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, + 0x7d, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, + 0x63, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 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, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x74, 0x72, 0x65, + 0x65, 0x2f, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x8d, + 0x01, 0x0a, 0x14, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x61, + 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, + 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x3a, 0x01, 0x2a, 0x22, 0x1f, 0x2f, + 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x74, 0x72, 0x65, 0x65, 0x2f, 0x73, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x8e, + 0x01, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, + 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x25, 0x2e, 0x61, 0x72, 0x6b, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, + 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x26, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, + 0x3a, 0x01, 0x2a, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x73, + 0x75, 0x62, 0x6d, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 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, 0x56, 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, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x70, 0x69, 0x6e, + 0x67, 0x2f, 0x7b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x69, + 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, + 0x12, 0x1d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, + 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x76, 0x31, 0x2f, + 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x2d, 0x74, 0x78, 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, 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, 0x80, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x12, 0x24, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, + 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x30, 0x01, 0x12, 0x73, 0x0a, 0x11, 0x53, 0x65, + 0x74, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, + 0x20, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4e, 0x6f, 0x73, 0x74, + 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x21, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4e, 0x6f, + 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, + 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78, 0x6f, 0x2f, 0x6e, 0x6f, 0x73, 0x74, 0x72, 0x12, + 0x83, 0x01, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, + 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, + 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, + 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, + 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x73, + 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, + 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78, 0x6f, 0x2f, 0x6e, 0x6f, 0x73, 0x74, 0x72, 0x2f, 0x64, + 0x65, 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 ( 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 5f203ac..898e499 100644 --- a/api-spec/protobuf/gen/ark/v1/service.pb.gw.go +++ b/api-spec/protobuf/gen/ark/v1/service.pb.gw.go @@ -233,14 +233,14 @@ func request_ArkService_Ping_0(ctx context.Context, marshaler runtime.Marshaler, _ = err ) - val, ok = pathParams["payment_id"] + val, ok = pathParams["request_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "payment_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "request_id") } - protoReq.PaymentId, err = runtime.String(val) + protoReq.RequestId, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "payment_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "request_id", err) } msg, err := client.Ping(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -259,14 +259,14 @@ func local_request_ArkService_Ping_0(ctx context.Context, marshaler runtime.Mars _ = err ) - val, ok = pathParams["payment_id"] + val, ok = pathParams["request_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "payment_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "request_id") } - protoReq.PaymentId, err = runtime.String(val) + protoReq.RequestId, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "payment_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "request_id", err) } msg, err := server.Ping(ctx, &protoReq) @@ -722,7 +722,7 @@ func RegisterArkServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ark.v1.ArkService/Ping", runtime.WithHTTPPathPattern("/v1/round/ping/{payment_id}")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ark.v1.ArkService/Ping", runtime.WithHTTPPathPattern("/v1/round/ping/{request_id}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1119,7 +1119,7 @@ func RegisterArkServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ark.v1.ArkService/Ping", runtime.WithHTTPPathPattern("/v1/round/ping/{payment_id}")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ark.v1.ArkService/Ping", runtime.WithHTTPPathPattern("/v1/round/ping/{request_id}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -1309,7 +1309,7 @@ var ( pattern_ArkService_GetEventStream_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "events"}, "")) - pattern_ArkService_Ping_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "round", "ping", "payment_id"}, "")) + pattern_ArkService_Ping_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "round", "ping", "request_id"}, "")) pattern_ArkService_SubmitRedeemTx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "redeem-tx"}, "")) diff --git a/client/main.go b/client/main.go index 233d60e..ecd3dd8 100644 --- a/client/main.go +++ b/client/main.go @@ -97,8 +97,8 @@ var ( Usage: "optional private key to encrypt", } urlFlag = &cli.StringFlag{ - Name: "asp-url", - Usage: "the url of the ASP to connect to", + Name: "server-url", + Usage: "the url of the Ark server to connect to", Required: true, } receiversFlag = &cli.StringFlag{ @@ -150,7 +150,7 @@ var ( var ( initCommand = cli.Command{ Name: "init", - Usage: "Initialize Ark wallet with encryption password, connect to ASP", + Usage: "Initialize Ark wallet with encryption password, connect to Ark server", Action: func(ctx *cli.Context) error { return initArkSdk(ctx) }, @@ -180,7 +180,7 @@ var ( } settleCmd = cli.Command{ Name: "settle", - Usage: "Settle onboarding funds or oor payments", + Usage: "Settle onboarding or pending funds", Action: func(ctx *cli.Context) error { return settle(ctx) }, @@ -196,7 +196,7 @@ var ( } sendCommand = cli.Command{ Name: "send", - Usage: "Send funds onchain, offchain, or asynchronously", + Usage: "Send funds offchain", Action: func(ctx *cli.Context) error { return send(ctx) }, @@ -243,7 +243,7 @@ func initArkSdk(ctx *cli.Context) error { ctx.Context, arksdk.InitArgs{ ClientType: clientType, WalletType: arksdk.SingleKeyWallet, - AspUrl: ctx.String(urlFlag.Name), + ServerUrl: ctx.String(urlFlag.Name), Seed: ctx.String(privateKeyFlag.Name), Password: string(password), ExplorerURL: ctx.String(explorerFlag.Name), @@ -258,8 +258,8 @@ func config(ctx *cli.Context) error { } cfg := map[string]interface{}{ - "asp_url": cfgData.AspUrl, - "asp_pubkey": hex.EncodeToString(cfgData.AspPubkey.SerializeCompressed()), + "server_url": cfgData.ServerUrl, + "server_pubkey": hex.EncodeToString(cfgData.ServerPubKey.SerializeCompressed()), "wallet_type": cfgData.WalletType, "client_tyep": cfgData.ClientType, "network": cfgData.Network.Name, @@ -368,7 +368,7 @@ func send(ctx *cli.Context) error { if isBitcoin { return sendCovenantLess(ctx, receivers) } - return sendCovenant(ctx.Context, receivers) + return sendCovenant(ctx, receivers) } func balance(ctx *cli.Context) error { @@ -525,9 +525,27 @@ func parseReceivers(receveirsJSON string, isBitcoin bool) ([]arksdk.Receiver, er } func sendCovenantLess(ctx *cli.Context, receivers []arksdk.Receiver) error { + var onchainReceivers, offchainReceivers []arksdk.Receiver + + for _, receiver := range receivers { + if receiver.IsOnchain() { + onchainReceivers = append(onchainReceivers, receiver) + } else { + offchainReceivers = append(offchainReceivers, receiver) + } + } + + if len(onchainReceivers) > 0 { + txid, err := arkSdkClient.SendOnChain(ctx.Context, onchainReceivers) + if err != nil { + return err + } + return printJSON(map[string]interface{}{"txid": txid}) + } + computeExpiration := ctx.Bool(enableExpiryCoinselectFlag.Name) - redeemTx, err := arkSdkClient.SendAsync( - ctx.Context, computeExpiration, receivers, + redeemTx, err := arkSdkClient.SendOffChain( + ctx.Context, computeExpiration, offchainReceivers, ) if err != nil { return err @@ -540,7 +558,7 @@ func sendCovenantLess(ctx *cli.Context, receivers []arksdk.Receiver) error { return printJSON(map[string]string{"txid": ptx.UnsignedTx.TxHash().String()}) } -func sendCovenant(ctx context.Context, receivers []arksdk.Receiver) error { +func sendCovenant(ctx *cli.Context, receivers []arksdk.Receiver) error { var onchainReceivers, offchainReceivers []arksdk.Receiver for _, receiver := range receivers { @@ -552,22 +570,21 @@ func sendCovenant(ctx context.Context, receivers []arksdk.Receiver) error { } if len(onchainReceivers) > 0 { - txID, err := arkSdkClient.SendOnChain(ctx, onchainReceivers) + txID, err := arkSdkClient.SendOnChain(ctx.Context, onchainReceivers) if err != nil { return err } return printJSON(map[string]interface{}{"txid": txID}) } - if len(offchainReceivers) > 0 { - txID, err := arkSdkClient.SendOffChain(ctx, false, offchainReceivers) - if err != nil { - return err - } - return printJSON(map[string]interface{}{"txid": txID}) + computeExpiration := ctx.Bool(enableExpiryCoinselectFlag.Name) + txid, err := arkSdkClient.SendOffChain( + ctx.Context, computeExpiration, offchainReceivers, + ) + if err != nil { + return err } - - return nil + return printJSON(map[string]interface{}{"txid": txid}) } func readPassword(ctx *cli.Context) ([]byte, error) { diff --git a/common/bitcointree/builder.go b/common/bitcointree/builder.go index b27d93a..271d740 100644 --- a/common/bitcointree/builder.go +++ b/common/bitcointree/builder.go @@ -17,11 +17,11 @@ import ( // CraftSharedOutput returns the taproot script and the amount of the initial root output func CraftSharedOutput( - cosigners []*secp256k1.PublicKey, aspPubkey *secp256k1.PublicKey, receivers []tree.VtxoLeaf, + cosigners []*secp256k1.PublicKey, server *secp256k1.PublicKey, receivers []tree.VtxoLeaf, feeSatsPerNode uint64, roundLifetime int64, ) ([]byte, int64, error) { aggregatedKey, _, err := createAggregatedKeyWithSweep( - cosigners, aspPubkey, roundLifetime, + cosigners, server, roundLifetime, ) if err != nil { return nil, 0, err @@ -34,21 +34,21 @@ func CraftSharedOutput( amount := root.getAmount() + int64(feeSatsPerNode) - scriptPubKey, err := common.P2TRScript(aggregatedKey.FinalKey) + scriptPubkey, err := common.P2TRScript(aggregatedKey.FinalKey) if err != nil { return nil, 0, err } - return scriptPubKey, amount, err + return scriptPubkey, amount, err } -// CraftCongestionTree creates all the tree's transactions -func CraftCongestionTree( - initialInput *wire.OutPoint, cosigners []*secp256k1.PublicKey, aspPubkey *secp256k1.PublicKey, receivers []tree.VtxoLeaf, +// BuildVtxoTree creates all the tree's transactions +func BuildVtxoTree( + initialInput *wire.OutPoint, cosigners []*secp256k1.PublicKey, server *secp256k1.PublicKey, receivers []tree.VtxoLeaf, feeSatsPerNode uint64, roundLifetime int64, -) (tree.CongestionTree, error) { +) (tree.VtxoTree, error) { aggregatedKey, sweepTapLeaf, err := createAggregatedKeyWithSweep( - cosigners, aspPubkey, roundLifetime, + cosigners, server, roundLifetime, ) if err != nil { return nil, err @@ -59,7 +59,7 @@ func CraftCongestionTree( return nil, err } - congestionTree := make(tree.CongestionTree, 0) + vtxoTree := make(tree.VtxoTree, 0) ins := []*wire.OutPoint{initialInput} nodes := []node{root} @@ -95,12 +95,12 @@ func CraftCongestionTree( } } - congestionTree = append(congestionTree, treeLevel) + vtxoTree = append(vtxoTree, treeLevel) nodes = append([]node{}, nextNodes...) ins = append([]*wire.OutPoint{}, nextInputsArgs...) } - return congestionTree, nil + return vtxoTree, nil } type node interface { @@ -252,7 +252,7 @@ func createRootNode( nodes := make([]node, 0, len(receivers)) for _, r := range receivers { - pubkeyBytes, err := hex.DecodeString(r.Pubkey) + pubkeyBytes, err := hex.DecodeString(r.PubKey) if err != nil { return nil, err } @@ -280,10 +280,10 @@ func createRootNode( } func createAggregatedKeyWithSweep( - cosigners []*secp256k1.PublicKey, aspPubkey *secp256k1.PublicKey, roundLifetime int64, + cosigners []*secp256k1.PublicKey, server *secp256k1.PublicKey, roundLifetime int64, ) (*musig2.AggregateKey, *psbt.TaprootTapLeafScript, error) { sweepClosure := &tree.CSVSigClosure{ - MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{aspPubkey}}, + MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{server}}, Seconds: uint(roundLifetime), } diff --git a/common/bitcointree/forfeit.go b/common/bitcointree/forfeit.go index 1706963..7ededd7 100644 --- a/common/bitcointree/forfeit.go +++ b/common/bitcointree/forfeit.go @@ -7,29 +7,24 @@ import ( ) func BuildForfeitTxs( - connectorTx *psbt.Packet, - vtxoInput *wire.OutPoint, - vtxoAmount, - connectorAmount, - feeAmount uint64, - vtxoScript, - aspScript []byte, + connectorTx *psbt.Packet, vtxoInput *wire.OutPoint, + vtxoAmount, connectorAmount, feeAmount uint64, + vtxoScript, serverScript []byte, ) (forfeitTxs []*psbt.Packet, err error) { + version := int32(2) + locktime := uint32(0) connectors, prevouts := getConnectorInputs(connectorTx, int64(connectorAmount)) for i, connectorInput := range connectors { connectorPrevout := prevouts[i] - partialTx, err := psbt.New( - []*wire.OutPoint{connectorInput, vtxoInput}, - []*wire.TxOut{{ - Value: int64(vtxoAmount) + int64(connectorAmount) - int64(feeAmount), - PkScript: aspScript, - }}, - 2, - 0, - []uint32{wire.MaxTxInSequenceNum, wire.MaxTxInSequenceNum}, - ) + ins := []*wire.OutPoint{connectorInput, vtxoInput} + outs := []*wire.TxOut{{ + Value: int64(vtxoAmount) + int64(connectorAmount) - int64(feeAmount), + PkScript: serverScript, + }} + sequences := []uint32{wire.MaxTxInSequenceNum, wire.MaxTxInSequenceNum} + partialTx, err := psbt.New(ins, outs, version, locktime, sequences) if err != nil { return nil, err } diff --git a/common/bitcointree/musig2.go b/common/bitcointree/musig2.go index f4ecfee..927e430 100644 --- a/common/bitcointree/musig2.go +++ b/common/bitcointree/musig2.go @@ -20,8 +20,8 @@ import ( ) var ( - ErrCongestionTreeNotSet = errors.New("congestion tree not set") - ErrAggregateKeyNotSet = errors.New("aggregate key not set") + ErrMissingVtxoTree = errors.New("missing vtxo tree") + ErrMissingAggregateKey = errors.New("missing aggregate key") ) type Musig2Nonce struct { @@ -62,7 +62,7 @@ type CoordinatorSession interface { AggregateNonces() (TreeNonces, error) AddSig(*btcec.PublicKey, TreePartialSigs) error // SignTree combines the signatures and add them to the tree's psbts - SignTree() (tree.CongestionTree, error) + SignTree() (tree.VtxoTree, error) } func (n TreeNonces) Encode(w io.Writer) error { @@ -111,7 +111,7 @@ func ValidateTreeSigs( scriptRoot []byte, finalAggregatedKey *btcec.PublicKey, roundSharedOutputAmount int64, - vtxoTree tree.CongestionTree, + vtxoTree tree.VtxoTree, ) error { prevoutFetcherFactory, err := prevOutFetcherFactory(finalAggregatedKey, vtxoTree, roundSharedOutputAmount) if err != nil { @@ -163,7 +163,7 @@ func ValidateTreeSigs( func NewTreeSignerSession( signer *btcec.PrivateKey, roundSharedOutputAmount int64, - vtxoTree tree.CongestionTree, + vtxoTree tree.VtxoTree, scriptRoot []byte, ) SignerSession { return &treeSignerSession{ @@ -176,7 +176,7 @@ func NewTreeSignerSession( type treeSignerSession struct { secretKey *btcec.PrivateKey - tree tree.CongestionTree + tree tree.VtxoTree myNonces [][]*musig2.Nonces keys []*btcec.PublicKey aggregateNonces TreeNonces @@ -187,7 +187,7 @@ type treeSignerSession struct { func (t *treeSignerSession) generateNonces() error { if t.tree == nil { - return ErrCongestionTreeNotSet + return ErrMissingVtxoTree } myNonces := make([][]*musig2.Nonces, 0) @@ -213,7 +213,7 @@ func (t *treeSignerSession) generateNonces() error { func (t *treeSignerSession) GetNonces() (TreeNonces, error) { if t.tree == nil { - return nil, ErrCongestionTreeNotSet + return nil, ErrMissingVtxoTree } if t.myNonces == nil { @@ -267,11 +267,11 @@ func (t *treeSignerSession) SetAggregatedNonces(nonces TreeNonces) error { func (t *treeSignerSession) Sign() (TreePartialSigs, error) { if t.tree == nil { - return nil, ErrCongestionTreeNotSet + return nil, ErrMissingVtxoTree } if t.keys == nil { - return nil, ErrAggregateKeyNotSet + return nil, ErrMissingAggregateKey } if t.aggregateNonces == nil { @@ -331,7 +331,7 @@ func (t *treeSignerSession) signPartial(partialTx *psbt.Packet, posx int, posy i type treeCoordinatorSession struct { scriptRoot []byte - tree tree.CongestionTree + tree tree.VtxoTree keys []*btcec.PublicKey nonces []TreeNonces sigs []TreePartialSigs @@ -340,7 +340,7 @@ type treeCoordinatorSession struct { func NewTreeCoordinatorSession( roundSharedOutputAmount int64, - vtxoTree tree.CongestionTree, + vtxoTree tree.VtxoTree, scriptRoot []byte, keys []*btcec.PublicKey, ) (CoordinatorSession, error) { @@ -428,7 +428,7 @@ func (t *treeCoordinatorSession) AggregateNonces() (TreeNonces, error) { } // SignTree implements CoordinatorSession. -func (t *treeCoordinatorSession) SignTree() (tree.CongestionTree, error) { +func (t *treeCoordinatorSession) SignTree() (tree.VtxoTree, error) { var missingSigs int for _, sig := range t.sigs { if sig == nil { @@ -508,7 +508,7 @@ func (t *treeCoordinatorSession) SignTree() (tree.CongestionTree, error) { func prevOutFetcherFactory( finalAggregatedKey *btcec.PublicKey, - vtxoTree tree.CongestionTree, + vtxoTree tree.VtxoTree, roundSharedOutputAmount int64, ) ( func(partial *psbt.Packet) (txscript.PrevOutputFetcher, error), diff --git a/common/bitcointree/musig2_test.go b/common/bitcointree/musig2_test.go index ad9c5ce..bfec381 100644 --- a/common/bitcointree/musig2_test.go +++ b/common/bitcointree/musig2_test.go @@ -28,33 +28,33 @@ func TestRoundTripSignTree(t *testing.T) { for _, f := range fixtures.Valid { // Generate 20 cosigners cosigners := make([]*secp256k1.PrivateKey, 20) - cosignerPubKeys := make([]*btcec.PublicKey, 20) + cosignerPubkeys := make([]*btcec.PublicKey, 20) for i := 0; i < 20; i++ { - privKey, err := secp256k1.GeneratePrivateKey() + prvkey, err := secp256k1.GeneratePrivateKey() require.NoError(t, err) - cosigners[i] = privKey - cosignerPubKeys[i] = privKey.PubKey() + cosigners[i] = prvkey + cosignerPubkeys[i] = prvkey.PubKey() } - asp, err := secp256k1.GeneratePrivateKey() + server, err := secp256k1.GeneratePrivateKey() require.NoError(t, err) _, sharedOutputAmount, err := bitcointree.CraftSharedOutput( - cosignerPubKeys, - asp.PubKey(), + cosignerPubkeys, + server.PubKey(), castReceivers(f.Receivers), minRelayFee, lifetime, ) require.NoError(t, err) - vtxoTree, err := bitcointree.CraftCongestionTree( + vtxoTree, err := bitcointree.BuildVtxoTree( &wire.OutPoint{ Hash: *testTxid, Index: 0, }, - cosignerPubKeys, - asp.PubKey(), + cosignerPubkeys, + server.PubKey(), castReceivers(f.Receivers), minRelayFee, lifetime, @@ -62,7 +62,7 @@ func TestRoundTripSignTree(t *testing.T) { require.NoError(t, err) sweepClosure := &tree.CSVSigClosure{ - MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{asp.PubKey()}}, + MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{server.PubKey()}}, Seconds: uint(lifetime), } @@ -73,11 +73,11 @@ func TestRoundTripSignTree(t *testing.T) { sweepTapTree := txscript.AssembleTaprootScriptTree(sweepTapLeaf) root := sweepTapTree.RootNode.TapHash() - aspCoordinator, err := bitcointree.NewTreeCoordinatorSession( + serverCoordinator, err := bitcointree.NewTreeCoordinatorSession( sharedOutputAmount, vtxoTree, root.CloneBytes(), - cosignerPubKeys, + cosignerPubkeys, ) require.NoError(t, err) @@ -91,16 +91,16 @@ func TestRoundTripSignTree(t *testing.T) { for i, session := range signerSessions { nonces, err := session.GetNonces() require.NoError(t, err) - err = aspCoordinator.AddNonce(cosignerPubKeys[i], nonces) + err = serverCoordinator.AddNonce(cosignerPubkeys[i], nonces) require.NoError(t, err) } - aggregatedNonce, err := aspCoordinator.AggregateNonces() + aggregatedNonce, err := serverCoordinator.AggregateNonces() require.NoError(t, err) // Set keys and aggregated nonces for all signers for _, session := range signerSessions { - err = session.SetKeys(cosignerPubKeys) + err = session.SetKeys(cosignerPubkeys) require.NoError(t, err) err = session.SetAggregatedNonces(aggregatedNonce) require.NoError(t, err) @@ -110,15 +110,15 @@ func TestRoundTripSignTree(t *testing.T) { for i, session := range signerSessions { sig, err := session.Sign() require.NoError(t, err) - err = aspCoordinator.AddSig(cosignerPubKeys[i], sig) + err = serverCoordinator.AddSig(cosignerPubkeys[i], sig) require.NoError(t, err) } - signedTree, err := aspCoordinator.SignTree() + signedTree, err := serverCoordinator.SignTree() require.NoError(t, err) // verify the tree - aggregatedKey, err := bitcointree.AggregateKeys(cosignerPubKeys, root.CloneBytes()) + aggregatedKey, err := bitcointree.AggregateKeys(cosignerPubkeys, root.CloneBytes()) require.NoError(t, err) err = bitcointree.ValidateTreeSigs( @@ -140,7 +140,7 @@ func castReceivers(receivers []receiverFixture) []tree.VtxoLeaf { receiversOut := make([]tree.VtxoLeaf, 0, len(receivers)) for _, r := range receivers { receiversOut = append(receiversOut, tree.VtxoLeaf{ - Pubkey: r.Pubkey, + PubKey: r.Pubkey, Amount: uint64(r.Amount), }) } diff --git a/common/bitcointree/validation.go b/common/bitcointree/validation.go index bb9dc6e..eec211a 100644 --- a/common/bitcointree/validation.go +++ b/common/bitcointree/validation.go @@ -2,7 +2,6 @@ package bitcointree import ( "bytes" - "errors" "fmt" "strings" @@ -15,36 +14,36 @@ import ( ) var ( - ErrInvalidPoolTransaction = errors.New("invalid pool transaction") - ErrInvalidPoolTransactionOutputs = errors.New("invalid number of outputs in pool transaction") - ErrEmptyTree = errors.New("empty congestion tree") - ErrInvalidRootLevel = errors.New("root level must have only one node") - ErrNoLeaves = errors.New("no leaves in the tree") - ErrNodeTransactionEmpty = errors.New("node transaction is empty") - ErrNodeTxidEmpty = errors.New("node txid is empty") - ErrNodeParentTxidEmpty = errors.New("node parent txid is empty") - ErrNodeTxidDifferent = errors.New("node txid differs from node transaction") - ErrNumberOfInputs = errors.New("node transaction should have only one input") - ErrNumberOfOutputs = errors.New("node transaction should have only three or two outputs") - ErrParentTxidInput = errors.New("parent txid should be the input of the node transaction") - ErrNumberOfChildren = errors.New("node branch transaction should have two children") - ErrLeafChildren = errors.New("leaf node should have max 1 child") - ErrInvalidChildTxid = errors.New("invalid child txid") - ErrNumberOfTapscripts = errors.New("input should have 1 tapscript leaf") - ErrInternalKey = errors.New("invalid taproot internal key") - ErrInvalidTaprootScript = errors.New("invalid taproot script") - ErrInvalidControlBlock = errors.New("invalid control block") - ErrInvalidTaprootScriptLen = errors.New("invalid taproot script length (expected 32 bytes)") - ErrInvalidLeafTaprootScript = errors.New("invalid leaf taproot script") - ErrInvalidAmount = errors.New("children amount is different from parent amount") - ErrInvalidSweepSequence = errors.New("invalid sweep sequence") - ErrInvalidASP = errors.New("invalid ASP") - ErrMissingFeeOutput = errors.New("missing fee output") - ErrInvalidLeftOutput = errors.New("invalid left output") - ErrInvalidRightOutput = errors.New("invalid right output") - ErrMissingSweepTapscript = errors.New("missing sweep tapscript") - ErrInvalidLeaf = errors.New("leaf node shouldn't have children") - ErrWrongPoolTxID = errors.New("root input should be the pool tx outpoint") + ErrInvalidRoundTx = fmt.Errorf("invalid round transaction") + ErrInvalidRoundTxOutputs = fmt.Errorf("invalid number of outputs in round transaction") + ErrEmptyTree = fmt.Errorf("empty vtxo tree") + ErrInvalidRootLevel = fmt.Errorf("root level must have only one node") + ErrNoLeaves = fmt.Errorf("no leaves in the tree") + ErrNodeTxEmpty = fmt.Errorf("node transaction is empty") + ErrNodeTxidEmpty = fmt.Errorf("node txid is empty") + ErrNodeParentTxidEmpty = fmt.Errorf("node parent txid is empty") + ErrNodeTxidDifferent = fmt.Errorf("node txid differs from node transaction") + ErrNumberOfInputs = fmt.Errorf("node transaction should have only one input") + ErrNumberOfOutputs = fmt.Errorf("node transaction should have only three or two outputs") + ErrParentTxidInput = fmt.Errorf("parent txid should be the input of the node transaction") + ErrNumberOfChildren = fmt.Errorf("node branch transaction should have two children") + ErrLeafChildren = fmt.Errorf("leaf node should have max 1 child") + ErrInvalidChildTxid = fmt.Errorf("invalid child txid") + ErrNumberOfTapscripts = fmt.Errorf("input should have 1 tapscript leaf") + ErrInternalKey = fmt.Errorf("invalid taproot internal key") + ErrInvalidTaprootScript = fmt.Errorf("invalid taproot script") + ErrInvalidControlBlock = fmt.Errorf("invalid control block") + ErrInvalidTaprootScriptLen = fmt.Errorf("invalid taproot script length (expected 32 bytes)") + ErrInvalidLeafTaprootScript = fmt.Errorf("invalid leaf taproot script") + ErrInvalidAmount = fmt.Errorf("children amount is different from parent amount") + ErrInvalidSweepSequence = fmt.Errorf("invalid sweep sequence") + ErrInvalidServer = fmt.Errorf("invalid server") + ErrMissingFeeOutput = fmt.Errorf("missing fee output") + ErrInvalidLeftOutput = fmt.Errorf("invalid left output") + ErrInvalidRightOutput = fmt.Errorf("invalid right output") + ErrMissingSweepTapscript = fmt.Errorf("missing sweep tapscript") + ErrInvalidLeaf = fmt.Errorf("leaf node shouldn't have children") + ErrWrongRoundTxid = fmt.Errorf("the input of the tree root is not the round tx's shared output") ) // 0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 @@ -62,28 +61,28 @@ func UnspendableKey() *secp256k1.PublicKey { return key } -// ValidateCongestionTree checks if the given congestion tree is valid -// poolTxID & poolTxIndex & poolTxAmount are used to validate the root input outpoint -// aspPublicKey & roundLifetime are used to validate the sweep tapscript leaves +// ValidateVtxoTree checks if the given vtxo tree is valid +// roundTxid & roundTxIndex & roundTxAmount are used to validate the root input outpoint +// serverPubkey & roundLifetime are used to validate the sweep tapscript leaves // besides that, the function validates: // - the number of nodes // - the number of leaves // - children coherence with parent // - every control block and taproot output scripts // - input and output amounts -func ValidateCongestionTree( - vtxoTree tree.CongestionTree, poolTx string, aspPublicKey *secp256k1.PublicKey, roundLifetime int64, +func ValidateVtxoTree( + vtxoTree tree.VtxoTree, roundTx string, serverPubkey *secp256k1.PublicKey, roundLifetime int64, ) error { - poolTransaction, err := psbt.NewFromRawBytes(strings.NewReader(poolTx), true) + roundTransaction, err := psbt.NewFromRawBytes(strings.NewReader(roundTx), true) if err != nil { - return ErrInvalidPoolTransaction + return ErrInvalidRoundTx } - if len(poolTransaction.Outputs) < sharedOutputIndex+1 { - return ErrInvalidPoolTransactionOutputs + if len(roundTransaction.Outputs) < sharedOutputIndex+1 { + return ErrInvalidRoundTxOutputs } - poolTxAmount := poolTransaction.UnsignedTx.TxOut[sharedOutputIndex].Value + roundTxAmount := roundTransaction.UnsignedTx.TxOut[sharedOutputIndex].Value nbNodes := vtxoTree.NumberOfNodes() if nbNodes == 0 { @@ -94,7 +93,7 @@ func ValidateCongestionTree( return ErrInvalidRootLevel } - // check that root input is connected to the pool tx + // check that root input is connected to the round tx rootPsetB64 := vtxoTree[0][0].Tx rootPset, err := psbt.NewFromRawBytes(strings.NewReader(rootPsetB64), true) if err != nil { @@ -106,9 +105,9 @@ func ValidateCongestionTree( } rootInput := rootPset.UnsignedTx.TxIn[0] - if chainhash.Hash(rootInput.PreviousOutPoint.Hash).String() != poolTransaction.UnsignedTx.TxHash().String() || + if chainhash.Hash(rootInput.PreviousOutPoint.Hash).String() != roundTransaction.UnsignedTx.TxHash().String() || rootInput.PreviousOutPoint.Index != sharedOutputIndex { - return ErrWrongPoolTxID + return ErrWrongRoundTxid } sumRootValue := int64(0) @@ -116,7 +115,7 @@ func ValidateCongestionTree( sumRootValue += output.Value } - if sumRootValue >= poolTxAmount { + if sumRootValue >= roundTxAmount { return ErrInvalidAmount } @@ -125,7 +124,7 @@ func ValidateCongestionTree( } sweepClosure := &tree.CSVSigClosure{ - MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{aspPublicKey}}, + MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{serverPubkey}}, Seconds: uint(roundLifetime), } @@ -152,9 +151,9 @@ func ValidateCongestionTree( return nil } -func validateNodeTransaction(node tree.Node, tree tree.CongestionTree, tapTreeRoot []byte) error { +func validateNodeTransaction(node tree.Node, tree tree.VtxoTree, tapTreeRoot []byte) error { if node.Tx == "" { - return ErrNodeTransactionEmpty + return ErrNodeTxEmpty } if node.Txid == "" { diff --git a/common/bitcointree/vtxo.go b/common/bitcointree/vtxo.go index 97d86d5..a65de3c 100644 --- a/common/bitcointree/vtxo.go +++ b/common/bitcointree/vtxo.go @@ -26,8 +26,8 @@ func ParseVtxoScript(scripts []string) (VtxoScript, error) { return nil, fmt.Errorf("invalid vtxo scripts: %s", scripts) } -func NewDefaultVtxoScript(owner, asp *secp256k1.PublicKey, exitDelay uint) VtxoScript { - base := tree.NewDefaultVtxoScript(owner, asp, exitDelay) +func NewDefaultVtxoScript(owner, server *secp256k1.PublicKey, exitDelay uint) VtxoScript { + base := tree.NewDefaultVtxoScript(owner, server, exitDelay) return &TapscriptsVtxoScript{*base} } diff --git a/common/connectors.go b/common/connectors.go index 572a640..bafebcf 100644 --- a/common/connectors.go +++ b/common/connectors.go @@ -7,14 +7,14 @@ import ( "github.com/vulpemventures/go-elements/psetv2" ) -func ValidateConnectors(poolTx string, connectors []string) error { - ptx, err := psetv2.NewPsetFromBase64(poolTx) +func ValidateConnectors(roundTx string, connectors []string) error { + ptx, err := psetv2.NewPsetFromBase64(roundTx) if err != nil { - return fmt.Errorf("invalid pool tx: %s", err) + return fmt.Errorf("invalid round tx: %s", err) } utx, err := ptx.UnsignedTx() if err != nil { - return fmt.Errorf("invalid pool tx: %s", err) + return fmt.Errorf("invalid round tx: %s", err) } prevConnectorTxid := utx.TxHash().String() prevConnectorVout := uint32(1) diff --git a/common/descriptor/ark.go b/common/descriptor/ark.go index f2805cd..ce15b5c 100644 --- a/common/descriptor/ark.go +++ b/common/descriptor/ark.go @@ -8,12 +8,12 @@ import ( "github.com/decred/dcrd/dcrec/secp256k1/v4" ) -// tr(unspendable, { and(pk(user), pk(asp)), and(older(timeout), pk(user)) }) +// tr(unspendable, { and(pk(user), pk(server)), and(older(timeout), pk(user)) }) const DefaultVtxoDescriptorTemplate = "tr(%s,{ and(pk(%s), pk(%s)), and(older(%d), pk(%s)) })" func ParseDefaultVtxoDescriptor( descriptor string, -) (user, asp *secp256k1.PublicKey, timeout uint, err error) { +) (user, server *secp256k1.PublicKey, timeout uint, err error) { desc, err := ParseTaprootDescriptor(descriptor) if err != nil { return nil, nil, 0, err @@ -42,7 +42,7 @@ func ParseDefaultVtxoDescriptor( return nil, nil, 0, err } - asp, err = schnorr.ParsePubKey(keyBytes) + server, err = schnorr.ParsePubKey(keyBytes) if err != nil { return nil, nil, 0, err } @@ -70,7 +70,7 @@ func ParseDefaultVtxoDescriptor( return nil, nil, 0, errors.New("boarding descriptor is invalid") } - if asp == nil { + if server == nil { return nil, nil, 0, errors.New("boarding descriptor is invalid") } diff --git a/common/encoding.go b/common/encoding.go index d719e63..662d492 100644 --- a/common/encoding.go +++ b/common/encoding.go @@ -8,24 +8,24 @@ import ( "github.com/decred/dcrd/dcrec/secp256k1/v4" ) -// Address represents an Ark address with HRP, ASP public key, and VTXO Taproot public key +// Address represents an Ark address with HRP, server public key, and VTXO Taproot public key type Address struct { HRP string - Asp *secp256k1.PublicKey + Server *secp256k1.PublicKey VtxoTapKey *secp256k1.PublicKey } // Encode converts the address to its bech32m string representation func (a *Address) Encode() (string, error) { - if a.Asp == nil { - return "", fmt.Errorf("missing asp public key") + if a.Server == nil { + return "", fmt.Errorf("missing server public key") } if a.VtxoTapKey == nil { return "", fmt.Errorf("missing vtxo tap public key") } combinedKey := append( - schnorr.SerializePubKey(a.Asp), schnorr.SerializePubKey(a.VtxoTapKey)..., + schnorr.SerializePubKey(a.Server), schnorr.SerializePubKey(a.VtxoTapKey)..., ) grp, err := bech32.ConvertBits(combinedKey, 8, 5, true) if err != nil { @@ -52,19 +52,19 @@ func DecodeAddress(addr string) (*Address, error) { return nil, err } - aKey, err := schnorr.ParsePubKey(grp[:32]) + serverKey, err := schnorr.ParsePubKey(grp[:32]) if err != nil { return nil, fmt.Errorf("failed to parse public key: %s", err) } vtxoKey, err := schnorr.ParsePubKey(grp[32:]) if err != nil { - return nil, fmt.Errorf("failed to parse asp public key: %s", err) + return nil, fmt.Errorf("failed to parse server public key: %s", err) } return &Address{ HRP: prefix, - Asp: aKey, + Server: serverKey, VtxoTapKey: vtxoKey, }, nil } diff --git a/common/encoding_test.go b/common/encoding_test.go index b64e002..ad03773 100644 --- a/common/encoding_test.go +++ b/common/encoding_test.go @@ -25,9 +25,9 @@ func TestAddressEncoding(t *testing.T) { fixtures := struct { Address struct { Valid []struct { - Addr string `json:"addr"` - ExpectedUserKey string `json:"expectedUserKey"` - ExpectedAspKey string `json:"expectedAspKey"` + Addr string `json:"addr"` + ExpectedUserKey string `json:"expectedUserKey"` + ExpectedServerKey string `json:"expectedServerKey"` } `json:"valid"` Invalid []struct { Addr string `json:"addr"` @@ -43,14 +43,14 @@ func TestAddressEncoding(t *testing.T) { addr, err := common.DecodeAddress(f.Addr) require.NoError(t, err) require.NotEmpty(t, addr.HRP) - require.NotNil(t, addr.Asp) + require.NotNil(t, addr.Server) require.NotNil(t, addr.VtxoTapKey) require.NoError(t, err) require.Equal(t, f.ExpectedUserKey, hex.EncodeToString(addr.VtxoTapKey.SerializeCompressed())) require.NoError(t, err) - require.Equal(t, f.ExpectedAspKey, hex.EncodeToString(addr.Asp.SerializeCompressed())) + require.Equal(t, f.ExpectedServerKey, hex.EncodeToString(addr.Server.SerializeCompressed())) encoded, err := addr.Encode() require.NoError(t, err) diff --git a/common/fees.go b/common/fees.go index 777086c..dba4474 100644 --- a/common/fees.go +++ b/common/fees.go @@ -30,7 +30,7 @@ func ComputeForfeitTxFee( feeRate chainfee.SatPerKVByte, tapscript *waddrmgr.Tapscript, witnessSize int, - aspScriptClass txscript.ScriptClass, + serverScriptClass txscript.ScriptClass, ) (uint64, error) { txWeightEstimator := &input.TxWeightEstimator{} @@ -40,7 +40,7 @@ func ComputeForfeitTxFee( tapscript, ) - switch aspScriptClass { + switch serverScriptClass { case txscript.PubKeyHashTy: txWeightEstimator.AddP2PKHOutput() case txscript.ScriptHashTy: @@ -52,7 +52,7 @@ func ComputeForfeitTxFee( case txscript.WitnessV1TaprootTy: txWeightEstimator.AddP2TROutput() default: - return 0, fmt.Errorf("unknown asp script class: %v", aspScriptClass) + return 0, fmt.Errorf("unknown server script class: %v", serverScriptClass) } return uint64(feeRate.FeeForVSize(lntypes.VByte(txWeightEstimator.VSize())).ToUnit(btcutil.AmountSatoshi)), nil diff --git a/common/fixtures/encoding.json b/common/fixtures/encoding.json index 7502ebe..1b2a8c6 100644 --- a/common/fixtures/encoding.json +++ b/common/fixtures/encoding.json @@ -4,7 +4,7 @@ { "addr": "tark1x0lm8hhr2wc6n6lyemtyh9rz8rg2ftpkfun46aca56kjg3ws0tsztfpuanaquxc6faedvjk3tax0575y6perapg3e95654pk8r4fjecs5fyd2", "expectedUserKey": "0225a43cecfa0e1b1a4f72d64ad15f4cfa7a84d0723e8511c969aa543638ea9967", - "expectedAspKey": "0233ffb3dee353b1a9ebe4ced64b946238d0a4ac364f275d771da6ad2445d07ae0" + "expectedServerKey": "0233ffb3dee353b1a9ebe4ced64b946238d0a4ac364f275d771da6ad2445d07ae0" } ], "invalid": [ diff --git a/common/tree/builder.go b/common/tree/builder.go index 4668bf2..2d3066f 100644 --- a/common/tree/builder.go +++ b/common/tree/builder.go @@ -12,15 +12,15 @@ import ( "github.com/vulpemventures/go-elements/taproot" ) -func CraftCongestionTree( - asset string, aspPubkey *secp256k1.PublicKey, receivers []VtxoLeaf, +func BuildVtxoTree( + asset string, serverPubkey *secp256k1.PublicKey, receivers []VtxoLeaf, feeSatsPerNode uint64, roundLifetime int64, ) ( - buildCongestionTree TreeFactory, + factoryFn TreeFactory, sharedOutputScript []byte, sharedOutputAmount uint64, err error, ) { - root, err := createPartialCongestionTree( - asset, aspPubkey, receivers, feeSatsPerNode, roundLifetime, + root, err := buildTreeNodes( + asset, serverPubkey, receivers, feeSatsPerNode, roundLifetime, ) if err != nil { return @@ -36,7 +36,7 @@ func CraftCongestionTree( return } sharedOutputAmount = root.getAmount() + root.feeSats - buildCongestionTree = root.createFinalCongestionTree() + factoryFn = root.buildVtxoTree() return } @@ -321,16 +321,16 @@ func (n *node) getTx( return pset, nil } -func (n *node) createFinalCongestionTree() TreeFactory { - return func(poolTxInput psetv2.InputArgs) (CongestionTree, error) { - congestionTree := make(CongestionTree, 0) +func (n *node) buildVtxoTree() TreeFactory { + return func(roundTxInput psetv2.InputArgs) (VtxoTree, error) { + vtxoTree := make(VtxoTree, 0) _, taprootTree, err := n.getWitnessData() if err != nil { return nil, err } - ins := []psetv2.InputArgs{poolTxInput} + ins := []psetv2.InputArgs{roundTxInput} inTrees := []*taproot.IndexedElementsTapScriptTree{taprootTree} nodes := []*node{n} @@ -366,7 +366,7 @@ func (n *node) createFinalCongestionTree() TreeFactory { } } - congestionTree = append(congestionTree, treeLevel) + vtxoTree = append(vtxoTree, treeLevel) nodes = append([]*node{}, nextNodes...) ins = append([]psetv2.InputArgs{}, nextInputsArgs...) inTrees = append( @@ -374,12 +374,12 @@ func (n *node) createFinalCongestionTree() TreeFactory { ) } - return congestionTree, nil + return vtxoTree, nil } } -func createPartialCongestionTree( - asset string, aspPubkey *secp256k1.PublicKey, receivers []VtxoLeaf, +func buildTreeNodes( + asset string, serverPubkey *secp256k1.PublicKey, receivers []VtxoLeaf, feeSatsPerNode uint64, roundLifetime int64, ) (root *node, err error) { if len(receivers) == 0 { @@ -388,7 +388,7 @@ func createPartialCongestionTree( nodes := make([]*node, 0, len(receivers)) for _, r := range receivers { - pubkeyBytes, err := hex.DecodeString(r.Pubkey) + pubkeyBytes, err := hex.DecodeString(r.PubKey) if err != nil { return nil, err } @@ -399,7 +399,7 @@ func createPartialCongestionTree( } leafNode := &node{ - sweepKey: aspPubkey, + sweepKey: serverPubkey, receivers: []vtxoOutput{{pubkey, r.Amount}}, asset: asset, feeSats: feeSatsPerNode, diff --git a/common/tree/congestion_tree.go b/common/tree/congestion_tree.go index b11f360..d150c6e 100644 --- a/common/tree/congestion_tree.go +++ b/common/tree/congestion_tree.go @@ -4,7 +4,7 @@ import ( "errors" ) -// Node is a struct embedding the transaction and the parent txid of a congestion tree node +// Node is a struct embedding the transaction and the parent txid of a vtxo tree node type Node struct { Txid string Tx string @@ -14,28 +14,28 @@ type Node struct { var ( ErrParentNotFound = errors.New("parent not found") - ErrLeafNotFound = errors.New("leaf not found in congestion tree") + ErrLeafNotFound = errors.New("leaf not found in vtxo tree") ) -// CongestionTree is reprensented as a matrix of TreeNode struct +// VtxoTree is reprensented as a matrix of TreeNode struct // the first level of the matrix is the root of the tree -type CongestionTree [][]Node +type VtxoTree [][]Node -// Root returns the root node of the congestion tree -func (c CongestionTree) Root() (Node, error) { +// Root returns the root node of the vtxo tree +func (c VtxoTree) Root() (Node, error) { if len(c) <= 0 { - return Node{}, errors.New("empty congestion tree") + return Node{}, errors.New("empty vtxo tree") } if len(c[0]) <= 0 { - return Node{}, errors.New("empty congestion tree") + return Node{}, errors.New("empty vtxo tree") } return c[0][0], nil } -// Leaves returns the leaves of the congestion tree (the vtxos txs) -func (c CongestionTree) Leaves() []Node { +// Leaves returns the leaves of the vtxo tree +func (c VtxoTree) Leaves() []Node { leaves := c[len(c)-1] for _, level := range c[:len(c)-1] { for _, node := range level { @@ -49,7 +49,7 @@ func (c CongestionTree) Leaves() []Node { } // Children returns all the nodes that have the given node as parent -func (c CongestionTree) Children(nodeTxid string) []Node { +func (c VtxoTree) Children(nodeTxid string) []Node { var children []Node for _, level := range c { for _, node := range level { @@ -62,8 +62,8 @@ func (c CongestionTree) Children(nodeTxid string) []Node { return children } -// NumberOfNodes returns the total number of pset in the congestion tree -func (c CongestionTree) NumberOfNodes() int { +// NumberOfNodes returns the total number of pset in the vtxo tree +func (c VtxoTree) NumberOfNodes() int { var count int for _, level := range c { count += len(level) @@ -71,8 +71,8 @@ func (c CongestionTree) NumberOfNodes() int { return count } -// Branch returns the branch of the given vtxo txid from root to leaf in the order of the congestion tree -func (c CongestionTree) Branch(vtxoTxid string) ([]Node, error) { +// Branch returns the branch of the given vtxo txid from root to leaf in the order of the vtxo tree +func (c VtxoTree) Branch(vtxoTxid string) ([]Node, error) { branch := make([]Node, 0) leaves := c.Leaves() @@ -102,7 +102,7 @@ func (c CongestionTree) Branch(vtxoTxid string) ([]Node, error) { return branch, nil } -func (n Node) findParent(tree CongestionTree) (Node, error) { +func (n Node) findParent(tree VtxoTree) (Node, error) { for _, level := range tree { for _, node := range level { if node.Txid == n.ParentTxid { diff --git a/common/tree/forfeit.go b/common/tree/forfeit.go index 2451f4f..1b7e614 100644 --- a/common/tree/forfeit.go +++ b/common/tree/forfeit.go @@ -8,13 +8,9 @@ import ( ) func BuildForfeitTxs( - connectorTx *psetv2.Pset, - vtxoInput psetv2.InputArgs, - vtxoAmount, - connectorAmount, - feeAmount uint64, - vtxoScript, - aspScript []byte, + connectorTx *psetv2.Pset, vtxoInput psetv2.InputArgs, + vtxoAmount, connectorAmount, feeAmount uint64, + vtxoScript, serverScript []byte, ) (forfeitTxs []*psetv2.Pset, err error) { connectors, prevouts := getConnectorInputs(connectorTx, connectorAmount) @@ -63,7 +59,7 @@ func BuildForfeitTxs( { Asset: asset, Amount: vtxoAmount + connectorAmount - feeAmount, - Script: aspScript, + Script: serverScript, }, { Asset: asset, diff --git a/common/tree/script.go b/common/tree/script.go index 726a69c..9a04d99 100644 --- a/common/tree/script.go +++ b/common/tree/script.go @@ -281,10 +281,10 @@ func (f *MultisigClosure) Witness(controlBlock []byte, signatures map[string][]b // Add signatures in the reverse order as public keys for i := len(f.PubKeys) - 1; i >= 0; i-- { - pubKey := f.PubKeys[i] - sig, ok := signatures[hex.EncodeToString(schnorr.SerializePubKey(pubKey))] + pubkey := f.PubKeys[i] + sig, ok := signatures[hex.EncodeToString(schnorr.SerializePubKey(pubkey))] if !ok { - return nil, fmt.Errorf("missing signature for public key %x", schnorr.SerializePubKey(pubKey)) + return nil, fmt.Errorf("missing signature for public key %x", schnorr.SerializePubKey(pubkey)) } witness = append(witness, sig) } diff --git a/common/tree/script_test.go b/common/tree/script_test.go index 18e6026..f38ab13 100644 --- a/common/tree/script_test.go +++ b/common/tree/script_test.go @@ -36,17 +36,17 @@ func TestRoundTripCSV(t *testing.T) { func TestMultisigClosure(t *testing.T) { // Generate some test keys - privKey1, err := secp256k1.GeneratePrivateKey() + prvkey1, err := secp256k1.GeneratePrivateKey() require.NoError(t, err) - pubKey1 := privKey1.PubKey() + pubkey1 := prvkey1.PubKey() - privKey2, err := secp256k1.GeneratePrivateKey() + prvkey2, err := secp256k1.GeneratePrivateKey() require.NoError(t, err) - pubKey2 := privKey2.PubKey() + pubkey2 := prvkey2.PubKey() t.Run("valid 2-of-2 multisig", func(t *testing.T) { closure := &tree.MultisigClosure{ - PubKeys: []*secp256k1.PublicKey{pubKey1, pubKey2}, + PubKeys: []*secp256k1.PublicKey{pubkey1, pubkey2}, } // Generate script @@ -62,18 +62,18 @@ func TestMultisigClosure(t *testing.T) { // Compare serialized pubkeys require.Equal(t, - schnorr.SerializePubKey(pubKey1), + schnorr.SerializePubKey(pubkey1), schnorr.SerializePubKey(decodedClosure.PubKeys[0]), ) require.Equal(t, - schnorr.SerializePubKey(pubKey2), + schnorr.SerializePubKey(pubkey2), schnorr.SerializePubKey(decodedClosure.PubKeys[1]), ) }) t.Run("valid single key multisig", func(t *testing.T) { closure := &tree.MultisigClosure{ - PubKeys: []*secp256k1.PublicKey{pubKey1}, + PubKeys: []*secp256k1.PublicKey{pubkey1}, } script, err := closure.Script() @@ -87,7 +87,7 @@ func TestMultisigClosure(t *testing.T) { // Compare serialized pubkey require.Equal(t, - schnorr.SerializePubKey(pubKey1), + schnorr.SerializePubKey(pubkey1), schnorr.SerializePubKey(decodedClosure.PubKeys[0]), ) }) @@ -110,9 +110,9 @@ func TestMultisigClosure(t *testing.T) { }) t.Run("invalid script - missing checksig", func(t *testing.T) { - pubKeyBytes := schnorr.SerializePubKey(pubKey1) + pubkeyBytes := schnorr.SerializePubKey(pubkey1) script := []byte{txscript.OP_DATA_32} - script = append(script, pubKeyBytes...) + script = append(script, pubkeyBytes...) // Missing OP_CHECKSIG closure := &tree.MultisigClosure{} @@ -122,9 +122,9 @@ func TestMultisigClosure(t *testing.T) { }) t.Run("invalid script - extra data after checksig", func(t *testing.T) { - pubKeyBytes := schnorr.SerializePubKey(pubKey1) + pubkeyBytes := schnorr.SerializePubKey(pubkey1) script := []byte{txscript.OP_DATA_32} - script = append(script, pubKeyBytes...) + script = append(script, pubkeyBytes...) script = append(script, txscript.OP_CHECKSIG) script = append(script, 0x00) // Extra unwanted byte @@ -136,7 +136,7 @@ func TestMultisigClosure(t *testing.T) { t.Run("witness size", func(t *testing.T) { closure := &tree.MultisigClosure{ - PubKeys: []*secp256k1.PublicKey{pubKey1, pubKey2}, + PubKeys: []*secp256k1.PublicKey{pubkey1, pubkey2}, } require.Equal(t, 128, closure.WitnessSize()) // 64 * 2 bytes @@ -144,15 +144,15 @@ func TestMultisigClosure(t *testing.T) { t.Run("valid 12-of-12 multisig", func(t *testing.T) { // Generate 12 keys - pubKeys := make([]*secp256k1.PublicKey, 12) + pubkeys := make([]*secp256k1.PublicKey, 12) for i := 0; i < 12; i++ { - privKey, err := secp256k1.GeneratePrivateKey() + prvkey, err := secp256k1.GeneratePrivateKey() require.NoError(t, err) - pubKeys[i] = privKey.PubKey() + pubkeys[i] = prvkey.PubKey() } closure := &tree.MultisigClosure{ - PubKeys: pubKeys, + PubKeys: pubkeys, } // Generate script @@ -169,7 +169,7 @@ func TestMultisigClosure(t *testing.T) { // Compare all serialized pubkeys for i := 0; i < 12; i++ { require.Equal(t, - schnorr.SerializePubKey(pubKeys[i]), + schnorr.SerializePubKey(pubkeys[i]), schnorr.SerializePubKey(decodedClosure.PubKeys[i]), ) } @@ -181,18 +181,18 @@ func TestMultisigClosure(t *testing.T) { func TestCSVSigClosure(t *testing.T) { // Generate test keys - privKey1, err := secp256k1.GeneratePrivateKey() + prvkey1, err := secp256k1.GeneratePrivateKey() require.NoError(t, err) - pubKey1 := privKey1.PubKey() + pubkey1 := prvkey1.PubKey() - privKey2, err := secp256k1.GeneratePrivateKey() + prvkey2, err := secp256k1.GeneratePrivateKey() require.NoError(t, err) - pubKey2 := privKey2.PubKey() + pubkey2 := prvkey2.PubKey() t.Run("valid single key CSV", func(t *testing.T) { csvSig := &tree.CSVSigClosure{ MultisigClosure: tree.MultisigClosure{ - PubKeys: []*secp256k1.PublicKey{pubKey1}, + PubKeys: []*secp256k1.PublicKey{pubkey1}, }, Seconds: 1024, } @@ -207,7 +207,7 @@ func TestCSVSigClosure(t *testing.T) { require.Equal(t, uint32(1024), uint32(decodedCSV.Seconds)) require.Equal(t, 1, len(decodedCSV.PubKeys)) require.Equal(t, - schnorr.SerializePubKey(pubKey1), + schnorr.SerializePubKey(pubkey1), schnorr.SerializePubKey(decodedCSV.PubKeys[0]), ) }) @@ -215,7 +215,7 @@ func TestCSVSigClosure(t *testing.T) { t.Run("valid 2-of-2 CSV", func(t *testing.T) { csvSig := &tree.CSVSigClosure{ MultisigClosure: tree.MultisigClosure{ - PubKeys: []*secp256k1.PublicKey{pubKey1, pubKey2}, + PubKeys: []*secp256k1.PublicKey{pubkey1, pubkey2}, }, Seconds: 2016, // ~2 weeks } @@ -230,11 +230,11 @@ func TestCSVSigClosure(t *testing.T) { require.Equal(t, uint32(2016), uint32(decodedCSV.Seconds)) require.Equal(t, 2, len(decodedCSV.PubKeys)) require.Equal(t, - schnorr.SerializePubKey(pubKey1), + schnorr.SerializePubKey(pubkey1), schnorr.SerializePubKey(decodedCSV.PubKeys[0]), ) require.Equal(t, - schnorr.SerializePubKey(pubKey2), + schnorr.SerializePubKey(pubkey2), schnorr.SerializePubKey(decodedCSV.PubKeys[1]), ) }) @@ -248,9 +248,9 @@ func TestCSVSigClosure(t *testing.T) { t.Run("invalid CSV value", func(t *testing.T) { // Create a script with invalid CSV value - pubKeyBytes := schnorr.SerializePubKey(pubKey1) + pubkeyBytes := schnorr.SerializePubKey(pubkey1) script := []byte{txscript.OP_DATA_32} - script = append(script, pubKeyBytes...) + script = append(script, pubkeyBytes...) script = append(script, txscript.OP_CHECKSIG) script = append(script, 0xFF) // Invalid CSV value @@ -263,7 +263,7 @@ func TestCSVSigClosure(t *testing.T) { t.Run("witness size", func(t *testing.T) { csvSig := &tree.CSVSigClosure{ MultisigClosure: tree.MultisigClosure{ - PubKeys: []*secp256k1.PublicKey{pubKey1, pubKey2}, + PubKeys: []*secp256k1.PublicKey{pubkey1, pubkey2}, }, Seconds: 1024, } @@ -274,7 +274,7 @@ func TestCSVSigClosure(t *testing.T) { t.Run("max timelock", func(t *testing.T) { csvSig := &tree.CSVSigClosure{ MultisigClosure: tree.MultisigClosure{ - PubKeys: []*secp256k1.PublicKey{pubKey1}, + PubKeys: []*secp256k1.PublicKey{pubkey1}, }, Seconds: 65535, // Maximum allowed value } @@ -438,22 +438,22 @@ func TestCSVSigClosureWitness(t *testing.T) { func TestDecodeChecksigAdd(t *testing.T) { // Generate some test public keys - pubKey1, err := secp256k1.GeneratePrivateKey() + pubkey1, err := secp256k1.GeneratePrivateKey() require.NoError(t, err) - pubKey2, err := secp256k1.GeneratePrivateKey() + pubkey2, err := secp256k1.GeneratePrivateKey() require.NoError(t, err) - pubKey3, err := secp256k1.GeneratePrivateKey() + pubkey3, err := secp256k1.GeneratePrivateKey() require.NoError(t, err) - pubKeys := []*secp256k1.PublicKey{pubKey1.PubKey(), pubKey2.PubKey(), pubKey3.PubKey()} + pubkeys := []*secp256k1.PublicKey{pubkey1.PubKey(), pubkey2.PubKey(), pubkey3.PubKey()} // Create a script for 3-of-3 multisig using CHECKSIGADD scriptBuilder := txscript.NewScriptBuilder(). - AddData(schnorr.SerializePubKey(pubKeys[0])). + AddData(schnorr.SerializePubKey(pubkeys[0])). AddOp(txscript.OP_CHECKSIG). - AddData(schnorr.SerializePubKey(pubKeys[1])). + AddData(schnorr.SerializePubKey(pubkeys[1])). AddOp(txscript.OP_CHECKSIGADD). - AddData(schnorr.SerializePubKey(pubKeys[2])). + AddData(schnorr.SerializePubKey(pubkeys[2])). AddOp(txscript.OP_CHECKSIGADD). AddInt64(3). AddOp(txscript.OP_EQUAL) diff --git a/common/tree/type.go b/common/tree/type.go index aee6f45..68d90c2 100644 --- a/common/tree/type.go +++ b/common/tree/type.go @@ -4,9 +4,9 @@ import ( "github.com/vulpemventures/go-elements/psetv2" ) -type TreeFactory func(outpoint psetv2.InputArgs) (CongestionTree, error) +type TreeFactory func(outpoint psetv2.InputArgs) (VtxoTree, error) type VtxoLeaf struct { - Pubkey string + PubKey string Amount uint64 } diff --git a/common/tree/validation.go b/common/tree/validation.go index affc6c2..163c500 100644 --- a/common/tree/validation.go +++ b/common/tree/validation.go @@ -13,37 +13,37 @@ import ( ) var ( - ErrInvalidPoolTransaction = errors.New("invalid pool transaction") - ErrInvalidPoolTransactionOutputs = errors.New("invalid number of outputs in pool transaction") - ErrEmptyTree = errors.New("empty congestion tree") - ErrInvalidRootLevel = errors.New("root level must have only one node") - ErrNoLeaves = errors.New("no leaves in the tree") - ErrNodeTransactionEmpty = errors.New("node transaction is empty") - ErrNodeTxidEmpty = errors.New("node txid is empty") - ErrNodeParentTxidEmpty = errors.New("node parent txid is empty") - ErrNodeTxidDifferent = errors.New("node txid differs from node transaction") - ErrNumberOfInputs = errors.New("node transaction should have only one input") - ErrNumberOfOutputs = errors.New("node transaction should have only three or two outputs") - ErrParentTxidInput = errors.New("parent txid should be the input of the node transaction") - ErrNumberOfChildren = errors.New("node branch transaction should have two children") - ErrLeafChildren = errors.New("leaf node should have max 1 child") - ErrInvalidChildTxid = errors.New("invalid child txid") - ErrNumberOfTapscripts = errors.New("input should have two tapscripts leaves") - ErrInternalKey = errors.New("taproot internal key is not unspendable") - ErrInvalidTaprootScript = errors.New("invalid taproot script") - ErrInvalidTaprootScriptLen = errors.New("invalid taproot script length (expected 32 bytes)") - ErrInvalidLeafTaprootScript = errors.New("invalid leaf taproot script") - ErrInvalidAmount = errors.New("children amount is different from parent amount") - ErrInvalidAsset = errors.New("invalid output asset") - ErrInvalidSweepSequence = errors.New("invalid sweep sequence") - ErrInvalidASP = errors.New("invalid ASP") - ErrMissingFeeOutput = errors.New("missing fee output") - ErrInvalidLeftOutput = errors.New("invalid left output") - ErrInvalidRightOutput = errors.New("invalid right output") - ErrMissingSweepTapscript = errors.New("missing sweep tapscript") - ErrMissingBranchTapscript = errors.New("missing branch tapscript") - ErrInvalidLeaf = errors.New("leaf node shouldn't have children") - ErrWrongPoolTxID = errors.New("root input should be the pool tx outpoint") + ErrInvalidRoundTx = fmt.Errorf("invalid round transaction") + ErrInvalidRoundTxOutputs = fmt.Errorf("invalid number of outputs in round transaction") + ErrEmptyTree = fmt.Errorf("empty vtxo tree") + ErrInvalidRootLevel = fmt.Errorf("root level must have only one node") + ErrNoLeaves = fmt.Errorf("no leaves in the tree") + ErrNodeTxEmpty = fmt.Errorf("node transaction is empty") + ErrNodeTxidEmpty = fmt.Errorf("node txid is empty") + ErrNodeParentTxidEmpty = fmt.Errorf("node parent txid is empty") + ErrNodeTxidDifferent = fmt.Errorf("node txid differs from node transaction") + ErrNumberOfInputs = fmt.Errorf("node transaction should have only one input") + ErrNumberOfOutputs = fmt.Errorf("node transaction should have only three or two outputs") + ErrParentTxidInput = fmt.Errorf("parent txid should be the input of the node transaction") + ErrNumberOfChildren = fmt.Errorf("node branch transaction should have two children") + ErrLeafChildren = fmt.Errorf("leaf node should have max 1 child") + ErrInvalidChildTxid = fmt.Errorf("invalid child txid") + ErrNumberOfTapscripts = fmt.Errorf("input should have 1 tapscript leaf") + ErrInternalKey = fmt.Errorf("invalid taproot internal key") + ErrInvalidTaprootScript = fmt.Errorf("invalid taproot script") + ErrInvalidTaprootScriptLen = fmt.Errorf("invalid taproot script length (expected 32 bytes)") + ErrInvalidLeafTaprootScript = fmt.Errorf("invalid leaf taproot script") + ErrInvalidAmount = fmt.Errorf("children amount is different from parent amount") + ErrInvalidAsset = errors.New("invalid output asset") + ErrInvalidSweepSequence = fmt.Errorf("invalid sweep sequence") + ErrInvalidServer = fmt.Errorf("invalid server") + ErrMissingFeeOutput = fmt.Errorf("missing fee output") + ErrInvalidLeftOutput = fmt.Errorf("invalid left output") + ErrInvalidRightOutput = fmt.Errorf("invalid right output") + ErrMissingSweepTapscript = fmt.Errorf("missing sweep tapscript") + ErrMissingBranchTapscript = errors.New("missing branch tapscript") + ErrInvalidLeaf = fmt.Errorf("leaf node shouldn't have children") + ErrWrongRoundTxid = fmt.Errorf("the input of the tree root is not the round tx's shared output") ) // 0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 @@ -61,36 +61,36 @@ func UnspendableKey() *secp256k1.PublicKey { return key } -// ValidateCongestionTree checks if the given congestion tree is valid -// poolTxID & poolTxIndex & poolTxAmount are used to validate the root input outpoint -// aspPublicKey & roundLifetime are used to validate the sweep tapscript leaves +// ValidateVtxoTree checks if the given vtxo tree is valid +// roundTxid & roundTxIndex & roundTxAmount are used to validate the root input outpoint +// serverPubkey & roundLifetime are used to validate the sweep tapscript leaves // besides that, the function validates: // - the number of nodes // - the number of leaves // - children coherence with parent // - every control block and taproot output scripts // - input and output amounts -func ValidateCongestionTree( - tree CongestionTree, poolTx string, aspPublicKey *secp256k1.PublicKey, +func ValidateVtxoTree( + tree VtxoTree, roundTx string, serverPubkey *secp256k1.PublicKey, roundLifetime int64, ) error { - poolTransaction, err := psetv2.NewPsetFromBase64(poolTx) + roundTransaction, err := psetv2.NewPsetFromBase64(roundTx) if err != nil { - return ErrInvalidPoolTransaction + return ErrInvalidRoundTx } - if len(poolTransaction.Outputs) < sharedOutputIndex+1 { - return ErrInvalidPoolTransactionOutputs + if len(roundTransaction.Outputs) < sharedOutputIndex+1 { + return ErrInvalidRoundTxOutputs } - poolTxAmount := poolTransaction.Outputs[sharedOutputIndex].Value + roundTxAmount := roundTransaction.Outputs[sharedOutputIndex].Value - utx, err := poolTransaction.UnsignedTx() + utx, err := roundTransaction.UnsignedTx() if err != nil { - return ErrInvalidPoolTransaction + return ErrInvalidRoundTx } - poolTxID := utx.TxHash().String() + roundTxid := utx.TxHash().String() nbNodes := tree.NumberOfNodes() if nbNodes == 0 { @@ -101,7 +101,7 @@ func ValidateCongestionTree( return ErrInvalidRootLevel } - // check that root input is connected to the pool tx + // check that root input is connected to the round tx rootPsetB64 := tree[0][0].Tx rootPset, err := psetv2.NewPsetFromBase64(rootPsetB64) if err != nil { @@ -113,9 +113,9 @@ func ValidateCongestionTree( } rootInput := rootPset.Inputs[0] - if chainhash.Hash(rootInput.PreviousTxid).String() != poolTxID || + if chainhash.Hash(rootInput.PreviousTxid).String() != roundTxid || rootInput.PreviousTxIndex != sharedOutputIndex { - return ErrWrongPoolTxID + return ErrWrongRoundTxid } sumRootValue := uint64(0) @@ -123,7 +123,7 @@ func ValidateCongestionTree( sumRootValue += output.Value } - if sumRootValue != poolTxAmount { + if sumRootValue != roundTxAmount { return ErrInvalidAmount } @@ -135,7 +135,7 @@ func ValidateCongestionTree( for _, level := range tree { for _, node := range level { if err := validateNodeTransaction( - node, tree, UnspendableKey(), aspPublicKey, roundLifetime, + node, tree, UnspendableKey(), serverPubkey, roundLifetime, ); err != nil { return err } @@ -146,12 +146,12 @@ func ValidateCongestionTree( } func validateNodeTransaction( - node Node, tree CongestionTree, - expectedInternalKey, expectedPublicKeyASP *secp256k1.PublicKey, + node Node, tree VtxoTree, + expectedInternalKey, expectedServerPubkey *secp256k1.PublicKey, expectedSequence int64, ) error { if node.Tx == "" { - return ErrNodeTransactionEmpty + return ErrNodeTxEmpty } if node.Txid == "" { @@ -238,21 +238,21 @@ func validateNodeTransaction( switch c := closure.(type) { case *CSVSigClosure: - isASP := len(c.MultisigClosure.PubKeys) == 1 && bytes.Equal( + isServer := len(c.MultisigClosure.PubKeys) == 1 && bytes.Equal( schnorr.SerializePubKey(c.MultisigClosure.PubKeys[0]), - schnorr.SerializePubKey(expectedPublicKeyASP), + schnorr.SerializePubKey(expectedServerPubkey), ) isSweepDelay := int64(c.Seconds) == expectedSequence - if isASP && !isSweepDelay { + if isServer && !isSweepDelay { return ErrInvalidSweepSequence } - if isSweepDelay && !isASP { - return ErrInvalidASP + if isSweepDelay && !isServer { + return ErrInvalidServer } - if isASP && isSweepDelay { + if isServer && isSweepDelay { sweepLeafFound = true } case *UnrollClosure: diff --git a/common/tree/vtxo.go b/common/tree/vtxo.go index a6b8d74..9903ea3 100644 --- a/common/tree/vtxo.go +++ b/common/tree/vtxo.go @@ -26,14 +26,14 @@ func ParseVtxoScript(scripts []string) (VtxoScript, error) { return v, err } -func NewDefaultVtxoScript(owner, asp *secp256k1.PublicKey, exitDelay uint) *TapscriptsVtxoScript { +func NewDefaultVtxoScript(owner, server *secp256k1.PublicKey, exitDelay uint) *TapscriptsVtxoScript { return &TapscriptsVtxoScript{ []Closure{ &CSVSigClosure{ MultisigClosure: MultisigClosure{PubKeys: []*secp256k1.PublicKey{owner}}, Seconds: exitDelay, }, - &MultisigClosure{PubKeys: []*secp256k1.PublicKey{owner, asp}}, + &MultisigClosure{PubKeys: []*secp256k1.PublicKey{owner, server}}, }, } } @@ -73,19 +73,19 @@ func (v *TapscriptsVtxoScript) Decode(scripts []string) error { return nil } -func (v *TapscriptsVtxoScript) Validate(asp *secp256k1.PublicKey, minExitDelay uint) error { - aspXonly := schnorr.SerializePubKey(asp) +func (v *TapscriptsVtxoScript) Validate(server *secp256k1.PublicKey, minExitDelay uint) error { + serverXonly := schnorr.SerializePubKey(server) for _, forfeit := range v.ForfeitClosures() { - // must contain asp pubkey + // must contain server pubkey found := false for _, pubkey := range forfeit.PubKeys { - if bytes.Equal(schnorr.SerializePubKey(pubkey), aspXonly) { + if bytes.Equal(schnorr.SerializePubKey(pubkey), serverXonly) { found = true break } } if !found { - return fmt.Errorf("invalid forfeit closure, ASP pubkey not found") + return fmt.Errorf("invalid forfeit closure, server pubkey not found") } } diff --git a/common/vtxo.go b/common/vtxo.go index c961224..aea79e9 100644 --- a/common/vtxo.go +++ b/common/vtxo.go @@ -26,7 +26,7 @@ type TaprootTree interface { } /* -A vtxo script is defined as a taproot contract with at least 1 forfeit closure (User && ASP) and 1 exit closure (A after t). +A vtxo script is defined as a taproot contract with at least 1 forfeit closure (User && Server) and 1 exit closure (A after t). It may also contain others closures implementing specific use cases. VtxoScript abstracts the taproot complexity behind vtxo contracts. diff --git a/pkg/client-sdk/ark_sdk.go b/pkg/client-sdk/ark_sdk.go index a71e58d..3f81403 100644 --- a/pkg/client-sdk/ark_sdk.go +++ b/pkg/client-sdk/ark_sdk.go @@ -24,7 +24,6 @@ type ArkClient interface { CollaborativeRedeem( ctx context.Context, addr string, amount uint64, withExpiryCoinselect bool, ) (string, error) - SendAsync(ctx context.Context, withExpiryCoinselect bool, receivers []Receiver) (string, error) Settle(ctx context.Context) (string, error) ListVtxos(ctx context.Context) (spendable, spent []client.Vtxo, err error) Dump(ctx context.Context) (seed string, err error) diff --git a/pkg/client-sdk/client.go b/pkg/client-sdk/client.go index fa3125b..77039b2 100644 --- a/pkg/client-sdk/client.go +++ b/pkg/client-sdk/client.go @@ -57,7 +57,7 @@ type arkClient struct { wallet wallet.WalletService store types.Store explorer explorer.Explorer - client client.ASPClient + client client.TransportClient txStreamCtxCancel context.CancelFunc } @@ -119,7 +119,7 @@ func (a *arkClient) initWithWallet( } clientSvc, err := getClient( - supportedClients, args.ClientType, args.AspUrl, + supportedClients, args.ClientType, args.ServerUrl, ) if err != nil { return fmt.Errorf("failed to setup client: %s", err) @@ -127,7 +127,7 @@ func (a *arkClient) initWithWallet( info, err := clientSvc.GetInfo(ctx) if err != nil { - return fmt.Errorf("failed to connect to asp: %s", err) + return fmt.Errorf("failed to connect to server: %s", err) } explorerSvc, err := getExplorer(args.ExplorerURL, info.Network) @@ -137,18 +137,18 @@ func (a *arkClient) initWithWallet( network := utils.NetworkFromString(info.Network) - buf, err := hex.DecodeString(info.Pubkey) + buf, err := hex.DecodeString(info.PubKey) if err != nil { - return fmt.Errorf("failed to parse asp pubkey: %s", err) + return fmt.Errorf("failed to parse server pubkey: %s", err) } - aspPubkey, err := secp256k1.ParsePubKey(buf) + serverPubkey, err := secp256k1.ParsePubKey(buf) if err != nil { - return fmt.Errorf("failed to parse asp pubkey: %s", err) + return fmt.Errorf("failed to parse server pubkey: %s", err) } storeData := types.Config{ - AspUrl: args.AspUrl, - AspPubkey: aspPubkey, + ServerUrl: args.ServerUrl, + ServerPubKey: serverPubkey, WalletType: args.Wallet.GetType(), ClientType: args.ClientType, Network: network, @@ -186,7 +186,7 @@ func (a *arkClient) init( } clientSvc, err := getClient( - supportedClients, args.ClientType, args.AspUrl, + supportedClients, args.ClientType, args.ServerUrl, ) if err != nil { return fmt.Errorf("failed to setup client: %s", err) @@ -194,7 +194,7 @@ func (a *arkClient) init( info, err := clientSvc.GetInfo(ctx) if err != nil { - return fmt.Errorf("failed to connect to asp: %s", err) + return fmt.Errorf("failed to connect to server: %s", err) } explorerSvc, err := getExplorer(args.ExplorerURL, info.Network) @@ -204,18 +204,18 @@ func (a *arkClient) init( network := utils.NetworkFromString(info.Network) - buf, err := hex.DecodeString(info.Pubkey) + buf, err := hex.DecodeString(info.PubKey) if err != nil { - return fmt.Errorf("failed to parse asp pubkey: %s", err) + return fmt.Errorf("failed to parse server pubkey: %s", err) } - aspPubkey, err := secp256k1.ParsePubKey(buf) + serverPubkey, err := secp256k1.ParsePubKey(buf) if err != nil { - return fmt.Errorf("failed to parse asp pubkey: %s", err) + return fmt.Errorf("failed to parse server pubkey: %s", err) } cfgData := types.Config{ - AspUrl: args.AspUrl, - AspPubkey: aspPubkey, + ServerUrl: args.ServerUrl, + ServerPubKey: serverPubkey, WalletType: args.WalletType, ClientType: args.ClientType, Network: network, @@ -252,17 +252,17 @@ func (a *arkClient) init( } func (a *arkClient) ping( - ctx context.Context, paymentID string, + ctx context.Context, requestID string, ) func() { ticker := time.NewTicker(5 * time.Second) go func(t *time.Ticker) { - if err := a.client.Ping(ctx, paymentID); err != nil { - logrus.Warnf("failed to ping asp: %s", err) + if err := a.client.Ping(ctx, requestID); err != nil { + logrus.Warnf("failed to ping server: %s", err) } for range t.C { - if err := a.client.Ping(ctx, paymentID); err != nil { - logrus.Warnf("failed to ping asp: %s", err) + if err := a.client.Ping(ctx, requestID); err != nil { + logrus.Warnf("failed to ping server: %s", err) } } }(ticker) @@ -292,10 +292,10 @@ func (a *arkClient) ListVtxos( } func getClient( - supportedClients utils.SupportedType[utils.ClientFactory], clientType, aspUrl string, -) (client.ASPClient, error) { + supportedClients utils.SupportedType[utils.ClientFactory], clientType, serverUrl string, +) (client.TransportClient, error) { factory := supportedClients[clientType] - return factory(aspUrl) + return factory(serverUrl) } func getExplorer(explorerURL, network string) (explorer.Explorer, error) { diff --git a/pkg/client-sdk/client/client.go b/pkg/client-sdk/client/client.go index 21612fc..93573cd 100644 --- a/pkg/client-sdk/client/client.go +++ b/pkg/client-sdk/client/client.go @@ -22,7 +22,7 @@ type RoundEvent interface { isRoundEvent() } -type ASPClient interface { +type TransportClient interface { GetInfo(ctx context.Context) (*Info, error) RegisterInputsForNextRound( ctx context.Context, inputs []Input, ephemeralKey string, @@ -31,7 +31,7 @@ type ASPClient interface { ctx context.Context, notes []string, ephemeralKey string, ) (string, error) RegisterOutputsForNextRound( - ctx context.Context, paymentID string, outputs []Output, + ctx context.Context, requestID string, outputs []Output, ) error SubmitTreeNonces( ctx context.Context, roundID, cosignerPubkey string, nonces bitcointree.TreeNonces, @@ -43,9 +43,9 @@ type ASPClient interface { ctx context.Context, signedForfeitTxs []string, signedRoundTx string, ) error GetEventStream( - ctx context.Context, paymentID string, + ctx context.Context, requestID string, ) (<-chan RoundEventChannel, func(), error) - Ping(ctx context.Context, paymentID string) error + Ping(ctx context.Context, requestID string) error SubmitRedeemTx( ctx context.Context, signedRedeemTx string, ) (string, error) @@ -59,7 +59,7 @@ type ASPClient interface { } type Info struct { - Pubkey string + PubKey string RoundLifetime int64 UnilateralExitDelay int64 RoundInterval int64 @@ -90,7 +90,7 @@ type Input struct { type Vtxo struct { Outpoint - Pubkey string + PubKey string Amount uint64 RoundTxid string ExpiresAt time.Time @@ -100,8 +100,8 @@ type Vtxo struct { SpentBy string } -func (v Vtxo) Address(asp *secp256k1.PublicKey, net common.Network) (string, error) { - pubkeyBytes, err := hex.DecodeString(v.Pubkey) +func (v Vtxo) Address(server *secp256k1.PublicKey, net common.Network) (string, error) { + pubkeyBytes, err := hex.DecodeString(v.PubKey) if err != nil { return "", err } @@ -113,7 +113,7 @@ func (v Vtxo) Address(asp *secp256k1.PublicKey, net common.Network) (string, err a := &common.Address{ HRP: net.Addr, - Asp: asp, + Server: server, VtxoTapKey: pubkey, } @@ -160,7 +160,7 @@ type Round struct { StartedAt *time.Time EndedAt *time.Time Tx string - Tree tree.CongestionTree + Tree tree.VtxoTree ForfeitTxs []string Connectors []string Stage RoundStage @@ -169,7 +169,7 @@ type Round struct { type RoundFinalizationEvent struct { ID string Tx string - Tree tree.CongestionTree + Tree tree.VtxoTree Connectors []string MinRelayFeeRate chainfee.SatPerKVByte } @@ -191,10 +191,10 @@ type RoundFailedEvent struct { func (e RoundFailedEvent) isRoundEvent() {} type RoundSigningStartedEvent struct { - ID string - UnsignedTree tree.CongestionTree - CosignersPublicKeys []*secp256k1.PublicKey - UnsignedRoundTx string + ID string + UnsignedTree tree.VtxoTree + CosignersPubKeys []*secp256k1.PublicKey + UnsignedRoundTx string } func (e RoundSigningStartedEvent) isRoundEvent() {} diff --git a/pkg/client-sdk/client/grpc/client.go b/pkg/client-sdk/client/grpc/client.go index f8b4481..8d1bf55 100644 --- a/pkg/client-sdk/client/grpc/client.go +++ b/pkg/client-sdk/client/grpc/client.go @@ -23,31 +23,31 @@ import ( type grpcClient struct { conn *grpc.ClientConn svc arkv1.ArkServiceClient - treeCache *utils.Cache[tree.CongestionTree] + treeCache *utils.Cache[tree.VtxoTree] } -func NewClient(aspUrl string) (client.ASPClient, error) { - if len(aspUrl) <= 0 { - return nil, fmt.Errorf("missing asp url") +func NewClient(serverUrl string) (client.TransportClient, error) { + if len(serverUrl) <= 0 { + return nil, fmt.Errorf("missing server url") } creds := insecure.NewCredentials() port := 80 - if strings.HasPrefix(aspUrl, "https://") { - aspUrl = strings.TrimPrefix(aspUrl, "https://") + if strings.HasPrefix(serverUrl, "https://") { + serverUrl = strings.TrimPrefix(serverUrl, "https://") creds = credentials.NewTLS(nil) port = 443 } - if !strings.Contains(aspUrl, ":") { - aspUrl = fmt.Sprintf("%s:%d", aspUrl, port) + if !strings.Contains(serverUrl, ":") { + serverUrl = fmt.Sprintf("%s:%d", serverUrl, port) } - conn, err := grpc.NewClient(aspUrl, grpc.WithTransportCredentials(creds)) + conn, err := grpc.NewClient(serverUrl, grpc.WithTransportCredentials(creds)) if err != nil { return nil, err } svc := arkv1.NewArkServiceClient(conn) - treeCache := utils.NewCache[tree.CongestionTree]() + treeCache := utils.NewCache[tree.VtxoTree]() return &grpcClient{conn, svc, treeCache}, nil } @@ -59,7 +59,7 @@ func (a *grpcClient) GetInfo(ctx context.Context) (*client.Info, error) { return nil, err } return &client.Info{ - Pubkey: resp.GetPubkey(), + PubKey: resp.GetPubkey(), RoundLifetime: resp.GetRoundLifetime(), UnilateralExitDelay: resp.GetUnilateralExitDelay(), RoundInterval: resp.GetRoundInterval(), @@ -84,20 +84,20 @@ func (a *grpcClient) GetBoardingAddress( } func (a *grpcClient) RegisterInputsForNextRound( - ctx context.Context, inputs []client.Input, ephemeralPublicKey string, + ctx context.Context, inputs []client.Input, ephemeralPubkey string, ) (string, error) { req := &arkv1.RegisterInputsForNextRoundRequest{ Inputs: ins(inputs).toProto(), } - if len(ephemeralPublicKey) > 0 { - req.EphemeralPubkey = &ephemeralPublicKey + if len(ephemeralPubkey) > 0 { + req.EphemeralPubkey = &ephemeralPubkey } resp, err := a.svc.RegisterInputsForNextRound(ctx, req) if err != nil { return "", err } - return resp.GetId(), nil + return resp.GetRequestId(), nil } func (a *grpcClient) RegisterNotesForNextRound( @@ -113,15 +113,15 @@ func (a *grpcClient) RegisterNotesForNextRound( if err != nil { return "", err } - return resp.GetId(), nil + return resp.GetRequestId(), nil } func (a *grpcClient) RegisterOutputsForNextRound( - ctx context.Context, paymentID string, outputs []client.Output, + ctx context.Context, requestID string, outputs []client.Output, ) error { req := &arkv1.RegisterOutputsForNextRoundRequest{ - Id: paymentID, - Outputs: outs(outputs).toProto(), + RequestId: requestID, + Outputs: outs(outputs).toProto(), } _, err := a.svc.RegisterOutputsForNextRound(ctx, req) return err @@ -191,7 +191,7 @@ func (a *grpcClient) SubmitSignedForfeitTxs( } func (a *grpcClient) GetEventStream( - ctx context.Context, paymentID string, + ctx context.Context, requestID string, ) (<-chan client.RoundEventChannel, func(), error) { req := &arkv1.GetEventStreamRequest{} stream, err := a.svc.GetEventStream(ctx, req) @@ -236,10 +236,10 @@ func (a *grpcClient) GetEventStream( } func (a *grpcClient) Ping( - ctx context.Context, paymentID string, + ctx context.Context, requestID string, ) error { req := &arkv1.PingRequest{ - PaymentId: paymentID, + RequestId: requestID, } _, err := a.svc.Ping(ctx, req) return err diff --git a/pkg/client-sdk/client/grpc/types.go b/pkg/client-sdk/client/grpc/types.go index bf61c1c..49e9552 100644 --- a/pkg/client-sdk/client/grpc/types.go +++ b/pkg/client-sdk/client/grpc/types.go @@ -86,10 +86,10 @@ func (e event) toRoundEvent() (client.RoundEvent, error) { } return client.RoundSigningStartedEvent{ - ID: ee.GetId(), - UnsignedTree: treeFromProto{ee.GetUnsignedVtxoTree()}.parse(), - CosignersPublicKeys: pubkeys, - UnsignedRoundTx: ee.GetUnsignedRoundTx(), + ID: ee.GetId(), + UnsignedTree: treeFromProto{ee.GetUnsignedVtxoTree()}.parse(), + CosignersPubKeys: pubkeys, + UnsignedRoundTx: ee.GetUnsignedRoundTx(), }, nil } @@ -123,7 +123,7 @@ func (v vtxo) toVtxo() client.Vtxo { IsPending: v.GetIsPending(), RedeemTx: v.GetRedeemTx(), SpentBy: v.GetSpentBy(), - Pubkey: v.GetPubkey(), + PubKey: v.GetPubkey(), CreatedAt: time.Unix(v.GetCreatedAt(), 0), } } @@ -166,8 +166,8 @@ type treeFromProto struct { *arkv1.Tree } -func (t treeFromProto) parse() tree.CongestionTree { - levels := make(tree.CongestionTree, 0, len(t.GetLevels())) +func (t treeFromProto) parse() tree.VtxoTree { + levels := make(tree.VtxoTree, 0, len(t.GetLevels())) for _, level := range t.GetLevels() { nodes := make([]tree.Node, 0, len(level.Nodes)) diff --git a/pkg/client-sdk/client/rest/client.go b/pkg/client-sdk/client/rest/client.go index f9212be..c046deb 100644 --- a/pkg/client-sdk/client/rest/client.go +++ b/pkg/client-sdk/client/rest/client.go @@ -32,12 +32,12 @@ type restClient struct { serverURL string svc ark_service.ClientService requestTimeout time.Duration - treeCache *utils.Cache[tree.CongestionTree] + treeCache *utils.Cache[tree.VtxoTree] } -func NewClient(serverURL string) (client.ASPClient, error) { +func NewClient(serverURL string) (client.TransportClient, error) { if len(serverURL) <= 0 { - return nil, fmt.Errorf("missing asp url") + return nil, fmt.Errorf("missing server url") } svc, err := newRestClient(serverURL) if err != nil { @@ -45,7 +45,7 @@ func NewClient(serverURL string) (client.ASPClient, error) { } // TODO: use twice the round interval. reqTimeout := 15 * time.Second - treeCache := utils.NewCache[tree.CongestionTree]() + treeCache := utils.NewCache[tree.VtxoTree]() return &restClient{serverURL, svc, reqTimeout, treeCache}, nil } @@ -79,7 +79,7 @@ func (a *restClient) GetInfo( } return &client.Info{ - Pubkey: resp.Payload.Pubkey, + PubKey: resp.Payload.Pubkey, RoundLifetime: int64(roundLifetime), UnilateralExitDelay: int64(unilateralExitDelay), RoundInterval: int64(roundInterval), @@ -108,7 +108,7 @@ func (a *restClient) GetBoardingAddress( } func (a *restClient) RegisterInputsForNextRound( - ctx context.Context, inputs []client.Input, ephemeralPublicKey string, + ctx context.Context, inputs []client.Input, ephemeralPubkey string, ) (string, error) { ins := make([]*models.V1Input, 0, len(inputs)) for _, i := range inputs { @@ -125,8 +125,8 @@ func (a *restClient) RegisterInputsForNextRound( body := &models.V1RegisterInputsForNextRoundRequest{ Inputs: ins, } - if len(ephemeralPublicKey) > 0 { - body.EphemeralPubkey = ephemeralPublicKey + if len(ephemeralPubkey) > 0 { + body.EphemeralPubkey = ephemeralPubkey } resp, err := a.svc.ArkServiceRegisterInputsForNextRound( @@ -136,7 +136,7 @@ func (a *restClient) RegisterInputsForNextRound( return "", err } - return resp.Payload.ID, nil + return resp.Payload.RequestID, nil } func (a *restClient) RegisterNotesForNextRound( @@ -154,11 +154,11 @@ func (a *restClient) RegisterNotesForNextRound( if err != nil { return "", err } - return resp.Payload.ID, nil + return resp.Payload.RequestID, nil } func (a *restClient) RegisterOutputsForNextRound( - ctx context.Context, paymentID string, outputs []client.Output, + ctx context.Context, requestID string, outputs []client.Output, ) error { outs := make([]*models.V1Output, 0, len(outputs)) for _, o := range outputs { @@ -168,8 +168,8 @@ func (a *restClient) RegisterOutputsForNextRound( }) } body := models.V1RegisterOutputsForNextRoundRequest{ - ID: paymentID, - Outputs: outs, + RequestID: requestID, + Outputs: outs, } _, err := a.svc.ArkServiceRegisterOutputsForNextRound( @@ -246,7 +246,7 @@ func (a *restClient) SubmitSignedForfeitTxs( } func (c *restClient) GetEventStream( - ctx context.Context, paymentID string, + ctx context.Context, requestID string, ) (<-chan client.RoundEventChannel, func(), error) { eventsCh := make(chan client.RoundEventChannel) @@ -354,10 +354,10 @@ func (c *restClient) GetEventStream( } event = client.RoundSigningStartedEvent{ - ID: e.ID, - UnsignedTree: treeFromProto{e.UnsignedVtxoTree}.parse(), - CosignersPublicKeys: pubkeys, - UnsignedRoundTx: e.UnsignedRoundTx, + ID: e.ID, + UnsignedTree: treeFromProto{e.UnsignedVtxoTree}.parse(), + CosignersPubKeys: pubkeys, + UnsignedRoundTx: e.UnsignedRoundTx, } case resp.Result.RoundSigningNoncesGenerated != nil: e := resp.Result.RoundSigningNoncesGenerated @@ -384,10 +384,10 @@ func (c *restClient) GetEventStream( } func (a *restClient) Ping( - ctx context.Context, paymentID string, + ctx context.Context, requestID string, ) error { r := ark_service.NewArkServicePingParams() - r.SetPaymentID(paymentID) + r.SetRequestID(requestID) _, err := a.svc.ArkServicePing(r) return err } @@ -573,8 +573,8 @@ type treeFromProto struct { *models.V1Tree } -func (t treeFromProto) parse() tree.CongestionTree { - congestionTree := make(tree.CongestionTree, 0, len(t.Levels)) +func (t treeFromProto) parse() tree.VtxoTree { + vtxoTree := make(tree.VtxoTree, 0, len(t.Levels)) for _, l := range t.Levels { level := make([]tree.Node, 0, len(l.Nodes)) for _, n := range l.Nodes { @@ -584,13 +584,13 @@ func (t treeFromProto) parse() tree.CongestionTree { ParentTxid: n.ParentTxid, }) } - congestionTree = append(congestionTree, level) + vtxoTree = append(vtxoTree, level) } - for j, treeLvl := range congestionTree { + for j, treeLvl := range vtxoTree { for i, node := range treeLvl { - if len(congestionTree.Children(node.Txid)) == 0 { - congestionTree[j][i] = tree.Node{ + if len(vtxoTree.Children(node.Txid)) == 0 { + vtxoTree[j][i] = tree.Node{ Txid: node.Txid, Tx: node.Tx, ParentTxid: node.ParentTxid, @@ -600,7 +600,7 @@ func (t treeFromProto) parse() tree.CongestionTree { } } - return congestionTree + return vtxoTree } func (c *restClient) GetTransactionsStream(ctx context.Context) (<-chan client.TransactionEvent, func(), error) { @@ -725,7 +725,7 @@ func vtxosFromRest(restVtxos []*models.V1Vtxo) []client.Vtxo { Txid: v.Outpoint.Txid, VOut: uint32(v.Outpoint.Vout), }, - Pubkey: v.Pubkey, + PubKey: v.Pubkey, Amount: uint64(amount), RoundTxid: v.RoundTxid, ExpiresAt: expiresAt, 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 6f0dce3..05410d6 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 @@ -396,7 +396,7 @@ func (a *Client) ArkServicePing(params *ArkServicePingParams, opts ...ClientOpti op := &runtime.ClientOperation{ ID: "ArkService_Ping", Method: "GET", - PathPattern: "/v1/round/ping/{paymentId}", + PathPattern: "/v1/round/ping/{requestId}", ProducesMediaTypes: []string{"application/json"}, ConsumesMediaTypes: []string{"application/json"}, Schemes: []string{"http"}, diff --git a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_ping_parameters.go b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_ping_parameters.go index 8c2d7d4..9f34815 100644 --- a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_ping_parameters.go +++ b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_ping_parameters.go @@ -61,8 +61,11 @@ ArkServicePingParams contains all the parameters to send to the API endpoint */ type ArkServicePingParams struct { - // PaymentID. - PaymentID string + /* RequestID. + + The id used to register inputs and ouptuts. + */ + RequestID string timeout time.Duration Context context.Context @@ -117,15 +120,15 @@ func (o *ArkServicePingParams) SetHTTPClient(client *http.Client) { o.HTTPClient = client } -// WithPaymentID adds the paymentID to the ark service ping params -func (o *ArkServicePingParams) WithPaymentID(paymentID string) *ArkServicePingParams { - o.SetPaymentID(paymentID) +// WithRequestID adds the requestID to the ark service ping params +func (o *ArkServicePingParams) WithRequestID(requestID string) *ArkServicePingParams { + o.SetRequestID(requestID) return o } -// SetPaymentID adds the paymentId to the ark service ping params -func (o *ArkServicePingParams) SetPaymentID(paymentID string) { - o.PaymentID = paymentID +// SetRequestID adds the requestId to the ark service ping params +func (o *ArkServicePingParams) SetRequestID(requestID string) { + o.RequestID = requestID } // WriteToRequest writes these params to a swagger request @@ -136,8 +139,8 @@ func (o *ArkServicePingParams) WriteToRequest(r runtime.ClientRequest, reg strfm } var res []error - // path param paymentId - if err := r.SetPathParam("paymentId", o.PaymentID); err != nil { + // path param requestId + if err := r.SetPathParam("requestId", o.RequestID); err != nil { return err } diff --git a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_ping_responses.go b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_ping_responses.go index 3f56b8b..a3029a8 100644 --- a/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_ping_responses.go +++ b/pkg/client-sdk/client/rest/service/arkservice/ark_service/ark_service_ping_responses.go @@ -88,12 +88,12 @@ func (o *ArkServicePingOK) Code() int { func (o *ArkServicePingOK) Error() string { payload, _ := json.Marshal(o.Payload) - return fmt.Sprintf("[GET /v1/round/ping/{paymentId}][%d] arkServicePingOK %s", 200, payload) + return fmt.Sprintf("[GET /v1/round/ping/{requestId}][%d] arkServicePingOK %s", 200, payload) } func (o *ArkServicePingOK) String() string { payload, _ := json.Marshal(o.Payload) - return fmt.Sprintf("[GET /v1/round/ping/{paymentId}][%d] arkServicePingOK %s", 200, payload) + return fmt.Sprintf("[GET /v1/round/ping/{requestId}][%d] arkServicePingOK %s", 200, payload) } func (o *ArkServicePingOK) GetPayload() models.V1PingResponse { @@ -160,12 +160,12 @@ func (o *ArkServicePingDefault) Code() int { func (o *ArkServicePingDefault) Error() string { payload, _ := json.Marshal(o.Payload) - return fmt.Sprintf("[GET /v1/round/ping/{paymentId}][%d] ArkService_Ping default %s", o._statusCode, payload) + return fmt.Sprintf("[GET /v1/round/ping/{requestId}][%d] ArkService_Ping default %s", o._statusCode, payload) } func (o *ArkServicePingDefault) String() string { payload, _ := json.Marshal(o.Payload) - return fmt.Sprintf("[GET /v1/round/ping/{paymentId}][%d] ArkService_Ping default %s", o._statusCode, payload) + return fmt.Sprintf("[GET /v1/round/ping/{requestId}][%d] ArkService_Ping default %s", o._statusCode, payload) } func (o *ArkServicePingDefault) GetPayload() *models.RPCStatus { diff --git a/pkg/client-sdk/client/rest/service/models/v1_ownership_proof.go b/pkg/client-sdk/client/rest/service/models/v1_ownership_proof.go index c5cd3da..c3a067b 100644 --- a/pkg/client-sdk/client/rest/service/models/v1_ownership_proof.go +++ b/pkg/client-sdk/client/rest/service/models/v1_ownership_proof.go @@ -12,7 +12,7 @@ import ( "github.com/go-openapi/swag" ) -// V1OwnershipProof This message is used to prove to the ASP that the user controls the vtxo without revealing the whole VTXO taproot tree. +// V1OwnershipProof This message is used to prove to the server that the user controls the vtxo without revealing the whole VTXO taproot tree. // // swagger:model v1OwnershipProof type V1OwnershipProof struct { diff --git a/pkg/client-sdk/client/rest/service/models/v1_register_inputs_for_next_round_response.go b/pkg/client-sdk/client/rest/service/models/v1_register_inputs_for_next_round_response.go index 38ad364..8e9dce3 100644 --- a/pkg/client-sdk/client/rest/service/models/v1_register_inputs_for_next_round_response.go +++ b/pkg/client-sdk/client/rest/service/models/v1_register_inputs_for_next_round_response.go @@ -17,8 +17,8 @@ import ( // swagger:model v1RegisterInputsForNextRoundResponse type V1RegisterInputsForNextRoundResponse struct { - // Mocks wabisabi's blinded credentials. - ID string `json:"id,omitempty"` + // request Id + RequestID string `json:"requestId,omitempty"` } // Validate validates this v1 register inputs for next round response diff --git a/pkg/client-sdk/client/rest/service/models/v1_register_outputs_for_next_round_request.go b/pkg/client-sdk/client/rest/service/models/v1_register_outputs_for_next_round_request.go index 08dc549..812d976 100644 --- a/pkg/client-sdk/client/rest/service/models/v1_register_outputs_for_next_round_request.go +++ b/pkg/client-sdk/client/rest/service/models/v1_register_outputs_for_next_round_request.go @@ -19,11 +19,11 @@ import ( // swagger:model v1RegisterOutputsForNextRoundRequest type V1RegisterOutputsForNextRoundRequest struct { - // Mocks wabisabi's blinded credentials. - ID string `json:"id,omitempty"` - - // List of receivers for a registered payment. + // List of receivers for to convert to leaves in the next VTXO tree. Outputs []*V1Output `json:"outputs"` + + // request Id + RequestID string `json:"requestId,omitempty"` } // Validate validates this v1 register outputs for next round request diff --git a/pkg/client-sdk/client/rest/service/models/v1_submit_signed_forfeit_txs_request.go b/pkg/client-sdk/client/rest/service/models/v1_submit_signed_forfeit_txs_request.go index 5ff54de..4669f93 100644 --- a/pkg/client-sdk/client/rest/service/models/v1_submit_signed_forfeit_txs_request.go +++ b/pkg/client-sdk/client/rest/service/models/v1_submit_signed_forfeit_txs_request.go @@ -20,7 +20,7 @@ type V1SubmitSignedForfeitTxsRequest struct { // Forfeit txs signed by the user. SignedForfeitTxs []string `json:"signedForfeitTxs"` - // If payment has boarding input, the user must sign the associated inputs. + // The user has to sign also the round tx if he registerd a boarding UTXO. SignedRoundTx string `json:"signedRoundTx,omitempty"` } diff --git a/pkg/client-sdk/covenant_client.go b/pkg/client-sdk/covenant_client.go index 395fce8..aacc872 100644 --- a/pkg/client-sdk/covenant_client.go +++ b/pkg/client-sdk/covenant_client.go @@ -87,7 +87,7 @@ func LoadCovenantClient(sdkStore types.Store) (ArkClient, error) { } clientSvc, err := getClient( - supportedClients, cfgData.ClientType, cfgData.AspUrl, + supportedClients, cfgData.ClientType, cfgData.ServerUrl, ) if err != nil { return nil, fmt.Errorf("failed to setup transport client: %s", err) @@ -147,7 +147,7 @@ func LoadCovenantClientWithWallet( } clientSvc, err := getClient( - supportedClients, cfgData.ClientType, cfgData.AspUrl, + supportedClients, cfgData.ClientType, cfgData.ServerUrl, ) if err != nil { return nil, fmt.Errorf("failed to setup transport client: %s", err) @@ -243,19 +243,19 @@ func (a *covenantArkClient) listenForTxStream(ctx context.Context) { func (a *covenantArkClient) processTransactionEvent( event client.TransactionEvent, ) { - // TODO considering current covenant state where all payments happening in round - //and that this is going to change we leave this unimplemented until asnc payments are implemented - //also with current state it is not possible to cover some edge cases like when in a round there - //are multiple boarding inputs + spent vtxo with change in spendable + received in the same round + // TODO: considering current covenant state where all transactions happening in round + // and that this is going to change we leave this unimplemented for now. + // Also, with current state it is not possible to cover some edge cases like when in a round there + // are multiple boarding inputs + spent vtxo with change in spendable + received in the same round } func (a *covenantArkClient) listenForBoardingUtxos( ctx context.Context, ) { - // TODO considering current covenant state where all payments happening in round - //and that this is going to change we leave this unimplemented until asnc payments are implemented - //also with current state it is not possible to cover some edge cases like when in a round there - //are multiple boarding inputs + spent vtxo with change in spendable + received in the same round + // TODO considering current covenant state where all transactions happening in round + // and that this is going to change we leave this unimplemented for now. + // Also, with current state it is not possible to cover some edge cases like when in a round there + // are multiple boarding inputs + spent vtxo with change in spendable + received in the same round } func (a *covenantArkClient) Balance( @@ -525,7 +525,7 @@ func (a *covenantArkClient) CollaborativeRedeem( for _, offchainAddr := range offchainAddrs { for _, v := range spendableVtxos { - vtxoAddr, err := v.Address(a.AspPubkey, a.Network) + vtxoAddr, err := v.Address(a.ServerPubKey, a.Network) if err != nil { return "", err } @@ -584,16 +584,16 @@ func (a *covenantArkClient) CollaborativeRedeem( }) } - paymentID, err := a.client.RegisterInputsForNextRound(ctx, inputs, "") + requestID, err := a.client.RegisterInputsForNextRound(ctx, inputs, "") if err != nil { return "", err } - if err := a.client.RegisterOutputsForNextRound(ctx, paymentID, receivers); err != nil { + if err := a.client.RegisterOutputsForNextRound(ctx, requestID, receivers); err != nil { return "", err } - roundTxID, err := a.handleRoundStream(ctx, paymentID, selectedCoins, selectedBoardingUtxos, receivers) + roundTxID, err := a.handleRoundStream(ctx, requestID, selectedCoins, selectedBoardingUtxos, receivers) if err != nil { return "", err } @@ -601,13 +601,6 @@ func (a *covenantArkClient) CollaborativeRedeem( return roundTxID, nil } -func (a *covenantArkClient) SendAsync( - ctx context.Context, - withExpiryCoinselect bool, receivers []Receiver, -) (string, error) { - return "", fmt.Errorf("not implemented") -} - func (a *covenantArkClient) Settle( ctx context.Context, ) (string, error) { @@ -889,7 +882,7 @@ func (a *covenantArkClient) sendOffchain( return "", fmt.Errorf("wallet is locked") } - expectedAspPubKey := schnorr.SerializePubKey(a.AspPubkey) + expectedServerPubkey := schnorr.SerializePubKey(a.ServerPubKey) outputs := make([]client.Output, 0) sumOfReceivers := uint64(0) @@ -900,10 +893,10 @@ func (a *covenantArkClient) sendOffchain( return "", fmt.Errorf("invalid receiver address: %s", err) } - rcvAspPubKey := schnorr.SerializePubKey(rcvAddr.Asp) + rcvServerPubKkey := schnorr.SerializePubKey(rcvAddr.Server) - if !bytes.Equal(expectedAspPubKey, rcvAspPubKey) { - return "", fmt.Errorf("invalid receiver address '%s': expected ASP %s, got %s", receiver.To(), hex.EncodeToString(expectedAspPubKey), hex.EncodeToString(rcvAspPubKey)) + if !bytes.Equal(expectedServerPubkey, rcvServerPubKkey) { + return "", fmt.Errorf("invalid receiver address '%s': expected server %s, got %s", receiver.To(), hex.EncodeToString(expectedServerPubkey), hex.EncodeToString(rcvServerPubKkey)) } if receiver.Amount() < a.Dust { @@ -934,7 +927,7 @@ func (a *covenantArkClient) sendOffchain( for _, offchainAddr := range offchainAddrs { for _, v := range spendableVtxos { - vtxoAddr, err := v.Address(a.AspPubkey, a.Network) + vtxoAddr, err := v.Address(a.ServerPubKey, a.Network) if err != nil { return "", err } @@ -1018,21 +1011,21 @@ func (a *covenantArkClient) sendOffchain( }) } - paymentID, err := a.client.RegisterInputsForNextRound(ctx, inputs, "") + requestID, err := a.client.RegisterInputsForNextRound(ctx, inputs, "") if err != nil { return "", err } if err := a.client.RegisterOutputsForNextRound( - ctx, paymentID, outputs, + ctx, requestID, outputs, ); err != nil { return "", err } - log.Infof("payment registered with id: %s", paymentID) + log.Infof("payout registered with id: %s", requestID) roundTxID, err := a.handleRoundStream( - ctx, paymentID, selectedCoins, boardingUtxos, outputs, + ctx, requestID, selectedCoins, boardingUtxos, outputs, ) if err != nil { return "", err @@ -1116,19 +1109,19 @@ func (a *covenantArkClient) addInputs( func (a *covenantArkClient) handleRoundStream( ctx context.Context, - paymentID string, + requestID string, vtxosToSign []client.TapscriptsVtxo, boardingUtxos []types.Utxo, receivers []client.Output, ) (string, error) { - eventsCh, close, err := a.client.GetEventStream(ctx, paymentID) + eventsCh, close, err := a.client.GetEventStream(ctx, requestID) if err != nil { return "", err } var pingStop func() for pingStop == nil { - pingStop = a.ping(ctx, paymentID) + pingStop = a.ping(ctx, requestID) } defer func() { @@ -1166,7 +1159,7 @@ func (a *covenantArkClient) handleRoundStream( continue } - log.Info("finalizing payment... ") + log.Info("submitting forfeit transactions... ") if err := a.client.SubmitSignedForfeitTxs(ctx, signedForfeitTxs, signedRoundTx); err != nil { return "", err } @@ -1185,7 +1178,7 @@ func (a *covenantArkClient) handleRoundFinalization( boardingUtxos []types.Utxo, receivers []client.Output, ) (signedForfeits []string, signedRoundTx string, err error) { - if err = a.validateCongestionTree(event, receivers); err != nil { + if err = a.validateVtxoTree(event, receivers); err != nil { return } @@ -1270,11 +1263,11 @@ func (a *covenantArkClient) handleRoundFinalization( return signedForfeits, signedRoundTx, nil } -func (a *covenantArkClient) validateCongestionTree( +func (a *covenantArkClient) validateVtxoTree( event client.RoundFinalizationEvent, receivers []client.Output, ) error { - poolTx := event.Tx - ptx, err := psetv2.NewPsetFromBase64(poolTx) + roundTx := event.Tx + ptx, err := psetv2.NewPsetFromBase64(roundTx) if err != nil { return err } @@ -1282,14 +1275,14 @@ func (a *covenantArkClient) validateCongestionTree( connectors := event.Connectors if !utils.IsOnchainOnly(receivers) { - if err := tree.ValidateCongestionTree( - event.Tree, poolTx, a.Config.AspPubkey, a.RoundLifetime, + if err := tree.ValidateVtxoTree( + event.Tree, roundTx, a.Config.ServerPubKey, a.RoundLifetime, ); err != nil { return err } } - if err := common.ValidateConnectors(poolTx, connectors); err != nil { + if err := common.ValidateConnectors(roundTx, connectors); err != nil { return err } @@ -1299,15 +1292,13 @@ func (a *covenantArkClient) validateCongestionTree( return err } - log.Infoln("congestion tree validated") - return nil } func (a *covenantArkClient) validateReceivers( ptx *psetv2.Pset, receivers []client.Output, - congestionTree tree.CongestionTree, + vtxoTree tree.VtxoTree, ) error { for _, receiver := range receivers { isOnChain, onchainScript, err := utils.ParseLiquidAddress( @@ -1323,7 +1314,7 @@ func (a *covenantArkClient) validateReceivers( } } else { if err := a.validateOffChainReceiver( - congestionTree, receiver, + vtxoTree, receiver, ); err != nil { return err } @@ -1357,7 +1348,7 @@ func (a *covenantArkClient) validateOnChainReceiver( } func (a *covenantArkClient) validateOffChainReceiver( - congestionTree tree.CongestionTree, + vtxoTree tree.VtxoTree, receiver client.Output, ) error { found := false @@ -1369,7 +1360,7 @@ func (a *covenantArkClient) validateOffChainReceiver( vtxoTapKey := schnorr.SerializePubKey(addr.VtxoTapKey) - leaves := congestionTree.Leaves() + leaves := vtxoTree.Leaves() for _, leaf := range leaves { tx, err := psetv2.NewPsetFromBase64(leaf.Tx) if err != nil { @@ -1614,22 +1605,22 @@ func (a *covenantArkClient) coinSelectOnchain( func (a *covenantArkClient) getRedeemBranches( ctx context.Context, vtxos []client.Vtxo, ) (map[string]*redemption.CovenantRedeemBranch, error) { - congestionTrees := make(map[string]tree.CongestionTree, 0) + vtxoTrees := make(map[string]tree.VtxoTree, 0) redeemBranches := make(map[string]*redemption.CovenantRedeemBranch, 0) for i := range vtxos { vtxo := vtxos[i] - if _, ok := congestionTrees[vtxo.RoundTxid]; !ok { + if _, ok := vtxoTrees[vtxo.RoundTxid]; !ok { round, err := a.client.GetRound(ctx, vtxo.RoundTxid) if err != nil { return nil, err } - congestionTrees[vtxo.RoundTxid] = round.Tree + vtxoTrees[vtxo.RoundTxid] = round.Tree } redeemBranch, err := redemption.NewCovenantRedeemBranch( - a.explorer, congestionTrees[vtxo.RoundTxid], vtxo, + a.explorer, vtxoTrees[vtxo.RoundTxid], vtxo, ) if err != nil { return nil, err diff --git a/pkg/client-sdk/covenantless_client.go b/pkg/client-sdk/covenantless_client.go index 79c0fac..0a544e4 100644 --- a/pkg/client-sdk/covenantless_client.go +++ b/pkg/client-sdk/covenantless_client.go @@ -91,7 +91,7 @@ func LoadCovenantlessClient(sdkStore types.Store) (ArkClient, error) { } clientSvc, err := getClient( - supportedClients, cfgData.ClientType, cfgData.AspUrl, + supportedClients, cfgData.ClientType, cfgData.ServerUrl, ) if err != nil { return nil, fmt.Errorf("failed to setup transport client: %s", err) @@ -151,7 +151,7 @@ func LoadCovenantlessClientWithWallet( } clientSvc, err := getClient( - supportedClients, cfgData.ClientType, cfgData.AspUrl, + supportedClients, cfgData.ClientType, cfgData.ServerUrl, ) if err != nil { return nil, fmt.Errorf("failed to setup transport client: %s", err) @@ -395,7 +395,7 @@ func (a *covenantlessArkClient) processTransactionEvent( vtxosToInsert := make([]types.Vtxo, 0) txsToInsert := make([]types.Transaction, 0) for _, v := range event.Round.SpendableVtxos { - if v.Pubkey == pubkey { + if v.PubKey == pubkey { vtxosToInsert = append(vtxosToInsert, types.Vtxo{ VtxoKey: types.VtxoKey{ Txid: v.Txid, @@ -474,7 +474,7 @@ func (a *covenantlessArkClient) processTransactionEvent( outputAmount := uint64(0) for _, v := range event.Redeem.SpendableVtxos { - if v.Pubkey == pubkey { + if v.PubKey == pubkey { vtxosToInsert = append(vtxosToInsert, types.Vtxo{ VtxoKey: types.VtxoKey{ Txid: v.Txid, @@ -507,7 +507,7 @@ func (a *covenantlessArkClient) processTransactionEvent( } } else { for _, v := range event.Redeem.SpendableVtxos { - if v.Pubkey == pubkey { + if v.PubKey == pubkey { vtxosToInsert = append(vtxosToInsert, types.Vtxo{ VtxoKey: types.VtxoKey{ Txid: v.Txid, @@ -708,13 +708,126 @@ func (a *covenantlessArkClient) SendOffChain( ctx context.Context, withExpiryCoinselect bool, receivers []Receiver, ) (string, error) { + if len(receivers) <= 0 { + return "", fmt.Errorf("missing receivers") + } + + netParams := utils.ToBitcoinNetwork(a.Network) for _, receiver := range receivers { - if receiver.IsOnchain() { - return "", fmt.Errorf("invalid receiver address '%s': must be offchain", receiver.To()) + isOnchain, _, err := utils.ParseBitcoinAddress(receiver.To(), netParams) + if err != nil { + return "", err + } + if isOnchain { + return "", fmt.Errorf("all receiver addresses must be offchain addresses") } } - return a.sendOffchain(ctx, withExpiryCoinselect, receivers) + offchainAddrs, _, _, err := a.wallet.GetAddresses(ctx) + if err != nil { + return "", err + } + + expectedServerPubkey := schnorr.SerializePubKey(a.ServerPubKey) + + sumOfReceivers := uint64(0) + + for _, receiver := range receivers { + rcvAddr, err := common.DecodeAddress(receiver.To()) + if err != nil { + return "", fmt.Errorf("invalid receiver address: %s", err) + } + + rcvServerPubkey := schnorr.SerializePubKey(rcvAddr.Server) + + if !bytes.Equal(expectedServerPubkey, rcvServerPubkey) { + return "", fmt.Errorf("invalid receiver address '%s': expected server %s, got %s", receiver.To(), hex.EncodeToString(expectedServerPubkey), hex.EncodeToString(rcvServerPubkey)) + } + + if receiver.Amount() < a.Dust { + return "", fmt.Errorf("invalid amount (%d), must be greater than dust %d", receiver.Amount(), a.Dust) + } + + sumOfReceivers += receiver.Amount() + } + + vtxos := make([]client.TapscriptsVtxo, 0) + opts := &CoinSelectOptions{ + WithExpirySorting: withExpiryCoinselect, + } + spendableVtxos, err := a.getVtxos(ctx, opts) + if err != nil { + return "", err + } + + for _, offchainAddr := range offchainAddrs { + for _, v := range spendableVtxos { + vtxoAddr, err := v.Address(a.ServerPubKey, a.Network) + if err != nil { + return "", err + } + + if vtxoAddr == offchainAddr.Address { + vtxos = append(vtxos, client.TapscriptsVtxo{ + Vtxo: v, + Tapscripts: offchainAddr.Tapscripts, + }) + } + } + } + + // do not include boarding utxos + _, selectedCoins, changeAmount, err := utils.CoinSelect( + nil, vtxos, sumOfReceivers, a.Dust, withExpiryCoinselect, + ) + if err != nil { + return "", err + } + + if changeAmount > 0 { + receivers = append(receivers, NewBitcoinReceiver(offchainAddrs[0].Address, changeAmount)) + } + + inputs := make([]redeemTxInput, 0, len(selectedCoins)) + + for _, coin := range selectedCoins { + vtxoScript, err := bitcointree.ParseVtxoScript(coin.Tapscripts) + if err != nil { + return "", err + } + + forfeitClosure := vtxoScript.ForfeitClosures()[0] + + forfeitScript, err := forfeitClosure.Script() + if err != nil { + return "", err + } + + forfeitLeaf := txscript.NewBaseTapLeaf(forfeitScript) + + inputs = append(inputs, redeemTxInput{ + coin, + forfeitLeaf.TapHash(), + }) + } + + feeRate := chainfee.FeePerKwFloor + redeemTx, err := buildRedeemTx(inputs, receivers, feeRate.FeePerVByte()) + if err != nil { + return "", err + } + + signedRedeemTx, err := a.wallet.SignTransaction(ctx, a.explorer, redeemTx) + if err != nil { + return "", err + } + + signedRedeemTx, err = a.client.SubmitRedeemTx(ctx, signedRedeemTx) + if err != nil { + return "", err + } + + return signedRedeemTx, nil } func (a *covenantlessArkClient) RedeemNotes(ctx context.Context, notes []string) (string, error) { @@ -741,7 +854,7 @@ func (a *covenantlessArkClient) RedeemNotes(ctx context.Context, notes []string) return "", err } - paymentID, err := a.client.RegisterNotesForNextRound( + requestID, err := a.client.RegisterNotesForNextRound( ctx, notes, hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()), ) if err != nil { @@ -756,15 +869,15 @@ func (a *covenantlessArkClient) RedeemNotes(ctx context.Context, notes []string) receiversOutput := []client.Output{output} if err := a.client.RegisterOutputsForNextRound( - ctx, paymentID, receiversOutput, + ctx, requestID, receiversOutput, ); err != nil { return "", err } - log.Infof("payment registered with id: %s", paymentID) + log.Infof("payout registered with id: %s", requestID) roundTxID, err := a.handleRoundStream( - ctx, paymentID, nil, nil, receiversOutput, roundEphemeralKey, + ctx, requestID, nil, nil, receiversOutput, roundEphemeralKey, ) if err != nil { return "", err @@ -865,7 +978,7 @@ func (a *covenantlessArkClient) CollaborativeRedeem( for _, offchainAddr := range offchainAddrs { for _, v := range spendableVtxos { - vtxoAddr, err := v.Address(a.AspPubkey, a.Network) + vtxoAddr, err := v.Address(a.ServerPubKey, a.Network) if err != nil { return "", err } @@ -929,7 +1042,7 @@ func (a *covenantlessArkClient) CollaborativeRedeem( return "", err } - paymentID, err := a.client.RegisterInputsForNextRound( + requestID, err := a.client.RegisterInputsForNextRound( ctx, inputs, hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()), @@ -938,12 +1051,12 @@ func (a *covenantlessArkClient) CollaborativeRedeem( return "", err } - if err := a.client.RegisterOutputsForNextRound(ctx, paymentID, receivers); err != nil { + if err := a.client.RegisterOutputsForNextRound(ctx, requestID, receivers); err != nil { return "", err } roundTxID, err := a.handleRoundStream( - ctx, paymentID, selectedCoins, selectedBoardingCoins, receivers, roundEphemeralKey, + ctx, requestID, selectedCoins, selectedBoardingCoins, receivers, roundEphemeralKey, ) if err != nil { return "", err @@ -952,132 +1065,6 @@ func (a *covenantlessArkClient) CollaborativeRedeem( return roundTxID, nil } -func (a *covenantlessArkClient) SendAsync( - ctx context.Context, - withExpiryCoinselect bool, receivers []Receiver, -) (string, error) { - if len(receivers) <= 0 { - return "", fmt.Errorf("missing receivers") - } - - netParams := utils.ToBitcoinNetwork(a.Network) - for _, receiver := range receivers { - isOnchain, _, err := utils.ParseBitcoinAddress(receiver.To(), netParams) - if err != nil { - return "", err - } - if isOnchain { - return "", fmt.Errorf("all receiver addresses must be offchain addresses") - } - } - - offchainAddrs, _, _, err := a.wallet.GetAddresses(ctx) - if err != nil { - return "", err - } - - expectedAspPubKey := schnorr.SerializePubKey(a.AspPubkey) - - sumOfReceivers := uint64(0) - - for _, receiver := range receivers { - rcvAddr, err := common.DecodeAddress(receiver.To()) - if err != nil { - return "", fmt.Errorf("invalid receiver address: %s", err) - } - - rcvAspPubKey := schnorr.SerializePubKey(rcvAddr.Asp) - - if !bytes.Equal(expectedAspPubKey, rcvAspPubKey) { - return "", fmt.Errorf("invalid receiver address '%s': expected ASP %s, got %s", receiver.To(), hex.EncodeToString(expectedAspPubKey), hex.EncodeToString(rcvAspPubKey)) - } - - if receiver.Amount() < a.Dust { - return "", fmt.Errorf("invalid amount (%d), must be greater than dust %d", receiver.Amount(), a.Dust) - } - - sumOfReceivers += receiver.Amount() - } - - vtxos := make([]client.TapscriptsVtxo, 0) - opts := &CoinSelectOptions{ - WithExpirySorting: withExpiryCoinselect, - } - spendableVtxos, err := a.getVtxos(ctx, opts) - if err != nil { - return "", err - } - - for _, offchainAddr := range offchainAddrs { - for _, v := range spendableVtxos { - vtxoAddr, err := v.Address(a.AspPubkey, a.Network) - if err != nil { - return "", err - } - - if vtxoAddr == offchainAddr.Address { - vtxos = append(vtxos, client.TapscriptsVtxo{ - Vtxo: v, - Tapscripts: offchainAddr.Tapscripts, - }) - } - } - } - - // do not include boarding utxos - _, selectedCoins, changeAmount, err := utils.CoinSelect( - nil, vtxos, sumOfReceivers, a.Dust, withExpiryCoinselect, - ) - if err != nil { - return "", err - } - - if changeAmount > 0 { - receivers = append(receivers, NewBitcoinReceiver(offchainAddrs[0].Address, changeAmount)) - } - - inputs := make([]redeemTxInput, 0, len(selectedCoins)) - - for _, coin := range selectedCoins { - vtxoScript, err := bitcointree.ParseVtxoScript(coin.Tapscripts) - if err != nil { - return "", err - } - - forfeitClosure := vtxoScript.ForfeitClosures()[0] - - forfeitScript, err := forfeitClosure.Script() - if err != nil { - return "", err - } - - forfeitLeaf := txscript.NewBaseTapLeaf(forfeitScript) - - inputs = append(inputs, redeemTxInput{ - coin, - forfeitLeaf.TapHash(), - }) - } - - feeRate := chainfee.FeePerKwFloor - redeemTx, err := buildRedeemTx(inputs, receivers, feeRate.FeePerVByte()) - if err != nil { - return "", err - } - - signedRedeemTx, err := a.wallet.SignTransaction(ctx, a.explorer, redeemTx) - if err != nil { - return "", err - } - - signedRedeemTx, err = a.client.SubmitRedeemTx(ctx, signedRedeemTx) - if err != nil { - return "", err - } - - return signedRedeemTx, nil -} - func (a *covenantlessArkClient) Settle(ctx context.Context) (string, error) { return a.sendOffchain(ctx, false, nil) } @@ -1136,7 +1123,7 @@ func (a *covenantlessArkClient) SetNostrNotificationRecipient(ctx context.Contex descriptorVtxos := make([]client.TapscriptsVtxo, 0) for _, offchainAddr := range offchainAddrs { for _, vtxo := range spendableVtxos { - vtxoAddr, err := vtxo.Address(a.AspPubkey, a.Network) + vtxoAddr, err := vtxo.Address(a.ServerPubKey, a.Network) if err != nil { return err } @@ -1362,7 +1349,7 @@ func (a *covenantlessArkClient) sendOffchain( return "", fmt.Errorf("wallet is locked") } - expectedAspPubKey := schnorr.SerializePubKey(a.AspPubkey) + expectedServerPubkey := schnorr.SerializePubKey(a.ServerPubKey) outputs := make([]client.Output, 0) sumOfReceivers := uint64(0) @@ -1373,10 +1360,10 @@ func (a *covenantlessArkClient) sendOffchain( return "", fmt.Errorf("invalid receiver address: %s", err) } - rcvAspPubKey := schnorr.SerializePubKey(rcvAddr.Asp) + rcvServerPubkey := schnorr.SerializePubKey(rcvAddr.Server) - if !bytes.Equal(expectedAspPubKey, rcvAspPubKey) { - return "", fmt.Errorf("invalid receiver address '%s': expected ASP %s, got %s", receiver.To(), hex.EncodeToString(expectedAspPubKey), hex.EncodeToString(rcvAspPubKey)) + if !bytes.Equal(expectedServerPubkey, rcvServerPubkey) { + return "", fmt.Errorf("invalid receiver address '%s': expected server %s, got %s", receiver.To(), hex.EncodeToString(expectedServerPubkey), hex.EncodeToString(rcvServerPubkey)) } if receiver.Amount() < a.Dust { @@ -1408,7 +1395,7 @@ func (a *covenantlessArkClient) sendOffchain( for _, offchainAddr := range offchainAddrs { for _, v := range spendableVtxos { - vtxoAddr, err := v.Address(a.AspPubkey, a.Network) + vtxoAddr, err := v.Address(a.ServerPubKey, a.Network) if err != nil { return "", err } @@ -1495,7 +1482,7 @@ func (a *covenantlessArkClient) sendOffchain( return "", err } - paymentID, err := a.client.RegisterInputsForNextRound( + requestID, err := a.client.RegisterInputsForNextRound( ctx, inputs, hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()), ) if err != nil { @@ -1503,15 +1490,15 @@ func (a *covenantlessArkClient) sendOffchain( } if err := a.client.RegisterOutputsForNextRound( - ctx, paymentID, outputs, + ctx, requestID, outputs, ); err != nil { return "", err } - log.Infof("payment registered with id: %s", paymentID) + log.Infof("registered inputs and outputs with request id: %s", requestID) roundTxID, err := a.handleRoundStream( - ctx, paymentID, selectedCoins, selectedBoardingCoins, outputs, roundEphemeralKey, + ctx, requestID, selectedCoins, selectedBoardingCoins, outputs, roundEphemeralKey, ) if err != nil { return "", err @@ -1594,7 +1581,7 @@ func (a *covenantlessArkClient) addInputs( func (a *covenantlessArkClient) handleRoundStream( ctx context.Context, - paymentID string, + requestID string, vtxosToSign []client.TapscriptsVtxo, boardingUtxos []types.Utxo, receivers []client.Output, @@ -1605,14 +1592,14 @@ func (a *covenantlessArkClient) handleRoundStream( return "", err } - eventsCh, close, err := a.client.GetEventStream(ctx, paymentID) + eventsCh, close, err := a.client.GetEventStream(ctx, requestID) if err != nil { return "", err } var pingStop func() for pingStop == nil { - pingStop = a.ping(ctx, paymentID) + pingStop = a.ping(ctx, requestID) } defer func() { @@ -1697,7 +1684,7 @@ func (a *covenantlessArkClient) handleRoundStream( continue } - log.Info("finalizing payment... ") + log.Info("submitting forfeit transactions... ") if err := a.client.SubmitSignedForfeitTxs(ctx, signedForfeitTxs, signedRoundTx); err != nil { return "", err } @@ -1715,7 +1702,7 @@ func (a *covenantlessArkClient) handleRoundSigningStarted( ctx context.Context, ephemeralKey *secp256k1.PrivateKey, event client.RoundSigningStartedEvent, ) (signerSession bitcointree.SignerSession, err error) { sweepClosure := tree.CSVSigClosure{ - MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{a.AspPubkey}}, + MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{a.ServerPubKey}}, Seconds: uint(a.RoundLifetime), } @@ -1740,7 +1727,7 @@ func (a *covenantlessArkClient) handleRoundSigningStarted( ephemeralKey, sharedOutputValue, event.UnsignedTree, root.CloneBytes(), ) - if err = signerSession.SetKeys(event.CosignersPublicKeys); err != nil { + if err = signerSession.SetKeys(event.CosignersPubKeys); err != nil { return } @@ -1749,9 +1736,9 @@ func (a *covenantlessArkClient) handleRoundSigningStarted( return } - myPubKey := hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed()) + myPubkey := hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed()) - err = a.arkClient.client.SubmitTreeNonces(ctx, event.ID, myPubKey, nonces) + err = a.arkClient.client.SubmitTreeNonces(ctx, event.ID, myPubkey, nonces) return } @@ -1794,8 +1781,8 @@ func (a *covenantlessArkClient) handleRoundFinalization( boardingUtxos []types.Utxo, receivers []client.Output, ) ([]string, string, error) { - if err := a.validateCongestionTree(event, receivers); err != nil { - return nil, "", fmt.Errorf("failed to verify congestion tree: %s", err) + if err := a.validateVtxoTree(event, receivers); err != nil { + return nil, "", fmt.Errorf("failed to verify vtxo tree: %s", err) } var forfeits []string @@ -1880,24 +1867,25 @@ func (a *covenantlessArkClient) handleRoundFinalization( return forfeits, signedRoundTx, nil } -func (a *covenantlessArkClient) validateCongestionTree( +func (a *covenantlessArkClient) validateVtxoTree( event client.RoundFinalizationEvent, receivers []client.Output, ) error { - poolTx := event.Tx - ptx, err := psbt.NewFromRawBytes(strings.NewReader(poolTx), true) + roundTx := event.Tx + ptx, err := psbt.NewFromRawBytes(strings.NewReader(roundTx), true) if err != nil { return err } if !utils.IsOnchainOnly(receivers) { - if err := bitcointree.ValidateCongestionTree( - event.Tree, poolTx, a.Config.AspPubkey, a.RoundLifetime, + if err := bitcointree.ValidateVtxoTree( + event.Tree, roundTx, a.Config.ServerPubKey, a.RoundLifetime, ); err != nil { return err } } - // if err := common.ValidateConnectors(poolTx, event.Connectors); err != nil { + // TODO: common.ValidateConnectors is for covenant version (liquid), add covenantless (bitcoin) version + // if err := common.ValidateConnectors(roundTx, event.Connectors); err != nil { // return err // } @@ -1907,15 +1895,13 @@ func (a *covenantlessArkClient) validateCongestionTree( return err } - log.Info("congestion tree validated") - return nil } func (a *covenantlessArkClient) validateReceivers( ptx *psbt.Packet, receivers []client.Output, - congestionTree tree.CongestionTree, + vtxoTree tree.VtxoTree, ) error { netParams := utils.ToBitcoinNetwork(a.Network) for _, receiver := range receivers { @@ -1932,7 +1918,7 @@ func (a *covenantlessArkClient) validateReceivers( } } else { if err := a.validateOffChainReceiver( - congestionTree, receiver, + vtxoTree, receiver, ); err != nil { return err } @@ -1966,7 +1952,7 @@ func (a *covenantlessArkClient) validateOnChainReceiver( } func (a *covenantlessArkClient) validateOffChainReceiver( - congestionTree tree.CongestionTree, + vtxoTree tree.VtxoTree, receiver client.Output, ) error { found := false @@ -1978,7 +1964,7 @@ func (a *covenantlessArkClient) validateOffChainReceiver( vtxoTapKey := schnorr.SerializePubKey(rcvAddr.VtxoTapKey) - leaves := congestionTree.Leaves() + leaves := vtxoTree.Leaves() for _, leaf := range leaves { tx, err := psbt.NewFromRawBytes(strings.NewReader(leaf.Tx), true) if err != nil { @@ -2247,7 +2233,7 @@ func (a *covenantlessArkClient) coinSelectOnchain( func (a *covenantlessArkClient) getRedeemBranches( ctx context.Context, vtxos []client.Vtxo, ) (map[string]*redemption.CovenantlessRedeemBranch, error) { - congestionTrees := make(map[string]tree.CongestionTree, 0) + vtxoTrees := make(map[string]tree.VtxoTree, 0) redeemBranches := make(map[string]*redemption.CovenantlessRedeemBranch, 0) for i := range vtxos { @@ -2258,17 +2244,17 @@ func (a *covenantlessArkClient) getRedeemBranches( continue } - if _, ok := congestionTrees[vtxo.RoundTxid]; !ok { + if _, ok := vtxoTrees[vtxo.RoundTxid]; !ok { round, err := a.client.GetRound(ctx, vtxo.RoundTxid) if err != nil { return nil, err } - congestionTrees[vtxo.RoundTxid] = round.Tree + vtxoTrees[vtxo.RoundTxid] = round.Tree } redeemBranch, err := redemption.NewCovenantlessRedeemBranch( - a.explorer, congestionTrees[vtxo.RoundTxid], vtxo, + a.explorer, vtxoTrees[vtxo.RoundTxid], vtxo, ) if err != nil { return nil, err diff --git a/pkg/client-sdk/example/covenant/alice_to_bob.go b/pkg/client-sdk/example/covenant/alice_to_bob.go index b11e6b4..28df7f1 100644 --- a/pkg/client-sdk/example/covenant/alice_to_bob.go +++ b/pkg/client-sdk/example/covenant/alice_to_bob.go @@ -18,7 +18,7 @@ import ( ) var ( - aspUrl = "localhost:6060" + serverUrl = "localhost:6060" clientType = arksdk.GrpcClient password = "password" walletType = arksdk.SingleKeyWallet @@ -110,7 +110,7 @@ func main() { log.Fatal(err) } - log.Infof("payment completed in round tx: %s", txid) + log.Infof("transaction completed in round: %s", txid) if err := generateBlock(); err != nil { log.Fatal(err) @@ -155,7 +155,7 @@ func setupArkClient(wallet string) (arksdk.ArkClient, error) { if err := client.Init(context.Background(), arksdk.InitArgs{ WalletType: walletType, ClientType: clientType, - AspUrl: aspUrl, + ServerUrl: serverUrl, Password: password, }); err != nil { return nil, fmt.Errorf("failed to initialize wallet: %s", err) diff --git a/pkg/client-sdk/example/covenant/wasm/index.html b/pkg/client-sdk/example/covenant/wasm/index.html index c618582..5efa1f1 100644 --- a/pkg/client-sdk/example/covenant/wasm/index.html +++ b/pkg/client-sdk/example/covenant/wasm/index.html @@ -28,13 +28,13 @@ logMessage("Init error: password is required"); return; } - const aspUrl = document.getElementById("aspUrl").value; - if (!aspUrl) { - logMessage("Init error: asp url is required"); + const serverUrl = document.getElementById("serverUrl").value; + if (!serverUrl) { + logMessage("Init error: server url is required"); return; } - await init(walletType, clientType, aspUrl, privateKey, password, chain, explorerUrl); - logMessage("wallet initialized and connected to ASP"); + await init(walletType, clientType, serverUrl, privateKey, password, chain, explorerUrl); + logMessage("wallet initialized and connected to server"); await config(); } catch (err) { logMessage("Init error: " + err.message); @@ -91,11 +91,11 @@ async function config() { try { - const aspUrl = await getAspUrl(); - logMessage("ASP URL: " + aspUrl); + const serverUrl = await getServerUrl(); + logMessage("Server URL: " + serverUrl); - const aspPubKeyHex = await getAspPubKeyHex(); - logMessage("ASP PubKey: " + aspPubKeyHex); + const serverPubkeyHex = await getServerPubkeyHex(); + logMessage("Server PubKey: " + serverPubkeyHex); const walletType = await getWalletType(); logMessage("Wallet Type: " + walletType); @@ -145,7 +145,7 @@

Wallet

- +
diff --git a/pkg/client-sdk/example/covenantless/alice_to_bob.go b/pkg/client-sdk/example/covenantless/alice_to_bob.go index 24f1695..9792e7f 100644 --- a/pkg/client-sdk/example/covenantless/alice_to_bob.go +++ b/pkg/client-sdk/example/covenantless/alice_to_bob.go @@ -18,7 +18,7 @@ import ( ) var ( - aspUrl = "localhost:7070" + serverUrl = "localhost:7070" clientType = arksdk.GrpcClient password = "password" walletType = arksdk.SingleKeyWallet @@ -128,11 +128,11 @@ func main() { fmt.Println("") log.Infof("alice is sending %d sats to bob offchain...", amount) - if _, err = aliceArkClient.SendAsync(ctx, false, receivers); err != nil { + if _, err = aliceArkClient.SendOffChain(ctx, false, receivers); err != nil { log.Fatal(err) } - log.Info("payment completed out of round") + log.Info("transaction completed out of round") if err := generateBlock(); err != nil { log.Fatal(err) @@ -188,7 +188,7 @@ func setupArkClient(wallet string) (arksdk.ArkClient, error) { if err := client.Init(context.Background(), arksdk.InitArgs{ WalletType: walletType, ClientType: clientType, - AspUrl: aspUrl, + ServerUrl: serverUrl, Password: password, WithTransactionFeed: true, }); err != nil { diff --git a/pkg/client-sdk/example/covenantless/wasm/index.html b/pkg/client-sdk/example/covenantless/wasm/index.html index cd40119..c3e09dc 100644 --- a/pkg/client-sdk/example/covenantless/wasm/index.html +++ b/pkg/client-sdk/example/covenantless/wasm/index.html @@ -28,13 +28,13 @@ logMessage("Init error: password is required"); return; } - const aspUrl = document.getElementById("aspUrl").value; - if (!aspUrl) { - logMessage("Init error: asp url is required"); + const serverUrl = document.getElementById("serverUrl").value; + if (!serverUrl) { + logMessage("Init error: server url is required"); return; } - await init(walletType, clientType, aspUrl, privateKey, password, chain, explorerUrl); - logMessage("wallet initialized and connected to ASP"); + await init(walletType, clientType, serverUrl, privateKey, password, chain, explorerUrl); + logMessage("wallet initialized and connected to server"); await config(); } catch (err) { logMessage("Init error: " + err.message); @@ -119,11 +119,11 @@ async function config() { try { - const aspUrl = await getAspUrl(); - logMessage("ASP URL: " + aspUrl); + const serverUrl = await getServerUrl(); + logMessage("Server URL: " + serverUrl); - const aspPubKeyHex = await getAspPubKeyHex(); - logMessage("ASP PubKey: " + aspPubKeyHex); + const serverPubkeyHex = await getServerPubkeyHex(); + logMessage("Server Pubkey: " + serverPubkeyHex); const walletType = await getWalletType(); logMessage("Wallet Type: " + walletType); @@ -149,7 +149,7 @@

Wallet

- +
diff --git a/pkg/client-sdk/internal/utils/types.go b/pkg/client-sdk/internal/utils/types.go index fb3dec0..3852ff8 100644 --- a/pkg/client-sdk/internal/utils/types.go +++ b/pkg/client-sdk/internal/utils/types.go @@ -22,7 +22,7 @@ func (t SupportedType[V]) Supports(typeStr string) bool { return ok } -type ClientFactory func(string) (client.ASPClient, error) +type ClientFactory func(string) (client.TransportClient, error) type Cache[V any] struct { mapping map[string]V diff --git a/pkg/client-sdk/internal/utils/utils.go b/pkg/client-sdk/internal/utils/utils.go index 40fb3a7..5f4cd68 100644 --- a/pkg/client-sdk/internal/utils/utils.go +++ b/pkg/client-sdk/internal/utils/utils.go @@ -173,11 +173,11 @@ func ToBitcoinNetwork(net common.Network) chaincfg.Params { } func GenerateRandomPrivateKey() (*secp256k1.PrivateKey, error) { - privKey, err := btcec.NewPrivateKey() + prvkey, err := btcec.NewPrivateKey() if err != nil { return nil, err } - return privKey, nil + return prvkey, nil } func HashPassword(password []byte) []byte { diff --git a/pkg/client-sdk/redemption/covenant_redeem.go b/pkg/client-sdk/redemption/covenant_redeem.go index 1b7278d..6e6f70f 100644 --- a/pkg/client-sdk/redemption/covenant_redeem.go +++ b/pkg/client-sdk/redemption/covenant_redeem.go @@ -24,9 +24,9 @@ type CovenantRedeemBranch struct { func NewCovenantRedeemBranch( explorer explorer.Explorer, - congestionTree tree.CongestionTree, vtxo client.Vtxo, + vtxoTree tree.VtxoTree, vtxo client.Vtxo, ) (*CovenantRedeemBranch, error) { - sweepClosure, seconds, err := findCovenantSweepClosure(congestionTree) + sweepClosure, seconds, err := findCovenantSweepClosure(vtxoTree) if err != nil { return nil, err } @@ -36,7 +36,7 @@ func NewCovenantRedeemBranch( return nil, err } - nodes, err := congestionTree.Branch(vtxo.Txid) + nodes, err := vtxoTree.Branch(vtxo.Txid) if err != nil { return nil, err } @@ -182,9 +182,9 @@ func (r *CovenantRedeemBranch) offchainPath() ([]*psetv2.Pset, error) { } func findCovenantSweepClosure( - congestionTree tree.CongestionTree, + vtxoTree tree.VtxoTree, ) (*taproot.TapElementsLeaf, uint, error) { - root, err := congestionTree.Root() + root, err := vtxoTree.Root() if err != nil { return nil, 0, err } diff --git a/pkg/client-sdk/redemption/covenantless_redeem.go b/pkg/client-sdk/redemption/covenantless_redeem.go index 1b15830..1f7771b 100644 --- a/pkg/client-sdk/redemption/covenantless_redeem.go +++ b/pkg/client-sdk/redemption/covenantless_redeem.go @@ -23,9 +23,9 @@ type CovenantlessRedeemBranch struct { func NewCovenantlessRedeemBranch( explorer explorer.Explorer, - congestionTree tree.CongestionTree, vtxo client.Vtxo, + vtxoTree tree.VtxoTree, vtxo client.Vtxo, ) (*CovenantlessRedeemBranch, error) { - _, seconds, err := findCovenantlessSweepClosure(congestionTree) + _, seconds, err := findCovenantlessSweepClosure(vtxoTree) if err != nil { return nil, err } @@ -35,7 +35,7 @@ func NewCovenantlessRedeemBranch( return nil, err } - nodes, err := congestionTree.Branch(vtxo.Txid) + nodes, err := vtxoTree.Branch(vtxo.Txid) if err != nil { return nil, err } @@ -155,9 +155,9 @@ func (r *CovenantlessRedeemBranch) OffchainPath() ([]*psbt.Packet, error) { } func findCovenantlessSweepClosure( - congestionTree tree.CongestionTree, + vtxoTree tree.VtxoTree, ) (*txscript.TapLeaf, uint, error) { - root, err := congestionTree.Root() + root, err := vtxoTree.Root() if err != nil { return nil, 0, err } diff --git a/pkg/client-sdk/store/file/config_store.go b/pkg/client-sdk/store/file/config_store.go index bfd2c2d..f39c0ce 100644 --- a/pkg/client-sdk/store/file/config_store.go +++ b/pkg/client-sdk/store/file/config_store.go @@ -52,8 +52,8 @@ func (s *configStore) GetDatadir() string { func (s *configStore) AddData(ctx context.Context, data types.Config) error { sd := &storeData{ - AspUrl: data.AspUrl, - AspPubkey: hex.EncodeToString(data.AspPubkey.SerializeCompressed()), + ServerUrl: data.ServerUrl, + ServerPubKey: hex.EncodeToString(data.ServerPubKey.SerializeCompressed()), WalletType: data.WalletType, ClientType: data.ClientType, Network: data.Network.Name, diff --git a/pkg/client-sdk/store/file/types.go b/pkg/client-sdk/store/file/types.go index f1f49c4..d91876b 100644 --- a/pkg/client-sdk/store/file/types.go +++ b/pkg/client-sdk/store/file/types.go @@ -10,8 +10,8 @@ import ( ) type storeData struct { - AspUrl string `json:"asp_url"` - AspPubkey string `json:"asp_pubkey"` + ServerUrl string `json:"server_url"` + ServerPubKey string `json:"server_pubkey"` WalletType string `json:"wallet_type"` ClientType string `json:"client_type"` Network string `json:"network"` @@ -26,8 +26,8 @@ type storeData struct { } func (d storeData) isEmpty() bool { - if d.AspUrl == "" && - d.AspPubkey == "" { + if d.ServerUrl == "" && + d.ServerPubKey == "" { return true } @@ -41,12 +41,12 @@ func (d storeData) decode() types.Config { unilateralExitDelay, _ := strconv.Atoi(d.UnilateralExitDelay) withTransactionFeed, _ := strconv.ParseBool(d.WithTransactionFeed) dust, _ := strconv.Atoi(d.Dust) - buf, _ := hex.DecodeString(d.AspPubkey) - aspPubkey, _ := secp256k1.ParsePubKey(buf) + buf, _ := hex.DecodeString(d.ServerPubKey) + serverPubkey, _ := secp256k1.ParsePubKey(buf) explorerURL := d.ExplorerURL return types.Config{ - AspUrl: d.AspUrl, - AspPubkey: aspPubkey, + ServerUrl: d.ServerUrl, + ServerPubKey: serverPubkey, WalletType: d.WalletType, ClientType: d.ClientType, Network: network, @@ -63,8 +63,8 @@ func (d storeData) decode() types.Config { func (d storeData) asMap() map[string]string { return map[string]string{ - "asp_url": d.AspUrl, - "asp_pubkey": d.AspPubkey, + "server_url": d.ServerUrl, + "server_pubkey": d.ServerPubKey, "wallet_type": d.WalletType, "client_type": d.ClientType, "network": d.Network, diff --git a/pkg/client-sdk/store/service_test.go b/pkg/client-sdk/store/service_test.go index 8be0fd6..f1a5c50 100644 --- a/pkg/client-sdk/store/service_test.go +++ b/pkg/client-sdk/store/service_test.go @@ -21,8 +21,8 @@ func TestStore(t *testing.T) { key, _ := btcec.NewPrivateKey() ctx := context.Background() testStoreData := sdktypes.Config{ - AspUrl: "localhost:7070", - AspPubkey: key.PubKey(), + ServerUrl: "localhost:7070", + ServerPubKey: key.PubKey(), WalletType: wallet.SingleKeyWallet, ClientType: client.GrpcClient, Network: common.LiquidRegTest, diff --git a/pkg/client-sdk/test/wasm/wasm_test.go b/pkg/client-sdk/test/wasm/wasm_test.go index 864d9c0..c631ef6 100644 --- a/pkg/client-sdk/test/wasm/wasm_test.go +++ b/pkg/client-sdk/test/wasm/wasm_test.go @@ -4,10 +4,6 @@ import ( "bytes" "encoding/json" "fmt" - utils "github.com/ark-network/ark/server/test/e2e" - "github.com/playwright-community/playwright-go" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "io" "net/http" "os" @@ -18,6 +14,11 @@ import ( "testing" "time" + utils "github.com/ark-network/ark/server/test/e2e" + "github.com/playwright-community/playwright-go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/shirou/gopsutil/net" ) @@ -51,7 +52,7 @@ func TestMain(m *testing.M) { os.Exit(1) } - _, err = runClarkCommand("init", "--asp-url", "localhost:7070", "--password", utils.Password, "--network", "regtest", "--explorer", "http://chopsticks:3000") + _, err = runClarkCommand("init", "--server-url", "localhost:7070", "--password", utils.Password, "--network", "regtest", "--explorer", "http://chopsticks:3000") if err != nil { fmt.Printf("error initializing ark config: %s", err) os.Exit(1) @@ -139,9 +140,9 @@ func TestWasm(t *testing.T) { amount := 1000 t.Logf("Alice is sending %d sats to Bob offchain...", amount) - require.NoError(t, sendAsync(alicePage, bobAddr.OffchainAddr, amount)) + require.NoError(t, sendOffChain(alicePage, bobAddr.OffchainAddr, amount)) - t.Log("Payment completed out of round") + t.Log("Transaction completed out of round") t.Logf("Bob settling the received funds...") txID, err = settle(bobPage) @@ -231,8 +232,8 @@ func initWallet(page playwright.Page) error { const privateKey = ""; const password = "pass"; const explorerUrl = ""; - const aspUrl = "http://localhost:7070"; - return await init(walletType, clientType, aspUrl, privateKey, password, chain, explorerUrl); + const serverUrl = "http://localhost:7070"; + return await init(walletType, clientType, serverUrl, privateKey, password, chain, explorerUrl); } catch (err) { console.error("Init error:", err); throw err; @@ -336,10 +337,10 @@ func settle(page playwright.Page) (string, error) { return fmt.Sprint(result), nil } -func sendAsync(page playwright.Page, addr string, amount int) error { +func sendOffChain(page playwright.Page, addr string, amount int) error { _, err := page.Evaluate(fmt.Sprintf(`async () => { try { - return await sendAsync(false, [{To:"%s", Amount:%d}]); + return await sendOffChain(false, [{To:"%s", Amount:%d}]); } catch (err) { console.error("Error:", err); throw err; diff --git a/pkg/client-sdk/types.go b/pkg/client-sdk/types.go index 38c56ce..9fc388d 100644 --- a/pkg/client-sdk/types.go +++ b/pkg/client-sdk/types.go @@ -23,7 +23,7 @@ var ( type InitArgs struct { ClientType string WalletType string - AspUrl string + ServerUrl string Seed string Password string ExplorerURL string @@ -51,8 +51,8 @@ func (a InitArgs) validate() error { ) } - if len(a.AspUrl) <= 0 { - return fmt.Errorf("missing asp url") + if len(a.ServerUrl) <= 0 { + return fmt.Errorf("missing server url") } if len(a.Password) <= 0 { return fmt.Errorf("missing password") @@ -63,7 +63,7 @@ func (a InitArgs) validate() error { type InitWithWalletArgs struct { ClientType string Wallet wallet.WalletService - AspUrl string + ServerUrl string Seed string Password string ExplorerURL string @@ -82,8 +82,8 @@ func (a InitWithWalletArgs) validate() error { return fmt.Errorf("client type not supported, please select one of: %s", supportedClients) } - if len(a.AspUrl) <= 0 { - return fmt.Errorf("missing asp url") + if len(a.ServerUrl) <= 0 { + return fmt.Errorf("missing server url") } if len(a.Password) <= 0 { return fmt.Errorf("missing password") diff --git a/pkg/client-sdk/types/types.go b/pkg/client-sdk/types/types.go index cdb4e70..8357158 100644 --- a/pkg/client-sdk/types/types.go +++ b/pkg/client-sdk/types/types.go @@ -16,8 +16,8 @@ const ( ) type Config struct { - AspUrl string - AspPubkey *secp256k1.PublicKey + ServerUrl string + ServerPubKey *secp256k1.PublicKey WalletType string ClientType string Network common.Network diff --git a/pkg/client-sdk/wallet/singlekey/bitcoin_wallet.go b/pkg/client-sdk/wallet/singlekey/bitcoin_wallet.go index 70cf402..326eceb 100644 --- a/pkg/client-sdk/wallet/singlekey/bitcoin_wallet.go +++ b/pkg/client-sdk/wallet/singlekey/bitcoin_wallet.go @@ -193,7 +193,7 @@ func (s *bitcoinWallet) SignTransaction( ) txsighashes := txscript.NewTxSigHashes(updater.Upsbt.UnsignedTx, prevoutFetcher) - myPubkey := schnorr.SerializePubKey(s.walletData.Pubkey) + myPubkey := schnorr.SerializePubKey(s.walletData.PubKey) for i, input := range ptx.Inputs { if len(input.TaprootLeafScript) > 0 { @@ -246,7 +246,7 @@ func (s *bitcoinWallet) SignTransaction( return "", err } - if !sig.Verify(preimage, s.walletData.Pubkey) { + if !sig.Verify(preimage, s.walletData.PubKey) { return "", fmt.Errorf("signature verification failed") } @@ -308,8 +308,8 @@ func (w *bitcoinWallet) getAddress( netParams := utils.ToBitcoinNetwork(data.Network) defaultVtxoScript := bitcointree.NewDefaultVtxoScript( - w.walletData.Pubkey, - data.AspPubkey, + w.walletData.PubKey, + data.ServerPubKey, uint(data.UnilateralExitDelay), ) @@ -320,13 +320,13 @@ func (w *bitcoinWallet) getAddress( offchainAddress := &common.Address{ HRP: data.Network.Addr, - Asp: data.AspPubkey, + Server: data.ServerPubKey, VtxoTapKey: vtxoTapKey, } boardingVtxoScript := bitcointree.NewDefaultVtxoScript( - w.walletData.Pubkey, - data.AspPubkey, + w.walletData.PubKey, + data.ServerPubKey, uint(data.UnilateralExitDelay*2), ) diff --git a/pkg/client-sdk/wallet/singlekey/liquid_wallet.go b/pkg/client-sdk/wallet/singlekey/liquid_wallet.go index c89dd62..678ee60 100644 --- a/pkg/client-sdk/wallet/singlekey/liquid_wallet.go +++ b/pkg/client-sdk/wallet/singlekey/liquid_wallet.go @@ -211,7 +211,7 @@ func (s *liquidWallet) SignTransaction( prevoutsAssets = append(prevoutsAssets, input.WitnessUtxo.Asset) } - myPubkey := schnorr.SerializePubKey(s.walletData.Pubkey) + myPubkey := schnorr.SerializePubKey(s.walletData.PubKey) for i, input := range pset.Inputs { if len(input.TapLeafScript) > 0 { @@ -265,7 +265,7 @@ func (s *liquidWallet) SignTransaction( tapScriptSig := psetv2.TapScriptSig{ PartialSig: psetv2.PartialSig{ - PubKey: schnorr.SerializePubKey(s.walletData.Pubkey), + PubKey: schnorr.SerializePubKey(s.walletData.PubKey), Signature: sig.Serialize(), }, LeafHash: hash.CloneBytes(), @@ -330,8 +330,8 @@ func (w *liquidWallet) getAddress( liquidNet := utils.ToElementsNetwork(data.Network) vtxoScript := tree.NewDefaultVtxoScript( - w.walletData.Pubkey, - data.AspPubkey, + w.walletData.PubKey, + data.ServerPubKey, uint(data.UnilateralExitDelay), ) @@ -342,13 +342,13 @@ func (w *liquidWallet) getAddress( offchainAddr := &common.Address{ HRP: data.Network.Addr, - Asp: data.AspPubkey, + Server: data.ServerPubKey, VtxoTapKey: vtxoTapKey, } boardingVtxoScript := tree.NewDefaultVtxoScript( - w.walletData.Pubkey, - data.AspPubkey, + w.walletData.PubKey, + data.ServerPubKey, uint(data.UnilateralExitDelay*2), ) diff --git a/pkg/client-sdk/wallet/singlekey/store/file/store.go b/pkg/client-sdk/wallet/singlekey/store/file/store.go index 88e9372..2859474 100644 --- a/pkg/client-sdk/wallet/singlekey/store/file/store.go +++ b/pkg/client-sdk/wallet/singlekey/store/file/store.go @@ -20,7 +20,7 @@ const ( type walletData struct { EncryptedPrvkey string `json:"encrypted_private_key"` PasswordHash string `json:"password_hash"` - Pubkey string `json:"pubkey"` + PubKey string `json:"pubkey"` } func (d walletData) isEmpty() bool { @@ -30,12 +30,12 @@ func (d walletData) isEmpty() bool { func (d walletData) decode() walletstore.WalletData { encryptedPrvkey, _ := hex.DecodeString(d.EncryptedPrvkey) passwordHash, _ := hex.DecodeString(d.PasswordHash) - buf, _ := hex.DecodeString(d.Pubkey) + buf, _ := hex.DecodeString(d.PubKey) pubkey, _ := secp256k1.ParsePubKey(buf) return walletstore.WalletData{ EncryptedPrvkey: encryptedPrvkey, PasswordHash: passwordHash, - Pubkey: pubkey, + PubKey: pubkey, } } @@ -43,7 +43,7 @@ func (d walletData) asMap() map[string]string { return map[string]string{ "encrypted_private_key": d.EncryptedPrvkey, "password_hash": d.PasswordHash, - "pubkey": d.Pubkey, + "pubkey": d.PubKey, } } @@ -71,7 +71,7 @@ func (s *fileStore) AddWallet(data walletstore.WalletData) error { wd := &walletData{ EncryptedPrvkey: hex.EncodeToString(data.EncryptedPrvkey), PasswordHash: hex.EncodeToString(data.PasswordHash), - Pubkey: hex.EncodeToString(data.Pubkey.SerializeCompressed()), + PubKey: hex.EncodeToString(data.PubKey.SerializeCompressed()), } if err := s.write(wd); err != nil { diff --git a/pkg/client-sdk/wallet/singlekey/store/store.go b/pkg/client-sdk/wallet/singlekey/store/store.go index c9c139e..d7fb750 100644 --- a/pkg/client-sdk/wallet/singlekey/store/store.go +++ b/pkg/client-sdk/wallet/singlekey/store/store.go @@ -7,7 +7,7 @@ import ( type WalletData struct { EncryptedPrvkey []byte PasswordHash []byte - Pubkey *secp256k1.PublicKey + PubKey *secp256k1.PublicKey } type WalletStore interface { diff --git a/pkg/client-sdk/wallet/singlekey/store/store_test.go b/pkg/client-sdk/wallet/singlekey/store/store_test.go index a903d50..ee29fd1 100644 --- a/pkg/client-sdk/wallet/singlekey/store/store_test.go +++ b/pkg/client-sdk/wallet/singlekey/store/store_test.go @@ -16,7 +16,7 @@ func TestWalletStore(t *testing.T) { testWalletData := walletstore.WalletData{ EncryptedPrvkey: make([]byte, 32), PasswordHash: make([]byte, 32), - Pubkey: key.PubKey(), + PubKey: key.PubKey(), } tests := []struct { diff --git a/pkg/client-sdk/wallet/singlekey/wallet.go b/pkg/client-sdk/wallet/singlekey/wallet.go index 4dceb17..8765d04 100644 --- a/pkg/client-sdk/wallet/singlekey/wallet.go +++ b/pkg/client-sdk/wallet/singlekey/wallet.go @@ -29,18 +29,18 @@ func (w *singlekeyWallet) Create( ) (string, error) { var privateKey *secp256k1.PrivateKey if len(seed) <= 0 { - privKey, err := utils.GenerateRandomPrivateKey() + prvkey, err := utils.GenerateRandomPrivateKey() if err != nil { return "", err } - privateKey = privKey + privateKey = prvkey } else { - privKeyBytes, err := hex.DecodeString(seed) + prvkeyBytes, err := hex.DecodeString(seed) if err != nil { return "", err } - privateKey = secp256k1.PrivKeyFromBytes(privKeyBytes) + privateKey = secp256k1.PrivKeyFromBytes(prvkeyBytes) } pwd := []byte(password) @@ -55,7 +55,7 @@ func (w *singlekeyWallet) Create( walletData := walletstore.WalletData{ EncryptedPrvkey: encryptedPrivateKey, PasswordHash: passwordHash, - Pubkey: pubkey, + PubKey: pubkey, } if err := w.walletStore.AddWallet(walletData); err != nil { return "", err diff --git a/pkg/client-sdk/wallet/wallet_test.go b/pkg/client-sdk/wallet/wallet_test.go index beb40e8..2bd6edc 100644 --- a/pkg/client-sdk/wallet/wallet_test.go +++ b/pkg/client-sdk/wallet/wallet_test.go @@ -21,8 +21,8 @@ func TestWallet(t *testing.T) { key, _ := btcec.NewPrivateKey() password := "password" testStoreData := sdktypes.Config{ - AspUrl: "localhost:7070", - AspPubkey: key.PubKey(), + ServerUrl: "localhost:7070", + ServerPubKey: key.PubKey(), WalletType: wallet.SingleKeyWallet, ClientType: client.GrpcClient, Network: common.LiquidRegTest, diff --git a/pkg/client-sdk/wasm/browser/config_store.go b/pkg/client-sdk/wasm/browser/config_store.go index 83e293c..e3b23d0 100644 --- a/pkg/client-sdk/wasm/browser/config_store.go +++ b/pkg/client-sdk/wasm/browser/config_store.go @@ -21,8 +21,8 @@ const ( ) type storeData struct { - AspUrl string `json:"asp_url"` - AspPubkey string `json:"asp_pubkey"` + ServerUrl string `json:"server_url"` + ServerPubKey string `json:"server_pubkey"` WalletType string `json:"wallet_type"` ClientType string `json:"client_type"` ExplorerURL string `json:"explorer_url"` @@ -54,8 +54,8 @@ func (s *configStore) GetDatadir() string { func (s *configStore) AddData(ctx context.Context, data types.Config) error { sd := &storeData{ - AspUrl: data.AspUrl, - AspPubkey: hex.EncodeToString(data.AspPubkey.SerializeCompressed()), + ServerUrl: data.ServerUrl, + ServerPubKey: hex.EncodeToString(data.ServerPubKey.SerializeCompressed()), WalletType: data.WalletType, ClientType: data.ClientType, Network: data.Network.Name, @@ -71,7 +71,7 @@ func (s *configStore) AddData(ctx context.Context, data types.Config) error { } func (s *configStore) GetData(ctx context.Context) (*types.Config, error) { - key := s.store.Call("getItem", "asp_pubkey") + key := s.store.Call("getItem", "server_pubkey") if key.IsNull() || key.IsUndefined() { return nil, nil } @@ -83,7 +83,7 @@ func (s *configStore) GetData(ctx context.Context) (*types.Config, error) { return nil, nil } - aspPubkey, err := secp256k1.ParsePubKey(buf) + serverPubkey, err := secp256k1.ParsePubKey(buf) if err != nil { return nil, err } @@ -95,8 +95,8 @@ func (s *configStore) GetData(ctx context.Context) (*types.Config, error) { withTxFeed, _ := strconv.ParseBool(s.store.Call("getItem", "with_transaction_feed").String()) return &types.Config{ - AspUrl: s.store.Call("getItem", "asp_url").String(), - AspPubkey: aspPubkey, + ServerUrl: s.store.Call("getItem", "server_url").String(), + ServerPubKey: serverPubkey, WalletType: s.store.Call("getItem", "wallet_type").String(), ClientType: s.store.Call("getItem", "client_type").String(), Network: network, diff --git a/pkg/client-sdk/wasm/browser/exports.go b/pkg/client-sdk/wasm/browser/exports.go index 861a308..286149c 100644 --- a/pkg/client-sdk/wasm/browser/exports.go +++ b/pkg/client-sdk/wasm/browser/exports.go @@ -30,7 +30,6 @@ func init() { js.Global().Set("receive", ReceiveWrapper()) js.Global().Set("sendOnChain", SendOnChainWrapper()) js.Global().Set("sendOffChain", SendOffChainWrapper()) - js.Global().Set("sendAsync", SendAsyncWrapper()) js.Global().Set("settle", SettleWrapper()) js.Global().Set("unilateralRedeem", UnilateralRedeemWrapper()) js.Global().Set("collaborativeRedeem", CollaborativeRedeemWrapper()) @@ -41,8 +40,8 @@ func init() { js.Global().Set("setNostrNotificationRecipient", SetNostrNotificationRecipientWrapper()) js.Global().Set("listVtxos", ListVtxosWrapper()) - js.Global().Set("getAspUrl", GetAspUrlWrapper()) - js.Global().Set("getAspPubKeyHex", GetAspPubkeyWrapper()) + js.Global().Set("getServerUrl", GetServerUrlWrapper()) + js.Global().Set("getServerPubkeyHex", GetServerPubkeyWrapper()) js.Global().Set("getWalletType", GetWalletTypeWrapper()) js.Global().Set("getClientType", GetClientTypeWrapper()) js.Global().Set("getNetwork", GetNetworkWrapper()) diff --git a/pkg/client-sdk/wasm/browser/wallet_store.go b/pkg/client-sdk/wasm/browser/wallet_store.go index 795951b..ff8cfee 100644 --- a/pkg/client-sdk/wasm/browser/wallet_store.go +++ b/pkg/client-sdk/wasm/browser/wallet_store.go @@ -16,18 +16,18 @@ import ( type walletData struct { EncryptedPrvkey string `json:"encrypted_private_key"` PasswordHash string `json:"password_hash"` - Pubkey string `json:"pubkey"` + PubKey string `json:"pubkey"` } func (d walletData) decode() *walletstore.WalletData { encryptedPrvkey, _ := hex.DecodeString(d.EncryptedPrvkey) passwordHash, _ := hex.DecodeString(d.PasswordHash) - buf, _ := hex.DecodeString(d.Pubkey) + buf, _ := hex.DecodeString(d.PubKey) pubkey, _ := secp256k1.ParsePubKey(buf) return &walletstore.WalletData{ EncryptedPrvkey: encryptedPrvkey, PasswordHash: passwordHash, - Pubkey: pubkey, + PubKey: pubkey, } } @@ -44,7 +44,7 @@ func (s *walletStore) AddWallet(data walletstore.WalletData) error { wd := &walletData{ EncryptedPrvkey: hex.EncodeToString(data.EncryptedPrvkey), PasswordHash: hex.EncodeToString(data.PasswordHash), - Pubkey: hex.EncodeToString(data.Pubkey.SerializeCompressed()), + PubKey: hex.EncodeToString(data.PubKey.SerializeCompressed()), } if err := s.writeData(wd); err != nil { @@ -57,7 +57,7 @@ func (s *walletStore) GetWallet() (*walletstore.WalletData, error) { data := walletData{ EncryptedPrvkey: s.store.Call("getItem", "encrypted_private_key").String(), PasswordHash: s.store.Call("getItem", "password_hash").String(), - Pubkey: s.store.Call("getItem", "pubkey").String(), + PubKey: s.store.Call("getItem", "pubkey").String(), } return data.decode(), nil } diff --git a/pkg/client-sdk/wasm/browser/wrappers.go b/pkg/client-sdk/wasm/browser/wrappers.go index be3eb0a..0625741 100644 --- a/pkg/client-sdk/wasm/browser/wrappers.go +++ b/pkg/client-sdk/wasm/browser/wrappers.go @@ -72,7 +72,7 @@ func InitWrapper() js.Func { err := arkSdkClient.InitWithWallet(context.Background(), arksdk.InitWithWalletArgs{ ClientType: args[1].String(), Wallet: walletSvc, - AspUrl: args[2].String(), + ServerUrl: args[2].String(), Seed: args[3].String(), Password: args[4].String(), ExplorerURL: args[6].String(), @@ -227,28 +227,6 @@ func SendOnChainWrapper() js.Func { } func SendOffChainWrapper() js.Func { - return JSPromise(func(args []js.Value) (interface{}, error) { - if len(args) != 2 { - return nil, errors.New("invalid number of args") - } - - withExpiryCoinselect := args[0].Bool() - receivers, err := parseReceivers(args[0]) - if err != nil { - return nil, err - } - - txID, err := arkSdkClient.SendOffChain( - context.Background(), withExpiryCoinselect, receivers, - ) - if err != nil { - return nil, err - } - return js.ValueOf(txID), nil - }) -} - -func SendAsyncWrapper() js.Func { return JSPromise(func(args []js.Value) (interface{}, error) { if len(args) != 2 { return nil, errors.New("invalid number of args") @@ -260,11 +238,7 @@ func SendAsyncWrapper() js.Func { return nil, err } - if receivers == nil || len(receivers) == 0 { - return nil, errors.New("no receivers specified") - } - - txID, err := arkSdkClient.SendAsync( + txID, err := arkSdkClient.SendOffChain( context.Background(), withExpiryCoinselect, receivers, ) if err != nil { @@ -340,25 +314,25 @@ func GetTransactionHistoryWrapper() js.Func { }) } -func GetAspUrlWrapper() js.Func { +func GetServerUrlWrapper() js.Func { return js.FuncOf(func(this js.Value, p []js.Value) interface{} { data, _ := arkSdkClient.GetConfigData(context.Background()) var url string if data != nil { - url = data.AspUrl + url = data.ServerUrl } return js.ValueOf(url) }) } -func GetAspPubkeyWrapper() js.Func { +func GetServerPubkeyWrapper() js.Func { return js.FuncOf(func(this js.Value, p []js.Value) interface{} { data, _ := arkSdkClient.GetConfigData(context.Background()) - var aspPubkey string + var serverPubkey string if data != nil { - aspPubkey = hex.EncodeToString(data.AspPubkey.SerializeCompressed()) + serverPubkey = hex.EncodeToString(data.ServerPubKey.SerializeCompressed()) } - return js.ValueOf(aspPubkey) + return js.ValueOf(serverPubkey) }) } diff --git a/server/README.md b/server/README.md index f903c3b..56bf8f1 100755 --- a/server/README.md +++ b/server/README.md @@ -1,5 +1,5 @@ # Ark Server -The Ark Server is a Go implementation of an Ark Service Provider (ASP). An ASP it's an always-on server that provides bitcoin liquidity in the Ark layer-two protocol. It supports Bitcoin and Liquid (with more experimantal features using covenants). +This is a Go implementation of the Ark server. An Ark server it's an always-on server that provides bitcoin liquidity in the Ark layer-two protocol. It supports Bitcoin and Liquid (with more experimantal features using covenants). **ALPHA STAGE SOFTWARE: USE AT YOUR OWN RISK!** diff --git a/server/internal/core/application/admin.go b/server/internal/core/application/admin.go index 506e74b..a22445f 100644 --- a/server/internal/core/application/admin.go +++ b/server/internal/core/application/admin.go @@ -89,11 +89,11 @@ func (a *adminService) GetRoundDetails(ctx context.Context, roundId string) (*Ro OutputsVtxos: []string{}, } - for _, payment := range round.Payments { + for _, request := range round.TxRequests { // TODO: Add fees amount - roundDetails.ForfeitedAmount += payment.TotalInputAmount() + roundDetails.ForfeitedAmount += request.TotalInputAmount() - for _, receiver := range payment.Receivers { + for _, receiver := range request.Receivers { if receiver.IsOnchain() { roundDetails.TotalExitAmount += receiver.Amount roundDetails.ExitAddresses = append(roundDetails.ExitAddresses, receiver.OnchainAddress) @@ -103,7 +103,7 @@ func (a *adminService) GetRoundDetails(ctx context.Context, roundId string) (*Ro roundDetails.TotalVtxosAmount += receiver.Amount } - for _, input := range payment.Inputs { + for _, input := range request.Inputs { roundDetails.InputsVtxos = append(roundDetails.InputsVtxos, input.Txid) } } @@ -134,7 +134,7 @@ func (a *adminService) GetScheduledSweeps(ctx context.Context) ([]ScheduledSweep for _, round := range sweepableRounds { sweepable, err := findSweepableOutputs( - ctx, a.walletSvc, a.txBuilder, a.sweeperTimeUnit, round.CongestionTree, + ctx, a.walletSvc, a.txBuilder, a.sweeperTimeUnit, round.VtxoTree, ) if err != nil { return nil, err diff --git a/server/internal/core/application/covenant.go b/server/internal/core/application/covenant.go index 452a7de..38a1d2d 100644 --- a/server/internal/core/application/covenant.go +++ b/server/internal/core/application/covenant.go @@ -44,8 +44,8 @@ type covenantService struct { scanner ports.BlockchainScanner sweeper *sweeper - paymentRequests *paymentsMap - forfeitTxs *forfeitTxsMap + txRequests *txRequestsQueue + forfeitTxs *forfeitTxsMap eventsCh chan domain.RoundEvent transactionEventsCh chan TransactionEvent @@ -94,7 +94,7 @@ func NewCovenantService( builder: builder, scanner: scanner, sweeper: newSweeper(walletSvc, repoManager, builder, scheduler, notificationPrefix), - paymentRequests: newPaymentsMap(), + txRequests: newTxRequestsQueue(), forfeitTxs: newForfeitTxsMap(builder), eventsCh: make(chan domain.RoundEvent), transactionEventsCh: make(chan TransactionEvent), @@ -287,14 +287,14 @@ func (s *covenantService) SpendVtxos(ctx context.Context, inputs []ports.Input) vtxosInputs = append(vtxosInputs, vtxo) } - payment, err := domain.NewPayment(vtxosInputs) + request, err := domain.NewTxRequest(vtxosInputs) if err != nil { return "", err } - if err := s.paymentRequests.push(*payment, boardingInputs); err != nil { + if err := s.txRequests.push(*request, boardingInputs); err != nil { return "", err } - return payment.Id, nil + return request.Id, nil } func (s *covenantService) newBoardingInput(tx *transaction.Transaction, input ports.Input) (*ports.BoardingInput, error) { @@ -344,7 +344,7 @@ func (s *covenantService) newBoardingInput(tx *transaction.Transaction, input po func (s *covenantService) ClaimVtxos(ctx context.Context, creds string, receivers []domain.Receiver) error { // Check credentials - payment, ok := s.paymentRequests.view(creds) + request, ok := s.txRequests.view(creds) if !ok { return fmt.Errorf("invalid credentials") } @@ -360,14 +360,14 @@ func (s *covenantService) ClaimVtxos(ctx context.Context, creds string, receiver } } - if err := payment.AddReceivers(receivers); err != nil { + if err := request.AddReceivers(receivers); err != nil { return err } - return s.paymentRequests.update(*payment) + return s.txRequests.update(*request) } -func (s *covenantService) UpdatePaymentStatus(_ context.Context, id string) error { - return s.paymentRequests.updatePingTimestamp(id) +func (s *covenantService) UpdateTxRequestStatus(_ context.Context, id string) error { + return s.txRequests.updatePingTimestamp(id) } func (s *covenantService) SubmitRedeemTx(context.Context, string) (string, error) { @@ -397,7 +397,7 @@ func (s *covenantService) ListVtxos(ctx context.Context, address string) ([]doma return nil, nil, fmt.Errorf("failed to decode address: %s", err) } - if !bytes.Equal(schnorr.SerializePubKey(decodedAddress.Asp), schnorr.SerializePubKey(s.pubkey)) { + if !bytes.Equal(schnorr.SerializePubKey(decodedAddress.Server), schnorr.SerializePubKey(s.pubkey)) { return nil, nil, fmt.Errorf("address does not match server pubkey") } @@ -414,8 +414,8 @@ func (s *covenantService) GetTransactionEventsChannel(ctx context.Context) <-cha return s.transactionEventsCh } -func (s *covenantService) GetRoundByTxid(ctx context.Context, poolTxid string) (*domain.Round, error) { - return s.repoManager.Rounds().GetRoundWithTxid(ctx, poolTxid) +func (s *covenantService) GetRoundByTxid(ctx context.Context, roundTxid string) (*domain.Round, error) { + return s.repoManager.Rounds().GetRoundWithTxid(ctx, roundTxid) } func (s *covenantService) GetCurrentRound(ctx context.Context) (*domain.Round, error) { @@ -472,11 +472,11 @@ func (s *covenantService) GetInfo(ctx context.Context) (*ServiceInfo, error) { }, nil } -func (s *covenantService) RegisterCosignerPubkey(ctx context.Context, paymentId string, _ string) error { +func (s *covenantService) RegisterCosignerPubkey(ctx context.Context, requestID 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") + // we should delete the associated tx request + if err := s.txRequests.delete(requestID); err != nil { + log.WithError(err).Warnf("failed to delete tx request %s", requestID) } return ErrTreeSigningNotRequired @@ -554,22 +554,22 @@ func (s *covenantService) startFinalization() { return } - // TODO: understand how many payments must be popped from the queue and actually registered for the round - num := s.paymentRequests.len() + // TODO: understand how many tx requests must be popped from the queue and actually registered for the round + num := s.txRequests.len() if num == 0 { roundAborted = true - err := fmt.Errorf("no payments registered") + err := fmt.Errorf("no tx requests registered") round.Fail(fmt.Errorf("round aborted: %s", err)) log.WithError(err).Debugf("round %s aborted", round.Id) return } - if num > paymentsThreshold { - num = paymentsThreshold + if num > txRequestsThreshold { + num = txRequestsThreshold } - payments, boardingInputs, _, _ := 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") + requests, boardingInputs, _, _ := s.txRequests.pop(num) + if _, err := round.RegisterTxRequests(requests); err != nil { + round.Fail(fmt.Errorf("failed to register tx requests: %s", err)) + log.WithError(err).Warn("failed to register tx requests") return } @@ -580,18 +580,18 @@ func (s *covenantService) startFinalization() { return } - unsignedPoolTx, tree, connectorAddress, connectors, err := s.builder.BuildRoundTx(s.pubkey, payments, boardingInputs, sweptRounds) + unsignedRoundTx, tree, connectorAddress, connectors, err := s.builder.BuildRoundTx(s.pubkey, requests, boardingInputs, sweptRounds) if err != nil { - round.Fail(fmt.Errorf("failed to create pool tx: %s", err)) - log.WithError(err).Warn("failed to create pool tx") + round.Fail(fmt.Errorf("failed to create round tx: %s", err)) + log.WithError(err).Warn("failed to create round tx") return } - log.Debugf("pool tx created for round %s", round.Id) + log.Debugf("round tx created for round %s", round.Id) - s.forfeitTxs.init(connectors, payments) + s.forfeitTxs.init(connectors, requests) if _, err := round.StartFinalization( - connectorAddress, connectors, tree, unsignedPoolTx, + connectorAddress, connectors, tree, unsignedRoundTx, ); err != nil { round.Fail(fmt.Errorf("failed to start finalization: %s", err)) log.WithError(err).Warn("failed to start finalization") @@ -670,8 +670,8 @@ func (s *covenantService) finalizeRound() { txid, err := s.wallet.BroadcastTransaction(ctx, signedRoundTx) if err != nil { log.Debugf("failed to broadcast round tx: %s", signedRoundTx) - changes = round.Fail(fmt.Errorf("failed to broadcast pool tx: %s", err)) - log.WithError(err).Warn("failed to broadcast pool tx") + changes = round.Fail(fmt.Errorf("failed to broadcast round tx: %s", err)) + log.WithError(err).Warn("failed to broadcast round tx") return } @@ -682,7 +682,7 @@ func (s *covenantService) finalizeRound() { return } - log.Debugf("finalized round %s with pool tx %s", round.Id, round.Txid) + log.Debugf("finalized round %s with round tx %s", round.Id, round.Txid) } func (s *covenantService) listenToScannerNotifications() { @@ -906,7 +906,7 @@ func (s *covenantService) updateVtxoSet(round *domain.Round) { ctx := context.Background() repo := s.repoManager.Vtxos() - spentVtxos := getSpentVtxos(round.Payments) + spentVtxos := getSpentVtxos(round.TxRequests) if len(spentVtxos) > 0 { for { if err := repo.SpendVtxos(ctx, spentVtxos, round.Txid); err != nil { @@ -970,8 +970,8 @@ func (s *covenantService) updateVtxoSet(round *domain.Round) { } } s.transactionEventsCh <- RoundTransactionEvent{ - RoundTxID: round.Txid, - SpentVtxos: getSpentVtxos(round.Payments), + RoundTxid: round.Txid, + SpentVtxos: getSpentVtxos(round.TxRequests), SpendableVtxos: s.getNewVtxos(round), ClaimedBoardingInputs: boardingInputs, } @@ -984,7 +984,7 @@ func (s *covenantService) propagateEvents(round *domain.Round) { case domain.RoundFinalizationStarted: ev := domain.RoundFinalizationStarted{ Id: e.Id, - CongestionTree: e.CongestionTree, + VtxoTree: e.VtxoTree, Connectors: e.Connectors, RoundTx: e.RoundTx, MinRelayFeeRate: int64(s.wallet.MinRelayFeeRate(context.Background())), @@ -1006,20 +1006,20 @@ func (s *covenantService) scheduleSweepVtxosForRound(round *domain.Round) { expirationTime := s.sweeper.scheduler.AddNow(s.roundLifetime) if err := s.sweeper.schedule( - expirationTime, round.Txid, round.CongestionTree, + expirationTime, round.Txid, round.VtxoTree, ); err != nil { log.WithError(err).Warn("failed to schedule sweep tx") } } func (s *covenantService) getNewVtxos(round *domain.Round) []domain.Vtxo { - if len(round.CongestionTree) <= 0 { + if len(round.VtxoTree) <= 0 { return nil } createdAt := time.Now().Unix() - leaves := round.CongestionTree.Leaves() + leaves := round.VtxoTree.Leaves() vtxos := make([]domain.Vtxo, 0) for _, node := range leaves { tx, _ := psetv2.NewPsetFromBase64(node.Tx) @@ -1038,7 +1038,7 @@ func (s *covenantService) getNewVtxos(round *domain.Round) []domain.Vtxo { vtxos = append(vtxos, domain.Vtxo{ VtxoKey: domain.VtxoKey{Txid: node.Txid, VOut: uint32(i)}, - Pubkey: vtxoPubkey, + PubKey: vtxoPubkey, Amount: uint64(out.Value), RoundTxid: round.Txid, CreatedAt: createdAt, @@ -1113,7 +1113,7 @@ func (s *covenantService) restoreWatchingVtxos() error { func (s *covenantService) extractVtxosScripts(vtxos []domain.Vtxo) ([]string, error) { indexedScripts := make(map[string]struct{}) for _, vtxo := range vtxos { - vtxoTapKeyBytes, err := hex.DecodeString(vtxo.Pubkey) + vtxoTapKeyBytes, err := hex.DecodeString(vtxo.PubKey) if err != nil { return nil, err } diff --git a/server/internal/core/application/covenantless.go b/server/internal/core/application/covenantless.go index d5488d5..6c35cde 100644 --- a/server/internal/core/application/covenantless.go +++ b/server/internal/core/application/covenantless.go @@ -46,8 +46,8 @@ type covenantlessService struct { scanner ports.BlockchainScanner sweeper *sweeper - paymentRequests *paymentsMap - forfeitTxs *forfeitTxsMap + txRequests *txRequestsQueue + forfeitTxs *forfeitTxsMap eventsCh chan domain.RoundEvent transactionEventsCh chan TransactionEvent @@ -99,7 +99,7 @@ func NewCovenantlessService( builder: builder, scanner: scanner, sweeper: newSweeper(walletSvc, repoManager, builder, scheduler, noteUriPrefix), - paymentRequests: newPaymentsMap(), + txRequests: newTxRequestsQueue(), forfeitTxs: newForfeitTxsMap(builder), eventsCh: make(chan domain.RoundEvent), transactionEventsCh: make(chan TransactionEvent), @@ -260,37 +260,37 @@ func (s *covenantlessService) SubmitRedeemTx( } // verify that the user signs a forfeit closure - var userPubKey *secp256k1.PublicKey + var userPubkey *secp256k1.PublicKey - aspXOnlyPubKey := schnorr.SerializePubKey(s.pubkey) + serverXOnlyPubkey := schnorr.SerializePubKey(s.pubkey) for _, sig := range input.TaprootScriptSpendSig { - if !bytes.Equal(sig.XOnlyPubKey, aspXOnlyPubKey) { + if !bytes.Equal(sig.XOnlyPubKey, serverXOnlyPubkey) { parsed, err := schnorr.ParsePubKey(sig.XOnlyPubKey) if err != nil { return "", fmt.Errorf("failed to parse pubkey: %s", err) } - userPubKey = parsed + userPubkey = parsed break } } - if userPubKey == nil { + if userPubkey == nil { return "", fmt.Errorf("redeem transaction is not signed") } - vtxoPublicKeyBytes, err := hex.DecodeString(vtxo.Pubkey) + vtxoPubkeyBuf, err := hex.DecodeString(vtxo.PubKey) if err != nil { return "", fmt.Errorf("failed to decode vtxo pubkey: %s", err) } - vtxoTapKey, err := schnorr.ParsePubKey(vtxoPublicKeyBytes) + vtxoPubkey, err := schnorr.ParsePubKey(vtxoPubkeyBuf) if err != nil { return "", fmt.Errorf("failed to parse vtxo pubkey: %s", err) } // verify witness utxo - pkscript, err := common.P2TRScript(vtxoTapKey) + pkscript, err := common.P2TRScript(vtxoPubkey) if err != nil { return "", fmt.Errorf("failed to get pkscript: %s", err) } @@ -378,8 +378,15 @@ func (s *covenantlessService) SubmitRedeemTx( return "", fmt.Errorf("no valid vtxo found") } - newVtxos := make([]domain.Vtxo, 0, len(redeemPtx.UnsignedTx.TxOut)) + // sign the redeem tx + signedRedeemTx, err := s.wallet.SignTransactionTapscript(ctx, redeemTx, nil) + if err != nil { + return "", fmt.Errorf("failed to sign redeem tx: %s", err) + } + + // Create new vtxos, update spent vtxos state + newVtxos := make([]domain.Vtxo, 0, len(redeemPtx.UnsignedTx.TxOut)) for outIndex, out := range outputs { vtxoTapKey, err := schnorr.ParsePubKey(out.PkScript[2:]) if err != nil { @@ -393,24 +400,15 @@ func (s *covenantlessService) SubmitRedeemTx( Txid: redeemTxid, VOut: uint32(outIndex), }, - Pubkey: vtxoPubkey, + PubKey: vtxoPubkey, Amount: uint64(out.Value), ExpireAt: expiration, RoundTxid: roundTxid, - RedeemTx: redeemTx, + RedeemTx: signedRedeemTx, CreatedAt: time.Now().Unix(), }) } - // sign the redeem tx - - signedRedeemTx, err := s.wallet.SignTransactionTapscript(ctx, redeemTx, nil) - if err != nil { - return "", fmt.Errorf("failed to sign redeem tx: %s", err) - } - - // create new vtxos, update spent vtxos state - if err := s.repoManager.Vtxos().AddVtxos(ctx, newVtxos); err != nil { return "", fmt.Errorf("failed to add vtxos: %s", err) } @@ -429,7 +427,7 @@ func (s *covenantlessService) SubmitRedeemTx( go func() { s.transactionEventsCh <- RedeemTransactionEvent{ - AsyncTxID: redeemTxid, + RedeemTxid: redeemTxid, SpentVtxos: spentVtxoKeys, SpendableVtxos: newVtxos, } @@ -492,16 +490,16 @@ func (s *covenantlessService) SpendNotes(ctx context.Context, notes []note.Note) } } - payment, err := domain.NewPayment(make([]domain.Vtxo, 0)) + request, err := domain.NewTxRequest(make([]domain.Vtxo, 0)) if err != nil { - return "", fmt.Errorf("failed to create payment: %s", err) + return "", fmt.Errorf("failed to create tx request: %s", err) } - if err := s.paymentRequests.pushWithNotes(*payment, notes); err != nil { - return "", fmt.Errorf("failed to push payment: %s", err) + if err := s.txRequests.pushWithNotes(*request, notes); err != nil { + return "", fmt.Errorf("failed to push tx requests: %s", err) } - return payment.Id, nil + return request.Id, nil } func (s *covenantlessService) SpendVtxos(ctx context.Context, inputs []ports.Input) (string, error) { @@ -600,14 +598,14 @@ func (s *covenantlessService) SpendVtxos(ctx context.Context, inputs []ports.Inp vtxosInputs = append(vtxosInputs, vtxo) } - payment, err := domain.NewPayment(vtxosInputs) + request, err := domain.NewTxRequest(vtxosInputs) if err != nil { return "", err } - if err := s.paymentRequests.push(*payment, boardingInputs); err != nil { + if err := s.txRequests.push(*request, boardingInputs); err != nil { return "", err } - return payment.Id, nil + return request.Id, nil } func (s *covenantlessService) newBoardingInput(tx wire.MsgTx, input ports.Input) (*ports.BoardingInput, error) { @@ -627,12 +625,12 @@ func (s *covenantlessService) newBoardingInput(tx wire.MsgTx, input ports.Input) return nil, fmt.Errorf("failed to get taproot key: %s", err) } - expectedScriptPubKey, err := common.P2TRScript(tapKey) + expectedScriptPubkey, err := common.P2TRScript(tapKey) if err != nil { return nil, fmt.Errorf("failed to get script pubkey: %s", err) } - if !bytes.Equal(output.PkScript, expectedScriptPubKey) { + if !bytes.Equal(output.PkScript, expectedScriptPubkey) { return nil, fmt.Errorf("descriptor does not match script in transaction output") } @@ -648,7 +646,7 @@ func (s *covenantlessService) newBoardingInput(tx wire.MsgTx, input ports.Input) func (s *covenantlessService) ClaimVtxos(ctx context.Context, creds string, receivers []domain.Receiver) error { // Check credentials - payment, ok := s.paymentRequests.view(creds) + request, ok := s.txRequests.view(creds) if !ok { return fmt.Errorf("invalid credentials") } @@ -664,14 +662,14 @@ func (s *covenantlessService) ClaimVtxos(ctx context.Context, creds string, rece } } - if err := payment.AddReceivers(receivers); err != nil { + if err := request.AddReceivers(receivers); err != nil { return err } - return s.paymentRequests.update(*payment) + return s.txRequests.update(*request) } -func (s *covenantlessService) UpdatePaymentStatus(_ context.Context, id string) error { - return s.paymentRequests.updatePingTimestamp(id) +func (s *covenantlessService) UpdateTxRequestStatus(_ context.Context, id string) error { + return s.txRequests.updatePingTimestamp(id) } func (s *covenantlessService) SignVtxos(ctx context.Context, forfeitTxs []string) error { @@ -697,7 +695,7 @@ func (s *covenantlessService) ListVtxos(ctx context.Context, address string) ([] return nil, nil, fmt.Errorf("failed to decode address: %s", err) } - if !bytes.Equal(schnorr.SerializePubKey(decodedAddress.Asp), schnorr.SerializePubKey(s.pubkey)) { + if !bytes.Equal(schnorr.SerializePubKey(decodedAddress.Server), schnorr.SerializePubKey(s.pubkey)) { return nil, nil, fmt.Errorf("address does not match server pubkey") } @@ -818,18 +816,18 @@ func calcNextMarketHour(marketHourStartTime, marketHourEndTime time.Time, period } } -func (s *covenantlessService) RegisterCosignerPubkey(ctx context.Context, paymentId string, pubkey string) error { +func (s *covenantlessService) RegisterCosignerPubkey(ctx context.Context, requestID 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) + ephemeralPubkey, err := secp256k1.ParsePubKey(pubkeyBytes) if err != nil { return fmt.Errorf("failed to parse pubkey: %s", err) } - return s.paymentRequests.pushEphemeralKey(paymentId, ephemeralPublicKey) + return s.txRequests.pushEphemeralKey(requestID, ephemeralPubkey) } func (s *covenantlessService) RegisterCosignerNonces( @@ -853,7 +851,7 @@ func (s *covenantlessService) RegisterCosignerNonces( session.nonces[pubkey] = nonces - if len(session.nonces) == session.nbCosigners-1 { // exclude the ASP + if len(session.nonces) == session.nbCosigners-1 { // exclude the server go func() { session.nonceDoneC <- struct{}{} }() @@ -884,7 +882,7 @@ func (s *covenantlessService) RegisterCosignerSignatures( session.signatures[pubkey] = signatures - if len(session.signatures) == session.nbCosigners-1 { // exclude the ASP + if len(session.signatures) == session.nbCosigners-1 { // exclude the server go func() { session.sigDoneC <- struct{}{} }() @@ -992,31 +990,31 @@ func (s *covenantlessService) startFinalization() { return } - // TODO: understand how many payments must be popped from the queue and actually registered for the round - num := s.paymentRequests.len() + // TODO: understand how many tx requests must be popped from the queue and actually registered for the round + num := s.txRequests.len() if num == 0 { roundAborted = true - err := fmt.Errorf("no payments registered") + err := fmt.Errorf("no tx requests registered") round.Fail(fmt.Errorf("round aborted: %s", err)) log.WithError(err).Debugf("round %s aborted", round.Id) return } - if num > paymentsThreshold { - num = paymentsThreshold + if num > txRequestsThreshold { + num = txRequestsThreshold } - payments, boardingInputs, cosigners, paymentsNotes := s.paymentRequests.pop(num) - if len(payments) > len(cosigners) { - err := fmt.Errorf("missing ephemeral key for payments") + requests, boardingInputs, cosigners, redeeemedNotes := s.txRequests.pop(num) + if len(requests) > len(cosigners) { + err := fmt.Errorf("missing ephemeral key for tx requests") round.Fail(fmt.Errorf("round aborted: %s", err)) log.WithError(err).Debugf("round %s aborted", round.Id) return } - notes = paymentsNotes + notes = redeeemedNotes - 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") + if _, err := round.RegisterTxRequests(requests); err != nil { + round.Fail(fmt.Errorf("failed to register tx requests: %s", err)) + log.WithError(err).Warn("failed to register tx requests") return } @@ -1038,7 +1036,7 @@ func (s *covenantlessService) startFinalization() { unsignedRoundTx, vtxoTree, connectorAddress, connectors, err := s.builder.BuildRoundTx( s.pubkey, - payments, + requests, boardingInputs, sweptRounds, cosigners..., @@ -1050,10 +1048,10 @@ func (s *covenantlessService) startFinalization() { } log.Debugf("round tx created for round %s", round.Id) - s.forfeitTxs.init(connectors, payments) + s.forfeitTxs.init(connectors, requests) if len(vtxoTree) > 0 { - log.Debugf("signing congestion tree for round %s", round.Id) + log.Debugf("signing vtxo tree for round %s", round.Id) signingSession := newMusigSigningSession(len(cosigners)) s.treeSigningSessions[round.Id] = signingSession @@ -1094,11 +1092,11 @@ func (s *covenantlessService) startFinalization() { return } - aspSignerSession := bitcointree.NewTreeSignerSession( + serverSignerSession := bitcointree.NewTreeSignerSession( ephemeralKey, sharedOutputAmount, vtxoTree, root.CloneBytes(), ) - nonces, err := aspSignerSession.GetNonces() + nonces, err := serverSignerSession.GetNonces() if err != nil { round.Fail(fmt.Errorf("failed to get nonces: %s", err)) log.WithError(err).Warn("failed to get nonces") @@ -1142,33 +1140,33 @@ func (s *covenantlessService) startFinalization() { s.propagateRoundSigningNoncesGeneratedEvent(aggragatedNonces) - if err := aspSignerSession.SetKeys(cosigners); err != nil { + if err := serverSignerSession.SetKeys(cosigners); err != nil { round.Fail(fmt.Errorf("failed to set keys: %s", err)) log.WithError(err).Warn("failed to set keys") return } - if err := aspSignerSession.SetAggregatedNonces(aggragatedNonces); err != nil { + if err := serverSignerSession.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() + // sign the tree as server + serverTreeSigs, err := serverSignerSession.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 { + if err := coordinator.AddSig(ephemeralKey.PubKey(), serverTreeSigs); 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) + log.Debugf("tree signed by us for round %s", round.Id) signaturesTimer := time.NewTimer(thirdOfRemainingDuration) @@ -1199,7 +1197,7 @@ func (s *covenantlessService) startFinalization() { return } - log.Debugf("congestion tree signed for round %s", round.Id) + log.Debugf("vtxo tree signed for round %s", round.Id) vtxoTree = signedTree } @@ -1216,11 +1214,11 @@ func (s *covenantlessService) startFinalization() { } func (s *covenantlessService) propagateRoundSigningStartedEvent( - unsignedCongestionTree tree.CongestionTree, cosigners []*secp256k1.PublicKey, + unsignedVtxoTree tree.VtxoTree, cosigners []*secp256k1.PublicKey, ) { ev := RoundSigningStarted{ Id: s.currentRound.Id, - UnsignedVtxoTree: unsignedCongestionTree, + UnsignedVtxoTree: unsignedVtxoTree, Cosigners: cosigners, UnsignedRoundTx: s.currentRound.UnsignedTx, } @@ -1311,7 +1309,7 @@ func (s *covenantlessService) finalizeRound(notes []note.Note) { txid, err := s.wallet.BroadcastTransaction(ctx, signedRoundTx) if err != nil { - changes = round.Fail(fmt.Errorf("failed to broadcast pool tx: %s", err)) + changes = round.Fail(fmt.Errorf("failed to broadcast round tx: %s", err)) return } @@ -1331,14 +1329,14 @@ func (s *covenantlessService) finalizeRound(notes []note.Note) { go func() { s.transactionEventsCh <- RoundTransactionEvent{ - RoundTxID: round.Txid, - SpentVtxos: getSpentVtxos(round.Payments), + RoundTxid: round.Txid, + SpentVtxos: getSpentVtxos(round.TxRequests), SpendableVtxos: s.getNewVtxos(round), ClaimedBoardingInputs: boardingInputs, } }() - log.Debugf("finalized round %s with pool tx %s", round.Id, round.Txid) + log.Debugf("finalized round %s with round tx %s", round.Id, round.Txid) } func (s *covenantlessService) listenToScannerNotifications() { @@ -1491,7 +1489,7 @@ func (s *covenantlessService) updateVtxoSet(round *domain.Round) { ctx := context.Background() repo := s.repoManager.Vtxos() - spentVtxos := getSpentVtxos(round.Payments) + spentVtxos := getSpentVtxos(round.TxRequests) if len(spentVtxos) > 0 { for { if err := repo.SpendVtxos(ctx, spentVtxos, round.Txid); err != nil { @@ -1544,7 +1542,7 @@ func (s *covenantlessService) propagateEvents(round *domain.Round) { case domain.RoundFinalizationStarted: ev := domain.RoundFinalizationStarted{ Id: e.Id, - CongestionTree: e.CongestionTree, + VtxoTree: e.VtxoTree, Connectors: e.Connectors, RoundTx: e.RoundTx, MinRelayFeeRate: int64(s.wallet.MinRelayFeeRate(context.Background())), @@ -1565,19 +1563,19 @@ func (s *covenantlessService) scheduleSweepVtxosForRound(round *domain.Round) { expirationTimestamp := s.sweeper.scheduler.AddNow(s.roundLifetime) - if err := s.sweeper.schedule(expirationTimestamp, round.Txid, round.CongestionTree); err != nil { + if err := s.sweeper.schedule(expirationTimestamp, round.Txid, round.VtxoTree); err != nil { log.WithError(err).Warn("failed to schedule sweep tx") } } func (s *covenantlessService) getNewVtxos(round *domain.Round) []domain.Vtxo { - if len(round.CongestionTree) <= 0 { + if len(round.VtxoTree) <= 0 { return nil } createdAt := time.Now().Unix() - leaves := round.CongestionTree.Leaves() + leaves := round.VtxoTree.Leaves() vtxos := make([]domain.Vtxo, 0) for _, node := range leaves { tx, err := psbt.NewFromRawBytes(strings.NewReader(node.Tx), true) @@ -1593,10 +1591,9 @@ func (s *covenantlessService) getNewVtxos(round *domain.Round) []domain.Vtxo { } vtxoPubkey := hex.EncodeToString(schnorr.SerializePubKey(vtxoTapKey)) - vtxos = append(vtxos, domain.Vtxo{ VtxoKey: domain.VtxoKey{Txid: node.Txid, VOut: uint32(i)}, - Pubkey: vtxoPubkey, + PubKey: vtxoPubkey, Amount: uint64(out.Value), RoundTxid: round.Txid, CreatedAt: createdAt, @@ -1672,7 +1669,7 @@ func (s *covenantlessService) extractVtxosScripts(vtxos []domain.Vtxo) ([]string indexedScripts := make(map[string]struct{}) for _, vtxo := range vtxos { - vtxoTapKeyBytes, err := hex.DecodeString(vtxo.Pubkey) + vtxoTapKeyBytes, err := hex.DecodeString(vtxo.PubKey) if err != nil { return nil, err } @@ -1731,7 +1728,7 @@ func (s *covenantlessService) reactToFraud(ctx context.Context, vtxo domain.Vtxo if err != nil { vtxosRepo := s.repoManager.Vtxos() - // if the round is not found, the utxo may be spent by an async payment redeem tx + // If the round is not found, the utxo may be spent by an out of round tx vtxos, err := vtxosRepo.GetVtxos(ctx, []domain.VtxoKey{ {Txid: vtxo.SpentBy, VOut: 0}, }) @@ -1739,14 +1736,14 @@ func (s *covenantlessService) reactToFraud(ctx context.Context, vtxo domain.Vtxo return fmt.Errorf("failed to retrieve round: %s", err) } - asyncPayVtxo := vtxos[0] - if asyncPayVtxo.Redeemed { // redeem tx is already onchain + storedVtxo := vtxos[0] + if storedVtxo.Redeemed { // redeem tx is already onchain return nil } - log.Debugf("vtxo %s:%d has been spent by async payment", vtxo.Txid, vtxo.VOut) + log.Debugf("vtxo %s:%d has been spent by out of round transaction", vtxo.Txid, vtxo.VOut) - redeemTxHex, err := s.builder.FinalizeAndExtract(asyncPayVtxo.RedeemTx) + redeemTxHex, err := s.builder.FinalizeAndExtract(storedVtxo.RedeemTx) if err != nil { return fmt.Errorf("failed to finalize redeem tx: %s", err) } diff --git a/server/internal/core/application/covenantless_event.go b/server/internal/core/application/covenantless_event.go index 6514343..41cad10 100644 --- a/server/internal/core/application/covenantless_event.go +++ b/server/internal/core/application/covenantless_event.go @@ -1,6 +1,6 @@ /* * This package contains intermediary events that are used only by the covenantless version -* they let to sign the congestion tree using musig2 algorithm +* they let to sign the vtxo 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 @@ -17,7 +17,7 @@ import ( // 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 + UnsignedVtxoTree tree.VtxoTree Cosigners []*secp256k1.PublicKey UnsignedRoundTx string } diff --git a/server/internal/core/application/errors.go b/server/internal/core/application/errors.go index 269576b..48dd357 100644 --- a/server/internal/core/application/errors.go +++ b/server/internal/core/application/errors.go @@ -2,10 +2,10 @@ package application import "fmt" -type errPaymentNotFound struct { +type errTxRequestNotFound struct { id string } -func (e errPaymentNotFound) Error() string { - return fmt.Sprintf("payment %s not found", e.id) +func (e errTxRequestNotFound) Error() string { + return fmt.Sprintf("tx request %s not found", e.id) } diff --git a/server/internal/core/application/proof.go b/server/internal/core/application/proof.go index befc4af..98e25b6 100644 --- a/server/internal/core/application/proof.go +++ b/server/internal/core/application/proof.go @@ -33,7 +33,7 @@ func (p OwnershipProof) validate(vtxo domain.Vtxo) error { rootHash := p.ControlBlock.RootHash(p.Script) vtxoTapKey := txscript.ComputeTaprootOutputKey(bitcointree.UnspendableKey(), rootHash) - if hex.EncodeToString(schnorr.SerializePubKey(vtxoTapKey)) != vtxo.Pubkey { + if hex.EncodeToString(schnorr.SerializePubKey(vtxoTapKey)) != vtxo.PubKey { return fmt.Errorf("invalid control block") } diff --git a/server/internal/core/application/sweeper.go b/server/internal/core/application/sweeper.go index 30902d5..03d1419 100644 --- a/server/internal/core/application/sweeper.go +++ b/server/internal/core/application/sweeper.go @@ -17,7 +17,7 @@ import ( // sweeper is an unexported service running while the main application service is started // it is responsible for sweeping onchain shared outputs that expired // it also handles delaying the sweep events in case some parts of the tree are broadcasted -// when a round is finalized, the main application service schedules a sweep event on the newly created congestion tree +// when a round is finalized, the main application service schedules a sweep event on the newly created vtxo tree type sweeper struct { wallet ports.WalletService repoManager ports.RepoManager @@ -58,7 +58,7 @@ func (s *sweeper) start() error { } for _, round := range allRounds { - task := s.createTask(round.Txid, round.CongestionTree) + task := s.createTask(round.Txid, round.VtxoTree) task() } @@ -78,14 +78,14 @@ func (s *sweeper) removeTask(treeRootTxid string) { // schedule set up a task to be executed once at the given timestamp func (s *sweeper) schedule( - expirationTimestamp int64, roundTxid string, congestionTree tree.CongestionTree, + expirationTimestamp int64, roundTxid string, vtxoTree tree.VtxoTree, ) error { - if len(congestionTree) <= 0 { // skip - log.Debugf("skipping sweep scheduling (round tx %s), empty congestion tree", roundTxid) + if len(vtxoTree) <= 0 { // skip + log.Debugf("skipping sweep scheduling (round tx %s), empty vtxo tree", roundTxid) return nil } - root, err := congestionTree.Root() + root, err := vtxoTree.Root() if err != nil { return err } @@ -94,7 +94,7 @@ func (s *sweeper) schedule( return nil } - task := s.createTask(roundTxid, congestionTree) + task := s.createTask(roundTxid, vtxoTree) var fancyTime string if s.scheduler.Unit() == ports.UnixTime { @@ -112,7 +112,7 @@ func (s *sweeper) schedule( s.scheduledTasks[root.Txid] = struct{}{} s.locker.Unlock() - if err := s.updateVtxoExpirationTime(congestionTree, expirationTimestamp); err != nil { + if err := s.updateVtxoExpirationTime(vtxoTree, expirationTimestamp); err != nil { log.WithError(err).Error("error while updating vtxo expiration time") } @@ -120,14 +120,14 @@ func (s *sweeper) schedule( } // createTask returns a function passed as handler in the scheduler -// it tries to craft a sweep tx containing the onchain outputs of the given congestion tree +// it tries to craft a sweep tx containing the onchain outputs of the given vtxo tree // if some parts of the tree have been broadcasted in the meantine, it will schedule the next taskes for the remaining parts of the tree func (s *sweeper) createTask( - roundTxid string, congestionTree tree.CongestionTree, + roundTxid string, vtxoTree tree.VtxoTree, ) func() { return func() { ctx := context.Background() - root, err := congestionTree.Root() + root, err := vtxoTree.Root() if err != nil { log.WithError(err).Error("error while getting root node") return @@ -139,17 +139,17 @@ func (s *sweeper) createTask( sweepInputs := make([]ports.SweepInput, 0) vtxoKeys := make([]domain.VtxoKey, 0) // vtxos associated to the sweep inputs - // inspect the congestion tree to find onchain shared outputs - sharedOutputs, err := findSweepableOutputs(ctx, s.wallet, s.builder, s.scheduler.Unit(), congestionTree) + // inspect the vtxo tree to find onchain shared outputs + sharedOutputs, err := findSweepableOutputs(ctx, s.wallet, s.builder, s.scheduler.Unit(), vtxoTree) if err != nil { - log.WithError(err).Error("error while inspecting congestion tree") + log.WithError(err).Error("error while inspecting vtxo tree") return } for expiredAt, inputs := range sharedOutputs { // if the shared outputs are not expired, schedule a sweep task for it if s.scheduler.AfterNow(expiredAt) { - subtrees, err := computeSubTrees(congestionTree, inputs) + subtrees, err := computeSubTrees(vtxoTree, inputs) if err != nil { log.WithError(err).Error("error while computing subtrees") continue @@ -185,7 +185,7 @@ func (s *sweeper) createTask( } } else { // if it's not a vtxo, find all the vtxos leaves reachable from that input - vtxosLeaves, err := s.builder.FindLeaves(congestionTree, input.GetHash().String(), input.GetIndex()) + vtxosLeaves, err := s.builder.FindLeaves(vtxoTree, input.GetHash().String(), input.GetIndex()) if err != nil { log.WithError(err).Error("error while finding vtxos leaves") continue @@ -301,7 +301,7 @@ func (s *sweeper) createTask( } func (s *sweeper) updateVtxoExpirationTime( - tree tree.CongestionTree, + tree tree.VtxoTree, expirationTime int64, ) error { leaves := tree.Leaves() @@ -376,13 +376,13 @@ func (s *sweeper) createAndSendNotes(ctx context.Context, vtxosKeys []domain.Vtx } } -func computeSubTrees(congestionTree tree.CongestionTree, inputs []ports.SweepInput) ([]tree.CongestionTree, error) { - subTrees := make(map[string]tree.CongestionTree, 0) +func computeSubTrees(vtxoTree tree.VtxoTree, inputs []ports.SweepInput) ([]tree.VtxoTree, error) { + subTrees := make(map[string]tree.VtxoTree, 0) - // for each sweepable input, create a sub congestion tree + // for each sweepable input, create a sub vtxo tree // it allows to skip the part of the tree that has been broadcasted in the next task for _, input := range inputs { - subTree, err := computeSubTree(congestionTree, input.GetHash().String()) + subTree, err := computeSubTree(vtxoTree, input.GetHash().String()) if err != nil { log.WithError(err).Error("error while finding sub tree") continue @@ -398,7 +398,7 @@ func computeSubTrees(congestionTree tree.CongestionTree, inputs []ports.SweepInp } // filter out the sub trees, remove the ones that are included in others - filteredSubTrees := make([]tree.CongestionTree, 0) + filteredSubTrees := make([]tree.VtxoTree, 0) for i, subTree := range subTrees { notIncludedInOtherTrees := true @@ -426,19 +426,19 @@ func computeSubTrees(congestionTree tree.CongestionTree, inputs []ports.SweepInp return filteredSubTrees, nil } -func computeSubTree(congestionTree tree.CongestionTree, newRoot string) (tree.CongestionTree, error) { - for _, level := range congestionTree { +func computeSubTree(vtxoTree tree.VtxoTree, newRoot string) (tree.VtxoTree, error) { + for _, level := range vtxoTree { for _, node := range level { if node.Txid == newRoot || node.ParentTxid == newRoot { - newTree := make(tree.CongestionTree, 0) + newTree := make(tree.VtxoTree, 0) newTree = append(newTree, []tree.Node{node}) - children := congestionTree.Children(node.Txid) + children := vtxoTree.Children(node.Txid) for len(children) > 0 { newTree = append(newTree, children) newChildren := make([]tree.Node, 0) for _, child := range children { - newChildren = append(newChildren, congestionTree.Children(child.Txid)...) + newChildren = append(newChildren, vtxoTree.Children(child.Txid)...) } children = newChildren } @@ -451,7 +451,7 @@ func computeSubTree(congestionTree tree.CongestionTree, newRoot string) (tree.Co return nil, fmt.Errorf("failed to create subtree, new root not found") } -func containsTree(tr0 tree.CongestionTree, tr1 tree.CongestionTree) (bool, error) { +func containsTree(tr0 tree.VtxoTree, tr1 tree.VtxoTree) (bool, error) { tr1Root, err := tr1.Root() if err != nil { return false, err @@ -468,7 +468,7 @@ func containsTree(tr0 tree.CongestionTree, tr1 tree.CongestionTree) (bool, error return false, nil } -// assuming the pset is a leaf in the congestion tree, returns the vtxo outpoint +// assuming the pset is a leaf in the vtxo tree, returns the vtxo outpoint func extractVtxoOutpoint(leaf tree.Node) (*domain.VtxoKey, error) { if !leaf.Leaf { return nil, fmt.Errorf("node is not a leaf") diff --git a/server/internal/core/application/types.go b/server/internal/core/application/types.go index c8d7b0a..37ffcbd 100644 --- a/server/internal/core/application/types.go +++ b/server/internal/core/application/types.go @@ -11,7 +11,7 @@ import ( ) var ( - paymentsThreshold = int64(128) + txRequestsThreshold = int64(128) ) type Service interface { @@ -22,11 +22,11 @@ type Service interface { ClaimVtxos(ctx context.Context, creds string, receivers []domain.Receiver) error SignVtxos(ctx context.Context, forfeitTxs []string) error SignRoundTx(ctx context.Context, roundTx string) error - GetRoundByTxid(ctx context.Context, poolTxid string) (*domain.Round, error) + GetRoundByTxid(ctx context.Context, roundTxid string) (*domain.Round, error) GetRoundById(ctx context.Context, id string) (*domain.Round, error) GetCurrentRound(ctx context.Context) (*domain.Round, error) GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent - UpdatePaymentStatus(ctx context.Context, paymentId string) error + UpdateTxRequestStatus(ctx context.Context, requestID string) error ListVtxos( ctx context.Context, address string, ) (spendableVtxos, spentVtxos []domain.Vtxo, err error) @@ -36,7 +36,7 @@ type Service interface { ctx context.Context, userPubkey *secp256k1.PublicKey, ) (address string, scripts []string, err error) // Tree signing methods - RegisterCosignerPubkey(ctx context.Context, paymentId string, ephemeralPublicKey string) error + RegisterCosignerPubkey(ctx context.Context, requestID string, ephemeralPubkey string) error RegisterCosignerNonces( ctx context.Context, roundID string, pubkey *secp256k1.PublicKey, nonces string, @@ -106,7 +106,7 @@ type TransactionEvent interface { } type RoundTransactionEvent struct { - RoundTxID string + RoundTxid string SpentVtxos []domain.VtxoKey SpendableVtxos []domain.Vtxo ClaimedBoardingInputs []domain.VtxoKey @@ -117,7 +117,7 @@ func (r RoundTransactionEvent) Type() TransactionEventType { } type RedeemTransactionEvent struct { - AsyncTxID string + RedeemTxid string SpentVtxos []domain.VtxoKey SpendableVtxos []domain.Vtxo } diff --git a/server/internal/core/application/utils.go b/server/internal/core/application/utils.go index 78f16b7..8d58295 100644 --- a/server/internal/core/application/utils.go +++ b/server/internal/core/application/utils.go @@ -16,32 +16,32 @@ import ( "github.com/nbd-wtf/go-nostr/nip19" ) -type timedPayment struct { - domain.Payment +type timedTxRequest struct { + domain.TxRequest boardingInputs []ports.BoardingInput notes []note.Note timestamp time.Time pingTimestamp time.Time } -type paymentsMap struct { +type txRequestsQueue struct { lock *sync.RWMutex - payments map[string]*timedPayment + requests map[string]*timedTxRequest ephemeralKeys map[string]*secp256k1.PublicKey } -func newPaymentsMap() *paymentsMap { - paymentsById := make(map[string]*timedPayment) +func newTxRequestsQueue() *txRequestsQueue { + requestsById := make(map[string]*timedTxRequest) lock := &sync.RWMutex{} - return &paymentsMap{lock, paymentsById, make(map[string]*secp256k1.PublicKey)} + return &txRequestsQueue{lock, requestsById, make(map[string]*secp256k1.PublicKey)} } -func (m *paymentsMap) len() int64 { +func (m *txRequestsQueue) len() int64 { m.lock.RLock() defer m.lock.RUnlock() count := int64(0) - for _, p := range m.payments { + for _, p := range m.requests { if len(p.Receivers) > 0 { count++ } @@ -49,154 +49,154 @@ func (m *paymentsMap) len() int64 { return count } -func (m *paymentsMap) delete(id string) error { +func (m *txRequestsQueue) delete(id string) error { m.lock.Lock() defer m.lock.Unlock() - if _, ok := m.payments[id]; !ok { - return errPaymentNotFound{id} + if _, ok := m.requests[id]; !ok { + return errTxRequestNotFound{id} } - delete(m.payments, id) + delete(m.requests, id) return nil } -func (m *paymentsMap) pushWithNotes(payment domain.Payment, notes []note.Note) error { +func (m *txRequestsQueue) pushWithNotes(request domain.TxRequest, notes []note.Note) error { m.lock.Lock() defer m.lock.Unlock() - if _, ok := m.payments[payment.Id]; ok { - return fmt.Errorf("duplicated payment %s", payment.Id) + if _, ok := m.requests[request.Id]; ok { + return fmt.Errorf("duplicated tx request %s", request.Id) } for _, note := range notes { - for _, payment := range m.payments { - for _, pNote := range payment.notes { - if note.ID == pNote.ID { + for _, txRequest := range m.requests { + for _, rNote := range txRequest.notes { + if note.ID == rNote.ID { return fmt.Errorf("duplicated note %s", note) } } } } - m.payments[payment.Id] = &timedPayment{payment, make([]ports.BoardingInput, 0), notes, time.Now(), time.Time{}} + m.requests[request.Id] = &timedTxRequest{request, make([]ports.BoardingInput, 0), notes, time.Now(), time.Time{}} return nil } -func (m *paymentsMap) push( - payment domain.Payment, +func (m *txRequestsQueue) push( + request domain.TxRequest, boardingInputs []ports.BoardingInput, ) error { m.lock.Lock() defer m.lock.Unlock() - if _, ok := m.payments[payment.Id]; ok { - return fmt.Errorf("duplicated payment %s", payment.Id) + if _, ok := m.requests[request.Id]; ok { + return fmt.Errorf("duplicated tx request %s", request.Id) } - for _, input := range payment.Inputs { - for _, pay := range m.payments { + for _, input := range request.Inputs { + for _, pay := range m.requests { for _, pInput := range pay.Inputs { if input.VtxoKey.Txid == pInput.VtxoKey.Txid && input.VtxoKey.VOut == pInput.VtxoKey.VOut { - return fmt.Errorf("duplicated input, %s:%d already used by payment %s", input.VtxoKey.Txid, input.VtxoKey.VOut, pay.Id) + return fmt.Errorf("duplicated input, %s:%d already used by tx request %s", input.VtxoKey.Txid, input.VtxoKey.VOut, pay.Id) } } } } for _, input := range boardingInputs { - for _, pay := range m.payments { - for _, pBoardingInput := range pay.boardingInputs { + for _, request := range m.requests { + for _, pBoardingInput := range request.boardingInputs { if input.Txid == pBoardingInput.Txid && input.VOut == pBoardingInput.VOut { - return fmt.Errorf("duplicated boarding input, %s:%d already used by payment %s", input.Txid, input.VOut, pay.Id) + return fmt.Errorf("duplicated boarding input, %s:%d already used by tx request %s", input.Txid, input.VOut, request.Id) } } } } - m.payments[payment.Id] = &timedPayment{payment, boardingInputs, make([]note.Note, 0), time.Now(), time.Time{}} + m.requests[request.Id] = &timedTxRequest{request, boardingInputs, make([]note.Note, 0), time.Now(), time.Time{}} return nil } -func (m *paymentsMap) pushEphemeralKey(paymentId string, pubkey *secp256k1.PublicKey) error { +func (m *txRequestsQueue) pushEphemeralKey(requestID 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) + if _, ok := m.requests[requestID]; !ok { + return fmt.Errorf("tx request %s not found, cannot register signing ephemeral public key", requestID) } - m.ephemeralKeys[paymentId] = pubkey + m.ephemeralKeys[requestID] = pubkey return nil } -func (m *paymentsMap) pop(num int64) ([]domain.Payment, []ports.BoardingInput, []*secp256k1.PublicKey, []note.Note) { +func (m *txRequestsQueue) pop(num int64) ([]domain.TxRequest, []ports.BoardingInput, []*secp256k1.PublicKey, []note.Note) { m.lock.Lock() defer m.lock.Unlock() - paymentsByTime := make([]timedPayment, 0, len(m.payments)) - for _, p := range m.payments { - // Skip payments without registered receivers. + requestsByTime := make([]timedTxRequest, 0, len(m.requests)) + for _, p := range m.requests { + // Skip tx requests without registered receivers. if len(p.Receivers) <= 0 { continue } - // Skip payments for which users didn't notify to be online in the last minute. + // Skip tx requests for which users didn't notify to be online in the last minute. if p.pingTimestamp.IsZero() || time.Since(p.pingTimestamp).Minutes() > 1 { continue } - paymentsByTime = append(paymentsByTime, *p) + requestsByTime = append(requestsByTime, *p) } - sort.SliceStable(paymentsByTime, func(i, j int) bool { - return paymentsByTime[i].timestamp.Before(paymentsByTime[j].timestamp) + sort.SliceStable(requestsByTime, func(i, j int) bool { + return requestsByTime[i].timestamp.Before(requestsByTime[j].timestamp) }) - if num < 0 || num > int64(len(paymentsByTime)) { - num = int64(len(paymentsByTime)) + if num < 0 || num > int64(len(requestsByTime)) { + num = int64(len(requestsByTime)) } - payments := make([]domain.Payment, 0, num) + requests := make([]domain.TxRequest, 0, num) boardingInputs := make([]ports.BoardingInput, 0) cosigners := make([]*secp256k1.PublicKey, 0, num) notes := make([]note.Note, 0) - for _, p := range paymentsByTime[:num] { + for _, p := range requestsByTime[:num] { boardingInputs = append(boardingInputs, p.boardingInputs...) - payments = append(payments, p.Payment) - if pubkey, ok := m.ephemeralKeys[p.Payment.Id]; ok { + requests = append(requests, p.TxRequest) + if pubkey, ok := m.ephemeralKeys[p.TxRequest.Id]; ok { cosigners = append(cosigners, pubkey) - delete(m.ephemeralKeys, p.Payment.Id) + delete(m.ephemeralKeys, p.TxRequest.Id) } notes = append(notes, p.notes...) - delete(m.payments, p.Id) + delete(m.requests, p.Id) } - return payments, boardingInputs, cosigners, notes + return requests, boardingInputs, cosigners, notes } -func (m *paymentsMap) update(payment domain.Payment) error { +func (m *txRequestsQueue) update(request domain.TxRequest) error { m.lock.Lock() defer m.lock.Unlock() - p, ok := m.payments[payment.Id] + r, ok := m.requests[request.Id] if !ok { - return fmt.Errorf("payment %s not found", payment.Id) + return fmt.Errorf("tx request %s not found", request.Id) } // sum inputs = vtxos + boarding utxos + notes sumOfInputs := uint64(0) - for _, input := range payment.Inputs { + for _, input := range request.Inputs { sumOfInputs += input.Amount } - for _, boardingInput := range p.boardingInputs { + for _, boardingInput := range r.boardingInputs { sumOfInputs += boardingInput.Amount } - for _, note := range p.notes { + for _, note := range r.notes { sumOfInputs += uint64(note.Value) } // sum outputs = receivers VTXOs sumOfOutputs := uint64(0) - for _, receiver := range payment.Receivers { + for _, receiver := range request.Receivers { sumOfOutputs += receiver.Amount } @@ -204,37 +204,37 @@ func (m *paymentsMap) update(payment domain.Payment) error { return fmt.Errorf("sum of inputs %d does not match sum of outputs %d", sumOfInputs, sumOfOutputs) } - p.Payment = payment + r.TxRequest = request return nil } -func (m *paymentsMap) updatePingTimestamp(id string) error { +func (m *txRequestsQueue) updatePingTimestamp(id string) error { m.lock.Lock() defer m.lock.Unlock() - payment, ok := m.payments[id] + request, ok := m.requests[id] if !ok { - return errPaymentNotFound{id} + return errTxRequestNotFound{id} } - payment.pingTimestamp = time.Now() + request.pingTimestamp = time.Now() return nil } -func (m *paymentsMap) view(id string) (*domain.Payment, bool) { +func (m *txRequestsQueue) view(id string) (*domain.TxRequest, bool) { m.lock.RLock() defer m.lock.RUnlock() - payment, ok := m.payments[id] + request, ok := m.requests[id] if !ok { return nil, false } - return &domain.Payment{ - Id: payment.Id, - Inputs: payment.Inputs, - Receivers: payment.Receivers, + return &domain.TxRequest{ + Id: request.Id, + Inputs: request.Inputs, + Receivers: request.Receivers, }, true } @@ -251,10 +251,10 @@ func newForfeitTxsMap(txBuilder ports.TxBuilder) *forfeitTxsMap { return &forfeitTxsMap{&sync.RWMutex{}, txBuilder, make(map[domain.VtxoKey][]string), nil, nil} } -func (m *forfeitTxsMap) init(connectors []string, payments []domain.Payment) { +func (m *forfeitTxsMap) init(connectors []string, requests []domain.TxRequest) { vtxosToSign := make([]domain.Vtxo, 0) - for _, payment := range payments { - vtxosToSign = append(vtxosToSign, payment.Inputs...) + for _, request := range requests { + vtxosToSign = append(vtxosToSign, request.Inputs...) } m.lock.Lock() @@ -318,18 +318,18 @@ func (m *forfeitTxsMap) pop() ([]string, error) { return txs, nil } -// onchainOutputs iterates over all the nodes' outputs in the congestion tree and checks their onchain state +// onchainOutputs iterates over all the nodes' outputs in the vtxo tree and checks their onchain state // returns the sweepable outputs as ports.SweepInput mapped by their expiration time func findSweepableOutputs( ctx context.Context, walletSvc ports.WalletService, txbuilder ports.TxBuilder, schedulerUnit ports.TimeUnit, - congestionTree tree.CongestionTree, + vtxoTree tree.VtxoTree, ) (map[int64][]ports.SweepInput, error) { sweepableOutputs := make(map[int64][]ports.SweepInput) blocktimeCache := make(map[string]int64) // txid -> blocktime / blockheight - nodesToCheck := congestionTree[0] // init with the root + nodesToCheck := vtxoTree[0] // init with the root for len(nodesToCheck) > 0 { newNodesToCheck := make([]tree.Node, 0) @@ -375,7 +375,7 @@ func findSweepableOutputs( // add the children to the nodes in order to check them during the next iteration // We will return the error below, but are we going to schedule the tasks for the "children roots"? if !node.Leaf { - children := congestionTree.Children(node.Txid) + children := vtxoTree.Children(node.Txid) newNodesToCheck = append(newNodesToCheck, children...) } continue @@ -393,10 +393,10 @@ func findSweepableOutputs( return sweepableOutputs, nil } -func getSpentVtxos(payments map[string]domain.Payment) []domain.VtxoKey { +func getSpentVtxos(requests map[string]domain.TxRequest) []domain.VtxoKey { vtxos := make([]domain.VtxoKey, 0) - for _, p := range payments { - for _, vtxo := range p.Inputs { + for _, request := range requests { + for _, vtxo := range request.Inputs { vtxos = append(vtxos, vtxo.VtxoKey) } } @@ -460,12 +460,12 @@ func nip19toNostrProfile(nostrRecipient string, defaultRelays []string) (string, nprofileRecipient = nostrRecipient case "npub": - recipientPublicKey, ok := result.(string) + recipientPubkey, ok := result.(string) if !ok { return "", fmt.Errorf("invalid NIP-19 result: %v", result) } - nprofileRecipient, err = nip19.EncodeProfile(recipientPublicKey, defaultRelays) + nprofileRecipient, err = nip19.EncodeProfile(recipientPubkey, defaultRelays) if err != nil { return "", fmt.Errorf("failed to encode nostr profile: %s", err) } diff --git a/server/internal/core/domain/events.go b/server/internal/core/domain/events.go index dc1b82a..583b8ac 100644 --- a/server/internal/core/domain/events.go +++ b/server/internal/core/domain/events.go @@ -10,7 +10,7 @@ func (r RoundStarted) IsEvent() {} func (r RoundFinalizationStarted) IsEvent() {} func (r RoundFinalized) IsEvent() {} func (r RoundFailed) IsEvent() {} -func (r PaymentsRegistered) IsEvent() {} +func (r TxRequestsRegistered) IsEvent() {} type RoundStarted struct { Id string @@ -19,7 +19,7 @@ type RoundStarted struct { type RoundFinalizationStarted struct { Id string - CongestionTree tree.CongestionTree // BTC: signed + VtxoTree tree.VtxoTree Connectors []string ConnectorAddress string RoundTx string @@ -39,7 +39,7 @@ type RoundFailed struct { Timestamp int64 } -type PaymentsRegistered struct { - Id string - Payments []Payment +type TxRequestsRegistered struct { + Id string + TxRequests []TxRequest } diff --git a/server/internal/core/domain/payment.go b/server/internal/core/domain/payment.go index 6ca241f..a694e22 100644 --- a/server/internal/core/domain/payment.go +++ b/server/internal/core/domain/payment.go @@ -11,66 +11,66 @@ import ( "github.com/google/uuid" ) -type Payment struct { +type TxRequest struct { Id string Inputs []Vtxo Receivers []Receiver } -func NewPayment(inputs []Vtxo) (*Payment, error) { - p := &Payment{ +func NewTxRequest(inputs []Vtxo) (*TxRequest, error) { + request := &TxRequest{ Id: uuid.New().String(), Inputs: inputs, } - if err := p.validate(true); err != nil { + if err := request.validate(true); err != nil { return nil, err } - return p, nil + return request, nil } -func (p *Payment) AddReceivers(receivers []Receiver) (err error) { - if p.Receivers == nil { - p.Receivers = make([]Receiver, 0) +func (r *TxRequest) AddReceivers(receivers []Receiver) (err error) { + if r.Receivers == nil { + r.Receivers = make([]Receiver, 0) } - p.Receivers = append(p.Receivers, receivers...) + r.Receivers = append(r.Receivers, receivers...) defer func() { if err != nil { - p.Receivers = p.Receivers[:len(p.Receivers)-len(receivers)] + r.Receivers = r.Receivers[:len(r.Receivers)-len(receivers)] } }() - err = p.validate(false) + err = r.validate(false) return } -func (p Payment) TotalInputAmount() uint64 { +func (r TxRequest) TotalInputAmount() uint64 { tot := uint64(0) - for _, in := range p.Inputs { + for _, in := range r.Inputs { tot += in.Amount } return tot } -func (p Payment) TotalOutputAmount() uint64 { +func (r TxRequest) TotalOutputAmount() uint64 { tot := uint64(0) - for _, r := range p.Receivers { + for _, r := range r.Receivers { tot += r.Amount } return tot } -func (p Payment) validate(ignoreOuts bool) error { - if len(p.Id) <= 0 { +func (r TxRequest) validate(ignoreOuts bool) error { + if len(r.Id) <= 0 { return fmt.Errorf("missing id") } if ignoreOuts { return nil } - if len(p.Receivers) <= 0 { + if len(r.Receivers) <= 0 { return fmt.Errorf("missing outputs") } - for _, r := range p.Receivers { - if len(r.OnchainAddress) <= 0 && len(r.Pubkey) <= 0 { + for _, r := range r.Receivers { + if len(r.OnchainAddress) <= 0 && len(r.PubKey) <= 0 { return fmt.Errorf("missing receiver destination") } if r.Amount == 0 { @@ -107,7 +107,7 @@ func (k VtxoKey) Hash() string { type Receiver struct { Amount uint64 OnchainAddress string // onchain - Pubkey string // offchain + PubKey string // offchain } func (r Receiver) IsOnchain() bool { @@ -117,9 +117,9 @@ func (r Receiver) IsOnchain() bool { type Vtxo struct { VtxoKey Amount uint64 - Pubkey string + PubKey string RoundTxid string - SpentBy string // round txid or async redeem txid + SpentBy string // round txid or redeem txid Spent bool Redeemed bool Swept bool @@ -129,7 +129,7 @@ type Vtxo struct { } func (v Vtxo) TapKey() (*secp256k1.PublicKey, error) { - pubkeyBytes, err := hex.DecodeString(v.Pubkey) + pubkeyBytes, err := hex.DecodeString(v.PubKey) if err != nil { return nil, err } diff --git a/server/internal/core/domain/payment_test.go b/server/internal/core/domain/payment_test.go index 1e4b8b5..3a56f05 100644 --- a/server/internal/core/domain/payment_test.go +++ b/server/internal/core/domain/payment_test.go @@ -16,36 +16,36 @@ var inputs = []domain.Vtxo{ Txid: "0000000000000000000000000000000000000000000000000000000000000000", VOut: 0, }, - Pubkey: pubkey, + PubKey: pubkey, Amount: 1000, }, } -func TestPayment(t *testing.T) { - t.Run("new_payment", func(t *testing.T) { +func TestTxRequest(t *testing.T) { + t.Run("new_tx_request", func(t *testing.T) { t.Run("valid", func(t *testing.T) { - payment, err := domain.NewPayment(inputs) + request, err := domain.NewTxRequest(inputs) require.NoError(t, err) - require.NotNil(t, payment) - require.NotEmpty(t, payment.Id) - require.Exactly(t, inputs, payment.Inputs) - require.Empty(t, payment.Receivers) + require.NotNil(t, request) + require.NotEmpty(t, request.Id) + require.Exactly(t, inputs, request.Inputs) + require.Empty(t, request.Receivers) }) }) t.Run("add_receivers", func(t *testing.T) { t.Run("valid", func(t *testing.T) { - payment, err := domain.NewPayment(inputs) + request, err := domain.NewTxRequest(inputs) require.NoError(t, err) - require.NotNil(t, payment) + require.NotNil(t, request) - err = payment.AddReceivers([]domain.Receiver{ + err = request.AddReceivers([]domain.Receiver{ { - Pubkey: pubkey, + PubKey: pubkey, Amount: 450, }, { - Pubkey: pubkey, + PubKey: pubkey, Amount: 550, }, }) @@ -63,12 +63,12 @@ func TestPayment(t *testing.T) { }, } - payment, err := domain.NewPayment(inputs) + request, err := domain.NewTxRequest(inputs) require.NoError(t, err) - require.NotNil(t, payment) + require.NotNil(t, request) for _, f := range fixtures { - err := payment.AddReceivers(f.receivers) + err := request.AddReceivers(f.receivers) require.EqualError(t, err, f.expectedErr) } }) diff --git a/server/internal/core/domain/round.go b/server/internal/core/domain/round.go index 7a42ac0..86639e2 100644 --- a/server/internal/core/domain/round.go +++ b/server/internal/core/domain/round.go @@ -38,11 +38,11 @@ type Round struct { StartingTimestamp int64 EndingTimestamp int64 Stage Stage - Payments map[string]Payment + TxRequests map[string]TxRequest Txid string UnsignedTx string ForfeitTxs []string - CongestionTree tree.CongestionTree + VtxoTree tree.VtxoTree Connectors []string ConnectorAddress string DustAmount uint64 @@ -55,7 +55,7 @@ func NewRound(dustAmount uint64) *Round { return &Round{ Id: uuid.New().String(), DustAmount: dustAmount, - Payments: make(map[string]Payment), + TxRequests: make(map[string]TxRequest), changes: make([]RoundEvent, 0), } } @@ -84,7 +84,7 @@ func (r *Round) On(event RoundEvent, replayed bool) { r.StartingTimestamp = e.Timestamp case RoundFinalizationStarted: r.Stage.Code = FinalizationStage - r.CongestionTree = e.CongestionTree + r.VtxoTree = e.VtxoTree r.Connectors = append([]string{}, e.Connectors...) r.ConnectorAddress = e.ConnectorAddress r.UnsignedTx = e.RoundTx @@ -96,12 +96,12 @@ func (r *Round) On(event RoundEvent, replayed bool) { case RoundFailed: r.Stage.Failed = true r.EndingTimestamp = e.Timestamp - case PaymentsRegistered: - if r.Payments == nil { - r.Payments = make(map[string]Payment) + case TxRequestsRegistered: + if r.TxRequests == nil { + r.TxRequests = make(map[string]TxRequest) } - for _, p := range e.Payments { - r.Payments[p.Id] = p + for _, p := range e.TxRequests { + r.TxRequests[p.Id] = p } } @@ -113,7 +113,7 @@ func (r *Round) On(event RoundEvent, replayed bool) { func (r *Round) StartRegistration() ([]RoundEvent, error) { empty := Stage{} if r.Stage != empty { - return nil, fmt.Errorf("not in a valid stage to start payment registration") + return nil, fmt.Errorf("not in a valid stage to start tx requests registration") } event := RoundStarted{ @@ -125,45 +125,45 @@ func (r *Round) StartRegistration() ([]RoundEvent, error) { return []RoundEvent{event}, nil } -func (r *Round) RegisterPayments(payments []Payment) ([]RoundEvent, error) { +func (r *Round) RegisterTxRequests(txRequests []TxRequest) ([]RoundEvent, error) { if r.Stage.Code != RegistrationStage || r.IsFailed() { - return nil, fmt.Errorf("not in a valid stage to register payments") + return nil, fmt.Errorf("not in a valid stage to register tx requests") } - if len(payments) <= 0 { - return nil, fmt.Errorf("missing payments to register") + if len(txRequests) <= 0 { + return nil, fmt.Errorf("missing tx requests to register") } - for _, p := range payments { - if err := p.validate(false); err != nil { + for _, request := range txRequests { + if err := request.validate(false); err != nil { return nil, err } } - event := PaymentsRegistered{ - Id: r.Id, - Payments: payments, + event := TxRequestsRegistered{ + Id: r.Id, + TxRequests: txRequests, } r.raise(event) return []RoundEvent{event}, nil } -func (r *Round) StartFinalization(connectorAddress string, connectors []string, congestionTree tree.CongestionTree, poolTx string) ([]RoundEvent, error) { - if len(poolTx) <= 0 { - return nil, fmt.Errorf("missing unsigned pool tx") +func (r *Round) StartFinalization(connectorAddress string, connectors []string, vtxoTree tree.VtxoTree, roundTx string) ([]RoundEvent, error) { + if len(roundTx) <= 0 { + return nil, fmt.Errorf("missing unsigned round tx") } if r.Stage.Code != RegistrationStage || r.IsFailed() { - return nil, fmt.Errorf("not in a valid stage to start payment finalization") + return nil, fmt.Errorf("not in a valid stage to start finalization") } - if len(r.Payments) <= 0 { - return nil, fmt.Errorf("no payments registered") + if len(r.TxRequests) <= 0 { + return nil, fmt.Errorf("no tx requests registered") } event := RoundFinalizationStarted{ Id: r.Id, - CongestionTree: congestionTree, + VtxoTree: vtxoTree, Connectors: connectors, ConnectorAddress: connectorAddress, - RoundTx: poolTx, + RoundTx: roundTx, } r.raise(event) @@ -172,17 +172,17 @@ func (r *Round) StartFinalization(connectorAddress string, connectors []string, func (r *Round) EndFinalization(forfeitTxs []string, txid string) ([]RoundEvent, error) { if len(forfeitTxs) <= 0 { - for _, p := range r.Payments { - if len(p.Inputs) > 0 { + for _, request := range r.TxRequests { + if len(request.Inputs) > 0 { return nil, fmt.Errorf("missing list of signed forfeit txs") } } } if len(txid) <= 0 { - return nil, fmt.Errorf("missing pool txid") + return nil, fmt.Errorf("missing round txid") } if r.Stage.Code != FinalizationStage || r.IsFailed() { - return nil, fmt.Errorf("not in a valid stage to end payment finalization") + return nil, fmt.Errorf("not in a valid stage to end finalization") } if r.Stage.Ended { return nil, fmt.Errorf("round already finalized") @@ -231,16 +231,16 @@ func (r *Round) IsFailed() bool { func (r *Round) TotalInputAmount() uint64 { totInputs := 0 - for _, p := range r.Payments { - totInputs += len(p.Inputs) + for _, request := range r.TxRequests { + totInputs += len(request.Inputs) } return uint64(totInputs * int(r.DustAmount)) } func (r *Round) TotalOutputAmount() uint64 { tot := uint64(0) - for _, p := range r.Payments { - tot += p.TotalOutputAmount() + for _, request := range r.TxRequests { + tot += request.TotalOutputAmount() } return tot } diff --git a/server/internal/core/domain/round_test.go b/server/internal/core/domain/round_test.go index 560e98b..7d68efd 100644 --- a/server/internal/core/domain/round_test.go +++ b/server/internal/core/domain/round_test.go @@ -11,7 +11,7 @@ import ( var ( dustAmount = uint64(450) - payments = []domain.Payment{ + requests = []domain.TxRequest{ { Id: "0", Inputs: []domain.Vtxo{ @@ -20,21 +20,21 @@ var ( Txid: txid, VOut: 0, }, - Pubkey: pubkey, + PubKey: pubkey, Amount: 2000, }, }, Receivers: []domain.Receiver{ { - Pubkey: pubkey, + PubKey: pubkey, Amount: 700, }, { - Pubkey: pubkey, + PubKey: pubkey, Amount: 700, }, { - Pubkey: pubkey, + PubKey: pubkey, Amount: 600, }, }, @@ -47,7 +47,7 @@ var ( Txid: txid, VOut: 0, }, - Pubkey: pubkey, + PubKey: pubkey, Amount: 1000, }, { @@ -55,20 +55,20 @@ var ( Txid: txid, VOut: 0, }, - Pubkey: pubkey, + PubKey: pubkey, Amount: 1000, }, }, Receivers: []domain.Receiver{{ - Pubkey: pubkey, + PubKey: pubkey, Amount: 2000, }}, }, } - emptyPtx = "cHNldP8BAgQCAAAAAQQBAAEFAQABBgEDAfsEAgAAAAA=" - emptyTx = "0200000000000000000000" - txid = "0000000000000000000000000000000000000000000000000000000000000000" - congestionTree = tree.CongestionTree{ + emptyPtx = "cHNldP8BAgQCAAAAAQQBAAEFAQABBgEDAfsEAgAAAAA=" + emptyTx = "0200000000000000000000" + txid = "0000000000000000000000000000000000000000000000000000000000000000" + vtxoTree = tree.VtxoTree{ { { Txid: txid, @@ -113,13 +113,13 @@ var ( } connectors = []string{emptyPtx, emptyPtx, emptyPtx} forfeitTxs = []string{emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx} - poolTx = emptyTx + roundTx = emptyTx ) func TestRound(t *testing.T) { testStartRegistration(t) - testRegisterPayments(t) + testRegisterTxRequests(t) testStartFinalization(t) @@ -165,7 +165,7 @@ func testStartRegistration(t *testing.T) { Failed: true, }, }, - expectedErr: "not in a valid stage to start payment registration", + expectedErr: "not in a valid stage to start tx requests registration", }, { round: &domain.Round{ @@ -174,7 +174,7 @@ func testStartRegistration(t *testing.T) { Code: domain.RegistrationStage, }, }, - expectedErr: "not in a valid stage to start payment registration", + expectedErr: "not in a valid stage to start tx requests registration", }, { round: &domain.Round{ @@ -183,7 +183,7 @@ func testStartRegistration(t *testing.T) { Code: domain.FinalizationStage, }, }, - expectedErr: "not in a valid stage to start payment registration", + expectedErr: "not in a valid stage to start tx requests registration", }, } @@ -196,20 +196,20 @@ func testStartRegistration(t *testing.T) { }) } -func testRegisterPayments(t *testing.T) { - t.Run("register_payments", func(t *testing.T) { +func testRegisterTxRequests(t *testing.T) { + t.Run("register_tx_requests", func(t *testing.T) { t.Run("valid", func(t *testing.T) { round := domain.NewRound(dustAmount) events, err := round.StartRegistration() require.NoError(t, err) require.NotEmpty(t, events) - events, err = round.RegisterPayments(payments) + events, err = round.RegisterTxRequests(requests) require.NoError(t, err) require.Len(t, events, 1) require.Condition(t, func() bool { - for _, payment := range payments { - _, ok := round.Payments[payment.Id] + for _, request := range requests { + _, ok := round.TxRequests[request.Id] if !ok { return false } @@ -217,16 +217,16 @@ func testRegisterPayments(t *testing.T) { return true }) - event, ok := events[0].(domain.PaymentsRegistered) + event, ok := events[0].(domain.TxRequestsRegistered) require.True(t, ok) require.Equal(t, round.Id, event.Id) - require.Equal(t, payments, event.Payments) + require.Equal(t, requests, event.TxRequests) }) t.Run("invalid", func(t *testing.T) { fixtures := []struct { round *domain.Round - payments []domain.Payment + requests []domain.TxRequest expectedErr string }{ { @@ -234,8 +234,8 @@ func testRegisterPayments(t *testing.T) { Id: "id", Stage: domain.Stage{}, }, - payments: payments, - expectedErr: "not in a valid stage to register payments", + requests: requests, + expectedErr: "not in a valid stage to register tx requests", }, { round: &domain.Round{ @@ -245,8 +245,8 @@ func testRegisterPayments(t *testing.T) { Failed: true, }, }, - payments: payments, - expectedErr: "not in a valid stage to register payments", + requests: requests, + expectedErr: "not in a valid stage to register tx requests", }, { round: &domain.Round{ @@ -255,8 +255,8 @@ func testRegisterPayments(t *testing.T) { Code: domain.FinalizationStage, }, }, - payments: payments, - expectedErr: "not in a valid stage to register payments", + requests: requests, + expectedErr: "not in a valid stage to register tx requests", }, { round: &domain.Round{ @@ -265,13 +265,13 @@ func testRegisterPayments(t *testing.T) { Code: domain.RegistrationStage, }, }, - payments: nil, - expectedErr: "missing payments to register", + requests: nil, + expectedErr: "missing tx requests to register", }, } for _, f := range fixtures { - events, err := f.round.RegisterPayments(f.payments) + events, err := f.round.RegisterTxRequests(f.requests) require.EqualError(t, err, f.expectedErr) require.Empty(t, events) } @@ -287,11 +287,11 @@ func testStartFinalization(t *testing.T) { require.NoError(t, err) require.NotEmpty(t, events) - events, err = round.RegisterPayments(payments) + events, err = round.RegisterTxRequests(requests) require.NoError(t, err) require.NotEmpty(t, events) - events, err = round.StartFinalization("", connectors, congestionTree, poolTx) + events, err = round.StartFinalization("", connectors, vtxoTree, roundTx) require.NoError(t, err) require.Len(t, events, 1) require.True(t, round.IsStarted()) @@ -302,20 +302,20 @@ func testStartFinalization(t *testing.T) { require.True(t, ok) require.Equal(t, round.Id, event.Id) require.Exactly(t, connectors, event.Connectors) - require.Exactly(t, congestionTree, event.CongestionTree) - require.Exactly(t, poolTx, event.RoundTx) + require.Exactly(t, vtxoTree, event.VtxoTree) + require.Exactly(t, roundTx, event.RoundTx) }) t.Run("invalid", func(t *testing.T) { - paymentsById := map[string]domain.Payment{} - for _, p := range payments { - paymentsById[p.Id] = p + requestsById := map[string]domain.TxRequest{} + for _, p := range requests { + requestsById[p.Id] = p } fixtures := []struct { round *domain.Round connectors []string - tree tree.CongestionTree - poolTx string + tree tree.VtxoTree + roundTx string expectedErr string }{ { @@ -324,12 +324,12 @@ func testStartFinalization(t *testing.T) { Stage: domain.Stage{ Code: domain.RegistrationStage, }, - Payments: paymentsById, + TxRequests: requestsById, }, connectors: connectors, - tree: congestionTree, - poolTx: "", - expectedErr: "missing unsigned pool tx", + tree: vtxoTree, + roundTx: "", + expectedErr: "missing unsigned round tx", }, { round: &domain.Round{ @@ -337,12 +337,12 @@ func testStartFinalization(t *testing.T) { Stage: domain.Stage{ Code: domain.RegistrationStage, }, - Payments: nil, + TxRequests: nil, }, connectors: connectors, - tree: congestionTree, - poolTx: poolTx, - expectedErr: "no payments registered", + tree: vtxoTree, + roundTx: roundTx, + expectedErr: "no tx requests registered", }, { round: &domain.Round{ @@ -350,12 +350,12 @@ func testStartFinalization(t *testing.T) { Stage: domain.Stage{ Code: domain.UndefinedStage, }, - Payments: paymentsById, + TxRequests: requestsById, }, connectors: connectors, - tree: congestionTree, - poolTx: poolTx, - expectedErr: "not in a valid stage to start payment finalization", + tree: vtxoTree, + roundTx: roundTx, + expectedErr: "not in a valid stage to start finalization", }, { round: &domain.Round{ @@ -364,12 +364,12 @@ func testStartFinalization(t *testing.T) { Code: domain.RegistrationStage, Failed: true, }, - Payments: paymentsById, + TxRequests: requestsById, }, connectors: connectors, - tree: congestionTree, - poolTx: poolTx, - expectedErr: "not in a valid stage to start payment finalization", + tree: vtxoTree, + roundTx: roundTx, + expectedErr: "not in a valid stage to start finalization", }, { round: &domain.Round{ @@ -377,18 +377,18 @@ func testStartFinalization(t *testing.T) { Stage: domain.Stage{ Code: domain.FinalizationStage, }, - Payments: paymentsById, + TxRequests: requestsById, }, connectors: connectors, - tree: congestionTree, - poolTx: poolTx, - expectedErr: "not in a valid stage to start payment finalization", + tree: vtxoTree, + roundTx: roundTx, + expectedErr: "not in a valid stage to start finalization", }, } for _, f := range fixtures { // TODO fix this - events, err := f.round.StartFinalization("", f.connectors, f.tree, f.poolTx) + events, err := f.round.StartFinalization("", f.connectors, f.tree, f.roundTx) require.EqualError(t, err, f.expectedErr) require.Empty(t, events) } @@ -404,11 +404,11 @@ func testEndFinalization(t *testing.T) { require.NoError(t, err) require.NotEmpty(t, events) - events, err = round.RegisterPayments(payments) + events, err = round.RegisterTxRequests(requests) require.NoError(t, err) require.NotEmpty(t, events) - events, err = round.StartFinalization("", connectors, congestionTree, poolTx) + events, err = round.StartFinalization("", connectors, vtxoTree, roundTx) require.NoError(t, err) require.NotEmpty(t, events) @@ -428,9 +428,9 @@ func testEndFinalization(t *testing.T) { }) t.Run("invalid", func(t *testing.T) { - paymentsById := map[string]domain.Payment{} - for _, p := range payments { - paymentsById[p.Id] = p + requestsById := map[string]domain.TxRequest{} + for _, p := range requests { + requestsById[p.Id] = p } fixtures := []struct { round *domain.Round @@ -444,7 +444,7 @@ func testEndFinalization(t *testing.T) { Stage: domain.Stage{ Code: domain.FinalizationStage, }, - Payments: paymentsById, + TxRequests: requestsById, }, forfeitTxs: nil, txid: txid, @@ -459,7 +459,7 @@ func testEndFinalization(t *testing.T) { }, forfeitTxs: forfeitTxs, txid: "", - expectedErr: "missing pool txid", + expectedErr: "missing round txid", }, { round: &domain.Round{ @@ -467,7 +467,7 @@ func testEndFinalization(t *testing.T) { }, forfeitTxs: forfeitTxs, txid: txid, - expectedErr: "not in a valid stage to end payment finalization", + expectedErr: "not in a valid stage to end finalization", }, { round: &domain.Round{ @@ -478,7 +478,7 @@ func testEndFinalization(t *testing.T) { }, forfeitTxs: forfeitTxs, txid: txid, - expectedErr: "not in a valid stage to end payment finalization", + expectedErr: "not in a valid stage to end finalization", }, { round: &domain.Round{ @@ -490,7 +490,7 @@ func testEndFinalization(t *testing.T) { }, forfeitTxs: []string{emptyPtx, emptyPtx, emptyPtx, emptyPtx}, txid: txid, - expectedErr: "not in a valid stage to end payment finalization", + expectedErr: "not in a valid stage to end finalization", }, { round: &domain.Round{ @@ -523,7 +523,7 @@ func testFail(t *testing.T) { require.NoError(t, err) require.NotEmpty(t, events) - events, err = round.RegisterPayments(payments) + events, err = round.RegisterTxRequests(requests) require.NoError(t, err) require.NotEmpty(t, events) diff --git a/server/internal/core/ports/tx_builder.go b/server/internal/core/ports/tx_builder.go index 9df3bcb..6aed2c6 100644 --- a/server/internal/core/ports/tx_builder.go +++ b/server/internal/core/ports/tx_builder.go @@ -27,15 +27,15 @@ type BoardingInput struct { } type TxBuilder interface { - // BuildRoundTx builds a round tx for the given payments, boarding inputs - // it selects coin from swept rounds and ASP wallet + // BuildRoundTx builds a round tx for the given tx requests, boarding inputs + // it selects coin from swept rounds and server wallet // returns the round partial tx, the vtxo tree and the set of connectors BuildRoundTx( - aspPubkey *secp256k1.PublicKey, payments []domain.Payment, boardingInputs []BoardingInput, sweptRounds []domain.Round, + serverPubkey *secp256k1.PublicKey, txRequests []domain.TxRequest, boardingInputs []BoardingInput, sweptRounds []domain.Round, cosigners ...*secp256k1.PublicKey, ) ( roundTx string, - congestionTree tree.CongestionTree, + vtxoTree tree.VtxoTree, connectorAddress string, connectors []string, err error, @@ -51,7 +51,7 @@ type TxBuilder interface { FinalizeAndExtract(tx string) (txhex string, err error) VerifyTapscriptPartialSigs(tx string) (valid bool, err error) // FindLeaves returns all the leaves txs that are reachable from the given outpoint - FindLeaves(congestionTree tree.CongestionTree, fromtxid string, vout uint32) (leaves []tree.Node, err error) + FindLeaves(vtxoTree tree.VtxoTree, fromtxid string, vout uint32) (leaves []tree.Node, err error) VerifyAndCombinePartialTx(dest string, src string) (string, error) GetTxID(tx string) (string, error) } diff --git a/server/internal/infrastructure/db/badger/utils.go b/server/internal/infrastructure/db/badger/utils.go index 3fb00f3..793a1e3 100644 --- a/server/internal/infrastructure/db/badger/utils.go +++ b/server/internal/infrastructure/db/badger/utils.go @@ -100,8 +100,8 @@ func deserializeEvent(buf []byte) (domain.RoundEvent, error) { } } { - var event = domain.PaymentsRegistered{} - if err := json.Unmarshal(buf, &event); err == nil && len(event.Payments) > 0 { + var event = domain.TxRequestsRegistered{} + if err := json.Unmarshal(buf, &event); err == nil && len(event.TxRequests) > 0 { return event, nil } } diff --git a/server/internal/infrastructure/db/badger/vtxo_repo.go b/server/internal/infrastructure/db/badger/vtxo_repo.go index 2f51a0c..219aa44 100644 --- a/server/internal/infrastructure/db/badger/vtxo_repo.go +++ b/server/internal/infrastructure/db/badger/vtxo_repo.go @@ -91,7 +91,7 @@ func (r *vtxoRepository) GetVtxos( func (r *vtxoRepository) GetVtxosForRound( ctx context.Context, txid string, ) ([]domain.Vtxo, error) { - query := badgerhold.Where("PoolTx").Eq(txid) + query := badgerhold.Where("RoundTx").Eq(txid) return r.findVtxos(ctx, query) } @@ -100,7 +100,7 @@ func (r *vtxoRepository) GetAllVtxos( ) ([]domain.Vtxo, []domain.Vtxo, error) { query := badgerhold.Where("Redeemed").Eq(false) if len(pubkey) > 0 { - query = query.And("Pubkey").Eq(pubkey) + query = query.And("PubKey").Eq(pubkey) } vtxos, err := r.findVtxos(ctx, query) if err != nil { diff --git a/server/internal/infrastructure/db/service_test.go b/server/internal/infrastructure/db/service_test.go index 65853fd..490ab2d 100644 --- a/server/internal/infrastructure/db/service_test.go +++ b/server/internal/infrastructure/db/service_test.go @@ -26,7 +26,7 @@ const ( pubkey2 = "33ffb3dee353b1a9ebe4ced64b946238d0a4ac364f275d771da6ad2445d07ae0" ) -var congestionTree = [][]tree.Node{ +var vtxoTree = [][]tree.Node{ { { Txid: randomString(32), @@ -148,17 +148,17 @@ func testRoundEventRepository(t *testing.T, svc ports.RepoManager) { Timestamp: 1701190270, }, domain.RoundFinalizationStarted{ - Id: "1ea610ff-bf3e-4068-9bfd-b6c3f553467e", - CongestionTree: congestionTree, - Connectors: []string{emptyPtx, emptyPtx}, - RoundTx: emptyTx, + Id: "1ea610ff-bf3e-4068-9bfd-b6c3f553467e", + VtxoTree: vtxoTree, + Connectors: []string{emptyPtx, emptyPtx}, + RoundTx: emptyTx, }, }, handler: func(round *domain.Round) { require.NotNil(t, round) require.Len(t, round.Events(), 2) - require.Len(t, round.CongestionTree, 3) - require.Equal(t, round.CongestionTree.NumberOfNodes(), 7) + require.Len(t, round.VtxoTree, 3) + require.Equal(t, round.VtxoTree.NumberOfNodes(), 7) require.Len(t, round.Connectors, 2) }, }, @@ -170,10 +170,10 @@ func testRoundEventRepository(t *testing.T, svc ports.RepoManager) { Timestamp: 1701190270, }, domain.RoundFinalizationStarted{ - Id: "7578231e-428d-45ae-aaa4-e62c77ad5cec", - CongestionTree: congestionTree, - Connectors: []string{emptyPtx, emptyPtx}, - RoundTx: emptyTx, + Id: "7578231e-428d-45ae-aaa4-e62c77ad5cec", + VtxoTree: vtxoTree, + Connectors: []string{emptyPtx, emptyPtx}, + RoundTx: emptyTx, }, domain.RoundFinalized{ Id: "7578231e-428d-45ae-aaa4-e62c77ad5cec", @@ -237,9 +237,9 @@ func testRoundRepository(t *testing.T, svc ports.RepoManager) { require.Condition(t, roundsMatch(*round, *roundById)) newEvents := []domain.RoundEvent{ - domain.PaymentsRegistered{ + domain.TxRequestsRegistered{ Id: roundId, - Payments: []domain.Payment{ + TxRequests: []domain.TxRequest{ { Id: uuid.New().String(), Inputs: []domain.Vtxo{ @@ -250,12 +250,12 @@ func testRoundRepository(t *testing.T, svc ports.RepoManager) { }, RoundTxid: randomString(32), ExpireAt: 7980322, - Pubkey: randomString(32), + PubKey: randomString(32), Amount: 300, }, }, Receivers: []domain.Receiver{{ - Pubkey: randomString(32), + PubKey: randomString(32), Amount: 300, }}, }, @@ -270,17 +270,17 @@ func testRoundRepository(t *testing.T, svc ports.RepoManager) { }, RoundTxid: randomString(32), ExpireAt: 7980322, - Pubkey: randomString(32), + PubKey: randomString(32), Amount: 600, }, }, Receivers: []domain.Receiver{ { - Pubkey: randomString(32), + PubKey: randomString(32), Amount: 400, }, { - Pubkey: randomString(32), + PubKey: randomString(32), Amount: 200, }, }, @@ -288,16 +288,16 @@ func testRoundRepository(t *testing.T, svc ports.RepoManager) { }, }, domain.RoundFinalizationStarted{ - Id: roundId, - CongestionTree: congestionTree, - Connectors: []string{emptyPtx, emptyPtx}, - RoundTx: emptyTx, + Id: roundId, + VtxoTree: vtxoTree, + Connectors: []string{emptyPtx, emptyPtx}, + RoundTx: emptyTx, }, } events = append(events, newEvents...) updatedRound := domain.NewRoundFromEvents(events) - for _, pay := range updatedRound.Payments { - err = svc.Vtxos().AddVtxos(ctx, pay.Inputs) + for _, request := range updatedRound.TxRequests { + err = svc.Vtxos().AddVtxos(ctx, request.Inputs) require.NoError(t, err) } @@ -346,7 +346,7 @@ func testVtxoRepository(t *testing.T, svc ports.RepoManager) { Txid: randomString(32), VOut: 0, }, - Pubkey: pubkey, + PubKey: pubkey, Amount: 1000, }, { @@ -354,7 +354,7 @@ func testVtxoRepository(t *testing.T, svc ports.RepoManager) { Txid: randomString(32), VOut: 1, }, - Pubkey: pubkey, + PubKey: pubkey, Amount: 2000, }, } @@ -363,7 +363,7 @@ func testVtxoRepository(t *testing.T, svc ports.RepoManager) { Txid: randomString(32), VOut: 1, }, - Pubkey: pubkey2, + PubKey: pubkey2, Amount: 2000, }) @@ -567,8 +567,8 @@ func roundsMatch(expected, got domain.Round) assert.Comparison { return false } - for k, v := range expected.Payments { - gotValue, ok := got.Payments[k] + for k, v := range expected.TxRequests { + gotValue, ok := got.TxRequests[k] if !ok { return false } @@ -612,7 +612,7 @@ func roundsMatch(expected, got domain.Round) assert.Comparison { } } - if !reflect.DeepEqual(expected.CongestionTree, got.CongestionTree) { + if !reflect.DeepEqual(expected.VtxoTree, got.VtxoTree) { return false } diff --git a/server/internal/infrastructure/db/sqlite/migration/20240703120550_init.down.sql b/server/internal/infrastructure/db/sqlite/migration/20240703120550_init.down.sql index 3ea3755..3212d7c 100644 --- a/server/internal/infrastructure/db/sqlite/migration/20240703120550_init.down.sql +++ b/server/internal/infrastructure/db/sqlite/migration/20240703120550_init.down.sql @@ -1,6 +1,6 @@ DROP TABLE IF EXISTS round; -DROP TABLE IF EXISTS payment; +DROP TABLE IF EXISTS tx_request; DROP TABLE IF EXISTS receiver; diff --git a/server/internal/infrastructure/db/sqlite/migration/20240703120550_init.up.sql b/server/internal/infrastructure/db/sqlite/migration/20240703120550_init.up.sql index dbdcfe1..ff13fbf 100644 --- a/server/internal/infrastructure/db/sqlite/migration/20240703120550_init.up.sql +++ b/server/internal/infrastructure/db/sqlite/migration/20240703120550_init.up.sql @@ -13,19 +13,19 @@ CREATE TABLE IF NOT EXISTS round ( swept BOOLEAN NOT NULL ); -CREATE TABLE IF NOT EXISTS payment ( +CREATE TABLE IF NOT EXISTS tx_request ( id TEXT PRIMARY KEY, round_id TEXT NOT NULL, FOREIGN KEY (round_id) REFERENCES round(id) ); CREATE TABLE IF NOT EXISTS receiver ( - payment_id TEXT NOT NULL, + request_id TEXT NOT NULL, pubkey TEXT, onchain_address TEXT, amount INTEGER NOT NULL, - FOREIGN KEY (payment_id) REFERENCES payment(id), - PRIMARY KEY (payment_id, pubkey, onchain_address) + FOREIGN KEY (request_id) REFERENCES tx_request(id), + PRIMARY KEY (request_id, pubkey, onchain_address) ); CREATE TABLE IF NOT EXISTS tx ( @@ -46,17 +46,17 @@ CREATE TABLE IF NOT EXISTS vtxo ( vout INTEGER NOT NULL, pubkey TEXT NOT NULL, amount INTEGER NOT NULL, - pool_tx TEXT NOT NULL, + round_tx TEXT NOT NULL, spent_by TEXT NOT NULL, spent BOOLEAN NOT NULL, redeemed BOOLEAN NOT NULL, swept BOOLEAN NOT NULL, expire_at INTEGER NOT NULL, created_at INTEGER NOT NULL, - payment_id TEXT, + request_id TEXT, redeem_tx TEXT, PRIMARY KEY (txid, vout), - FOREIGN KEY (payment_id) REFERENCES payment(id) + FOREIGN KEY (request_id) REFERENCES tx_request(id) ); CREATE TABLE IF NOT EXISTS note ( @@ -81,22 +81,22 @@ FROM entity LEFT OUTER JOIN entity_vtxo ON entity.id=entity_vtxo.entity_id; -CREATE VIEW round_payment_vw AS SELECT payment.* +CREATE VIEW round_request_vw AS SELECT tx_request.* FROM round -LEFT OUTER JOIN payment -ON round.id=payment.round_id; +LEFT OUTER JOIN tx_request +ON round.id=tx_request.round_id; CREATE VIEW round_tx_vw AS SELECT tx.* FROM round LEFT OUTER JOIN tx ON round.id=tx.round_id; -CREATE VIEW payment_receiver_vw AS SELECT receiver.* -FROM payment +CREATE VIEW request_receiver_vw AS SELECT receiver.* +FROM tx_request LEFT OUTER JOIN receiver -ON payment.id=receiver.payment_id; +ON tx_request.id=receiver.request_id; -CREATE VIEW payment_vtxo_vw AS SELECT vtxo.* -FROM payment +CREATE VIEW request_vtxo_vw AS SELECT vtxo.* +FROM tx_request LEFT OUTER JOIN vtxo -ON payment.id=vtxo.payment_id; \ No newline at end of file +ON tx_request.id=vtxo.request_id; \ No newline at end of file diff --git a/server/internal/infrastructure/db/sqlite/round_repo.go b/server/internal/infrastructure/db/sqlite/round_repo.go index 0020b7a..67dcfb0 100644 --- a/server/internal/infrastructure/db/sqlite/round_repo.go +++ b/server/internal/infrastructure/db/sqlite/round_repo.go @@ -86,7 +86,7 @@ func (r *roundRepository) AddOrUpdateRound(ctx context.Context, round domain.Rou return fmt.Errorf("failed to upsert round: %w", err) } - if len(round.ForfeitTxs) > 0 || len(round.Connectors) > 0 || len(round.CongestionTree) > 0 { + if len(round.ForfeitTxs) > 0 || len(round.Connectors) > 0 || len(round.VtxoTree) > 0 { for pos, tx := range round.ForfeitTxs { if err := querierWithTx.UpsertTransaction( ctx, @@ -115,7 +115,7 @@ func (r *roundRepository) AddOrUpdateRound(ctx context.Context, round domain.Rou } } - for level, levelTxs := range round.CongestionTree { + for level, levelTxs := range round.VtxoTree { for pos, tx := range levelTxs { if err := querierWithTx.UpsertTransaction( ctx, @@ -148,27 +148,27 @@ func (r *roundRepository) AddOrUpdateRound(ctx context.Context, round domain.Rou } } - if len(round.Payments) > 0 { - for _, payment := range round.Payments { - if err := querierWithTx.UpsertPayment( + if len(round.TxRequests) > 0 { + for _, request := range round.TxRequests { + if err := querierWithTx.UpsertTxRequest( ctx, - queries.UpsertPaymentParams{ - ID: payment.Id, + queries.UpsertTxRequestParams{ + ID: request.Id, RoundID: round.Id, }, ); err != nil { - return fmt.Errorf("failed to upsert payment: %w", err) + return fmt.Errorf("failed to upsert tx request: %w", err) } - for _, receiver := range payment.Receivers { + for _, receiver := range request.Receivers { if err := querierWithTx.UpsertReceiver( ctx, queries.UpsertReceiverParams{ - PaymentID: payment.Id, + RequestID: request.Id, Amount: int64(receiver.Amount), Pubkey: sql.NullString{ - String: receiver.Pubkey, - Valid: len(receiver.Pubkey) > 0, + String: receiver.PubKey, + Valid: len(receiver.PubKey) > 0, }, OnchainAddress: sql.NullString{ String: receiver.OnchainAddress, @@ -180,19 +180,19 @@ func (r *roundRepository) AddOrUpdateRound(ctx context.Context, round domain.Rou } } - for _, input := range payment.Inputs { - if err := querierWithTx.UpdateVtxoPaymentId( + for _, input := range request.Inputs { + if err := querierWithTx.UpdateVtxoRequestId( ctx, - queries.UpdateVtxoPaymentIdParams{ - PaymentID: sql.NullString{ - String: payment.Id, + queries.UpdateVtxoRequestIdParams{ + RequestID: sql.NullString{ + String: request.Id, Valid: true, }, Txid: input.Txid, Vout: int64(input.VOut), }, ); err != nil { - return fmt.Errorf("failed to update vtxo payment id: %w", err) + return fmt.Errorf("failed to update vtxo request id: %w", err) } } } @@ -210,18 +210,18 @@ func (r *roundRepository) GetRoundWithId(ctx context.Context, id string) (*domai return nil, err } - rvs := make([]roundPaymentTxReceiverVtxoRow, 0, len(rows)) + rvs := make([]combinedRow, 0, len(rows)) for _, row := range rows { - rvs = append(rvs, roundPaymentTxReceiverVtxoRow{ + rvs = append(rvs, combinedRow{ round: row.Round, - payment: row.RoundPaymentVw, + request: row.RoundRequestVw, tx: row.RoundTxVw, - receiver: row.PaymentReceiverVw, - vtxo: row.PaymentVtxoVw, + receiver: row.RequestReceiverVw, + vtxo: row.RequestVtxoVw, }) } - rounds, err := readRoundRows(rvs) + rounds, err := rowsToRounds(rvs) if err != nil { return nil, err } @@ -239,18 +239,18 @@ func (r *roundRepository) GetRoundWithTxid(ctx context.Context, txid string) (*d return nil, err } - rvs := make([]roundPaymentTxReceiverVtxoRow, 0, len(rows)) + rvs := make([]combinedRow, 0, len(rows)) for _, row := range rows { - rvs = append(rvs, roundPaymentTxReceiverVtxoRow{ + rvs = append(rvs, combinedRow{ round: row.Round, - payment: row.RoundPaymentVw, + request: row.RoundRequestVw, tx: row.RoundTxVw, - receiver: row.PaymentReceiverVw, - vtxo: row.PaymentVtxoVw, + receiver: row.RequestReceiverVw, + vtxo: row.RequestVtxoVw, }) } - rounds, err := readRoundRows(rvs) + rounds, err := rowsToRounds(rvs) if err != nil { return nil, err } @@ -268,18 +268,18 @@ func (r *roundRepository) GetSweepableRounds(ctx context.Context) ([]domain.Roun return nil, err } - rvs := make([]roundPaymentTxReceiverVtxoRow, 0, len(rows)) + rvs := make([]combinedRow, 0, len(rows)) for _, row := range rows { - rvs = append(rvs, roundPaymentTxReceiverVtxoRow{ + rvs = append(rvs, combinedRow{ round: row.Round, - payment: row.RoundPaymentVw, + request: row.RoundRequestVw, tx: row.RoundTxVw, - receiver: row.PaymentReceiverVw, - vtxo: row.PaymentVtxoVw, + receiver: row.RequestReceiverVw, + vtxo: row.RequestVtxoVw, }) } - rounds, err := readRoundRows(rvs) + rounds, err := rowsToRounds(rvs) if err != nil { return nil, err } @@ -299,18 +299,18 @@ func (r *roundRepository) GetSweptRounds(ctx context.Context) ([]domain.Round, e return nil, err } - rvs := make([]roundPaymentTxReceiverVtxoRow, 0, len(rows)) + rvs := make([]combinedRow, 0, len(rows)) for _, row := range rows { - rvs = append(rvs, roundPaymentTxReceiverVtxoRow{ + rvs = append(rvs, combinedRow{ round: row.Round, - payment: row.RoundPaymentVw, + request: row.RoundRequestVw, tx: row.RoundTxVw, - receiver: row.PaymentReceiverVw, - vtxo: row.PaymentVtxoVw, + receiver: row.RequestReceiverVw, + vtxo: row.RequestVtxoVw, }) } - rounds, err := readRoundRows(rvs) + rounds, err := rowsToRounds(rvs) if err != nil { return nil, err } @@ -324,23 +324,23 @@ func (r *roundRepository) GetSweptRounds(ctx context.Context) ([]domain.Round, e return res, nil } -func rowToReceiver(row queries.PaymentReceiverVw) domain.Receiver { +func rowToReceiver(row queries.RequestReceiverVw) domain.Receiver { return domain.Receiver{ Amount: uint64(row.Amount.Int64), - Pubkey: row.Pubkey.String, + PubKey: row.Pubkey.String, OnchainAddress: row.OnchainAddress.String, } } -type roundPaymentTxReceiverVtxoRow struct { +type combinedRow struct { round queries.Round - payment queries.RoundPaymentVw + request queries.RoundRequestVw tx queries.RoundTxVw - receiver queries.PaymentReceiverVw - vtxo queries.PaymentVtxoVw + receiver queries.RequestReceiverVw + vtxo queries.RequestVtxoVw } -func readRoundRows(rows []roundPaymentTxReceiverVtxoRow) ([]*domain.Round, error) { +func rowsToRounds(rows []combinedRow) ([]*domain.Round, error) { rounds := make(map[string]*domain.Round) for _, v := range rows { @@ -364,35 +364,34 @@ func readRoundRows(rows []roundPaymentTxReceiverVtxoRow) ([]*domain.Round, error DustAmount: uint64(v.round.DustAmount), Version: uint(v.round.Version), Swept: v.round.Swept, - Payments: make(map[string]domain.Payment), + TxRequests: make(map[string]domain.TxRequest), } } - if v.payment.ID.Valid { - payment, ok := round.Payments[v.payment.ID.String] + if v.request.ID.Valid { + request, ok := round.TxRequests[v.request.ID.String] if !ok { - payment = domain.Payment{ - Id: v.payment.ID.String, + request = domain.TxRequest{ + Id: v.request.ID.String, Inputs: make([]domain.Vtxo, 0), Receivers: make([]domain.Receiver, 0), } - round.Payments[v.payment.ID.String] = payment + round.TxRequests[v.request.ID.String] = request } - if v.vtxo.PaymentID.Valid { - payment, ok = round.Payments[v.vtxo.PaymentID.String] + if v.vtxo.RequestID.Valid { + request, ok = round.TxRequests[v.vtxo.RequestID.String] if !ok { - payment = domain.Payment{ - Id: v.vtxo.PaymentID.String, + request = domain.TxRequest{ + Id: v.vtxo.RequestID.String, Inputs: make([]domain.Vtxo, 0), Receivers: make([]domain.Receiver, 0), } } - vtxo := rowToPaymentVtxoVw(v.vtxo) + vtxo := combinedRowToVtxo(v.vtxo) found := false - - for _, v := range payment.Inputs { + for _, v := range request.Inputs { if vtxo.Txid == v.Txid && vtxo.VOut == v.VOut { found = true break @@ -400,16 +399,16 @@ func readRoundRows(rows []roundPaymentTxReceiverVtxoRow) ([]*domain.Round, error } if !found { - payment.Inputs = append(payment.Inputs, rowToPaymentVtxoVw(v.vtxo)) - round.Payments[v.vtxo.PaymentID.String] = payment + request.Inputs = append(request.Inputs, combinedRowToVtxo(v.vtxo)) + round.TxRequests[v.vtxo.RequestID.String] = request } } - if v.receiver.PaymentID.Valid { - payment, ok = round.Payments[v.receiver.PaymentID.String] + if v.receiver.RequestID.Valid { + request, ok = round.TxRequests[v.receiver.RequestID.String] if !ok { - payment = domain.Payment{ - Id: v.receiver.PaymentID.String, + request = domain.TxRequest{ + Id: v.receiver.RequestID.String, Inputs: make([]domain.Vtxo, 0), Receivers: make([]domain.Receiver, 0), } @@ -418,17 +417,17 @@ func readRoundRows(rows []roundPaymentTxReceiverVtxoRow) ([]*domain.Round, error rcv := rowToReceiver(v.receiver) found := false - for _, rcv := range payment.Receivers { + for _, rcv := range request.Receivers { if (v.receiver.Pubkey.Valid || v.receiver.OnchainAddress.Valid) && v.receiver.Amount.Valid { - if rcv.Pubkey == v.receiver.Pubkey.String && rcv.OnchainAddress == v.receiver.OnchainAddress.String && int64(rcv.Amount) == v.receiver.Amount.Int64 { + if rcv.PubKey == v.receiver.Pubkey.String && rcv.OnchainAddress == v.receiver.OnchainAddress.String && int64(rcv.Amount) == v.receiver.Amount.Int64 { found = true break } } } if !found { - payment.Receivers = append(payment.Receivers, rcv) - round.Payments[v.receiver.PaymentID.String] = payment + request.Receivers = append(request.Receivers, rcv) + round.TxRequests[v.receiver.RequestID.String] = request } } } @@ -444,10 +443,10 @@ func readRoundRows(rows []roundPaymentTxReceiverVtxoRow) ([]*domain.Round, error round.Connectors[position.Int64] = v.tx.Tx.String case "tree": level := v.tx.TreeLevel - round.CongestionTree = extendArray(round.CongestionTree, int(level.Int64)) - round.CongestionTree[int(level.Int64)] = extendArray(round.CongestionTree[int(level.Int64)], int(position.Int64)) - if round.CongestionTree[int(level.Int64)][position.Int64] == (tree.Node{}) { - round.CongestionTree[int(level.Int64)][position.Int64] = tree.Node{ + round.VtxoTree = extendArray(round.VtxoTree, int(level.Int64)) + round.VtxoTree[int(level.Int64)] = extendArray(round.VtxoTree[int(level.Int64)], int(position.Int64)) + if round.VtxoTree[int(level.Int64)][position.Int64] == (tree.Node{}) { + round.VtxoTree[int(level.Int64)][position.Int64] = tree.Node{ Tx: v.tx.Tx.String, Txid: v.tx.Txid.String, ParentTxid: v.tx.ParentTxid.String, @@ -469,15 +468,15 @@ func readRoundRows(rows []roundPaymentTxReceiverVtxoRow) ([]*domain.Round, error return result, nil } -func rowToPaymentVtxoVw(row queries.PaymentVtxoVw) domain.Vtxo { +func combinedRowToVtxo(row queries.RequestVtxoVw) domain.Vtxo { return domain.Vtxo{ VtxoKey: domain.VtxoKey{ Txid: row.Txid.String, VOut: uint32(row.Vout.Int64), }, Amount: uint64(row.Amount.Int64), - Pubkey: row.Pubkey.String, - RoundTxid: row.PoolTx.String, + PubKey: row.Pubkey.String, + RoundTxid: row.RoundTx.String, SpentBy: row.SpentBy.String, Spent: row.Spent.Bool, Redeemed: row.Redeemed.Bool, diff --git a/server/internal/infrastructure/db/sqlite/sqlc/queries/models.go b/server/internal/infrastructure/db/sqlite/sqlc/queries/models.go index 4c04ca2..54a8636 100644 --- a/server/internal/infrastructure/db/sqlite/sqlc/queries/models.go +++ b/server/internal/infrastructure/db/sqlite/sqlc/queries/models.go @@ -39,41 +39,36 @@ type Note struct { ID int64 } -type Payment struct { - ID string - RoundID string +type Receiver struct { + RequestID string + Pubkey sql.NullString + OnchainAddress sql.NullString + Amount int64 } -type PaymentReceiverVw struct { - PaymentID sql.NullString +type RequestReceiverVw struct { + RequestID sql.NullString Pubkey sql.NullString OnchainAddress sql.NullString Amount sql.NullInt64 } -type PaymentVtxoVw struct { +type RequestVtxoVw struct { Txid sql.NullString Vout sql.NullInt64 Pubkey sql.NullString Amount sql.NullInt64 - PoolTx sql.NullString + RoundTx sql.NullString SpentBy sql.NullString Spent sql.NullBool Redeemed sql.NullBool Swept sql.NullBool ExpireAt sql.NullInt64 CreatedAt sql.NullInt64 - PaymentID sql.NullString + RequestID sql.NullString RedeemTx sql.NullString } -type Receiver struct { - PaymentID string - Pubkey sql.NullString - OnchainAddress sql.NullString - Amount int64 -} - type Round struct { ID string StartingTimestamp int64 @@ -89,7 +84,7 @@ type Round struct { Swept bool } -type RoundPaymentVw struct { +type RoundRequestVw struct { ID sql.NullString RoundID sql.NullString } @@ -118,18 +113,23 @@ type Tx struct { IsLeaf sql.NullBool } +type TxRequest struct { + ID string + RoundID string +} + type Vtxo struct { Txid string Vout int64 Pubkey string Amount int64 - PoolTx string + RoundTx string SpentBy string Spent bool Redeemed bool Swept bool ExpireAt int64 CreatedAt int64 - PaymentID sql.NullString + RequestID sql.NullString RedeemTx sql.NullString } diff --git a/server/internal/infrastructure/db/sqlite/sqlc/queries/query.sql.go b/server/internal/infrastructure/db/sqlite/sqlc/queries/query.sql.go index fcafbd7..54eb24e 100644 --- a/server/internal/infrastructure/db/sqlite/sqlc/queries/query.sql.go +++ b/server/internal/infrastructure/db/sqlite/sqlc/queries/query.sql.go @@ -191,7 +191,7 @@ func (q *Queries) SelectEntitiesByVtxo(ctx context.Context, arg SelectEntitiesBy } const selectNotRedeemedVtxos = `-- name: SelectNotRedeemedVtxos :many -SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo +SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.round_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.request_id, vtxo.redeem_tx FROM vtxo WHERE redeemed = false ` @@ -213,14 +213,14 @@ func (q *Queries) SelectNotRedeemedVtxos(ctx context.Context) ([]SelectNotRedeem &i.Vtxo.Vout, &i.Vtxo.Pubkey, &i.Vtxo.Amount, - &i.Vtxo.PoolTx, + &i.Vtxo.RoundTx, &i.Vtxo.SpentBy, &i.Vtxo.Spent, &i.Vtxo.Redeemed, &i.Vtxo.Swept, &i.Vtxo.ExpireAt, &i.Vtxo.CreatedAt, - &i.Vtxo.PaymentID, + &i.Vtxo.RequestID, &i.Vtxo.RedeemTx, ); err != nil { return nil, err @@ -237,7 +237,7 @@ func (q *Queries) SelectNotRedeemedVtxos(ctx context.Context) ([]SelectNotRedeem } const selectNotRedeemedVtxosWithPubkey = `-- name: SelectNotRedeemedVtxosWithPubkey :many -SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo +SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.round_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.request_id, vtxo.redeem_tx FROM vtxo WHERE redeemed = false AND pubkey = ? ` @@ -259,14 +259,14 @@ func (q *Queries) SelectNotRedeemedVtxosWithPubkey(ctx context.Context, pubkey s &i.Vtxo.Vout, &i.Vtxo.Pubkey, &i.Vtxo.Amount, - &i.Vtxo.PoolTx, + &i.Vtxo.RoundTx, &i.Vtxo.SpentBy, &i.Vtxo.Spent, &i.Vtxo.Redeemed, &i.Vtxo.Swept, &i.Vtxo.ExpireAt, &i.Vtxo.CreatedAt, - &i.Vtxo.PaymentID, + &i.Vtxo.RequestID, &i.Vtxo.RedeemTx, ); err != nil { return nil, err @@ -343,24 +343,24 @@ func (q *Queries) SelectRoundIdsInRange(ctx context.Context, arg SelectRoundIdsI const selectRoundWithRoundId = `-- name: SelectRoundWithRoundId :many SELECT round.id, round.starting_timestamp, round.ending_timestamp, round.ended, round.failed, round.stage_code, round.txid, round.unsigned_tx, round.connector_address, round.dust_amount, round.version, round.swept, - round_payment_vw.id, round_payment_vw.round_id, + round_request_vw.id, round_request_vw.round_id, round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf, - payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.onchain_address, payment_receiver_vw.amount, - payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.created_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx + request_receiver_vw.request_id, request_receiver_vw.pubkey, request_receiver_vw.onchain_address, request_receiver_vw.amount, + request_vtxo_vw.txid, request_vtxo_vw.vout, request_vtxo_vw.pubkey, request_vtxo_vw.amount, request_vtxo_vw.round_tx, request_vtxo_vw.spent_by, request_vtxo_vw.spent, request_vtxo_vw.redeemed, request_vtxo_vw.swept, request_vtxo_vw.expire_at, request_vtxo_vw.created_at, request_vtxo_vw.request_id, request_vtxo_vw.redeem_tx FROM round - LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id + LEFT OUTER JOIN round_request_vw ON round.id=round_request_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id - LEFT OUTER JOIN payment_receiver_vw ON round_payment_vw.id=payment_receiver_vw.payment_id - LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id + LEFT OUTER JOIN request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id + LEFT OUTER JOIN request_vtxo_vw ON round_request_vw.id=request_vtxo_vw.request_id WHERE round.id = ? ` type SelectRoundWithRoundIdRow struct { Round Round - RoundPaymentVw RoundPaymentVw + RoundRequestVw RoundRequestVw RoundTxVw RoundTxVw - PaymentReceiverVw PaymentReceiverVw - PaymentVtxoVw PaymentVtxoVw + RequestReceiverVw RequestReceiverVw + RequestVtxoVw RequestVtxoVw } func (q *Queries) SelectRoundWithRoundId(ctx context.Context, id string) ([]SelectRoundWithRoundIdRow, error) { @@ -385,8 +385,8 @@ func (q *Queries) SelectRoundWithRoundId(ctx context.Context, id string) ([]Sele &i.Round.DustAmount, &i.Round.Version, &i.Round.Swept, - &i.RoundPaymentVw.ID, - &i.RoundPaymentVw.RoundID, + &i.RoundRequestVw.ID, + &i.RoundRequestVw.RoundID, &i.RoundTxVw.ID, &i.RoundTxVw.Tx, &i.RoundTxVw.RoundID, @@ -396,23 +396,23 @@ func (q *Queries) SelectRoundWithRoundId(ctx context.Context, id string) ([]Sele &i.RoundTxVw.TreeLevel, &i.RoundTxVw.ParentTxid, &i.RoundTxVw.IsLeaf, - &i.PaymentReceiverVw.PaymentID, - &i.PaymentReceiverVw.Pubkey, - &i.PaymentReceiverVw.OnchainAddress, - &i.PaymentReceiverVw.Amount, - &i.PaymentVtxoVw.Txid, - &i.PaymentVtxoVw.Vout, - &i.PaymentVtxoVw.Pubkey, - &i.PaymentVtxoVw.Amount, - &i.PaymentVtxoVw.PoolTx, - &i.PaymentVtxoVw.SpentBy, - &i.PaymentVtxoVw.Spent, - &i.PaymentVtxoVw.Redeemed, - &i.PaymentVtxoVw.Swept, - &i.PaymentVtxoVw.ExpireAt, - &i.PaymentVtxoVw.CreatedAt, - &i.PaymentVtxoVw.PaymentID, - &i.PaymentVtxoVw.RedeemTx, + &i.RequestReceiverVw.RequestID, + &i.RequestReceiverVw.Pubkey, + &i.RequestReceiverVw.OnchainAddress, + &i.RequestReceiverVw.Amount, + &i.RequestVtxoVw.Txid, + &i.RequestVtxoVw.Vout, + &i.RequestVtxoVw.Pubkey, + &i.RequestVtxoVw.Amount, + &i.RequestVtxoVw.RoundTx, + &i.RequestVtxoVw.SpentBy, + &i.RequestVtxoVw.Spent, + &i.RequestVtxoVw.Redeemed, + &i.RequestVtxoVw.Swept, + &i.RequestVtxoVw.ExpireAt, + &i.RequestVtxoVw.CreatedAt, + &i.RequestVtxoVw.RequestID, + &i.RequestVtxoVw.RedeemTx, ); err != nil { return nil, err } @@ -429,24 +429,24 @@ func (q *Queries) SelectRoundWithRoundId(ctx context.Context, id string) ([]Sele const selectRoundWithRoundTxId = `-- name: SelectRoundWithRoundTxId :many SELECT round.id, round.starting_timestamp, round.ending_timestamp, round.ended, round.failed, round.stage_code, round.txid, round.unsigned_tx, round.connector_address, round.dust_amount, round.version, round.swept, - round_payment_vw.id, round_payment_vw.round_id, + round_request_vw.id, round_request_vw.round_id, round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf, - payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.onchain_address, payment_receiver_vw.amount, - payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.created_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx + request_receiver_vw.request_id, request_receiver_vw.pubkey, request_receiver_vw.onchain_address, request_receiver_vw.amount, + request_vtxo_vw.txid, request_vtxo_vw.vout, request_vtxo_vw.pubkey, request_vtxo_vw.amount, request_vtxo_vw.round_tx, request_vtxo_vw.spent_by, request_vtxo_vw.spent, request_vtxo_vw.redeemed, request_vtxo_vw.swept, request_vtxo_vw.expire_at, request_vtxo_vw.created_at, request_vtxo_vw.request_id, request_vtxo_vw.redeem_tx FROM round - LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id + LEFT OUTER JOIN round_request_vw ON round.id=round_request_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id - LEFT OUTER JOIN payment_receiver_vw ON round_payment_vw.id=payment_receiver_vw.payment_id - LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id + LEFT OUTER JOIN request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id + LEFT OUTER JOIN request_vtxo_vw ON round_request_vw.id=request_vtxo_vw.request_id WHERE round.txid = ? ` type SelectRoundWithRoundTxIdRow struct { Round Round - RoundPaymentVw RoundPaymentVw + RoundRequestVw RoundRequestVw RoundTxVw RoundTxVw - PaymentReceiverVw PaymentReceiverVw - PaymentVtxoVw PaymentVtxoVw + RequestReceiverVw RequestReceiverVw + RequestVtxoVw RequestVtxoVw } func (q *Queries) SelectRoundWithRoundTxId(ctx context.Context, txid string) ([]SelectRoundWithRoundTxIdRow, error) { @@ -471,8 +471,8 @@ func (q *Queries) SelectRoundWithRoundTxId(ctx context.Context, txid string) ([] &i.Round.DustAmount, &i.Round.Version, &i.Round.Swept, - &i.RoundPaymentVw.ID, - &i.RoundPaymentVw.RoundID, + &i.RoundRequestVw.ID, + &i.RoundRequestVw.RoundID, &i.RoundTxVw.ID, &i.RoundTxVw.Tx, &i.RoundTxVw.RoundID, @@ -482,23 +482,23 @@ func (q *Queries) SelectRoundWithRoundTxId(ctx context.Context, txid string) ([] &i.RoundTxVw.TreeLevel, &i.RoundTxVw.ParentTxid, &i.RoundTxVw.IsLeaf, - &i.PaymentReceiverVw.PaymentID, - &i.PaymentReceiverVw.Pubkey, - &i.PaymentReceiverVw.OnchainAddress, - &i.PaymentReceiverVw.Amount, - &i.PaymentVtxoVw.Txid, - &i.PaymentVtxoVw.Vout, - &i.PaymentVtxoVw.Pubkey, - &i.PaymentVtxoVw.Amount, - &i.PaymentVtxoVw.PoolTx, - &i.PaymentVtxoVw.SpentBy, - &i.PaymentVtxoVw.Spent, - &i.PaymentVtxoVw.Redeemed, - &i.PaymentVtxoVw.Swept, - &i.PaymentVtxoVw.ExpireAt, - &i.PaymentVtxoVw.CreatedAt, - &i.PaymentVtxoVw.PaymentID, - &i.PaymentVtxoVw.RedeemTx, + &i.RequestReceiverVw.RequestID, + &i.RequestReceiverVw.Pubkey, + &i.RequestReceiverVw.OnchainAddress, + &i.RequestReceiverVw.Amount, + &i.RequestVtxoVw.Txid, + &i.RequestVtxoVw.Vout, + &i.RequestVtxoVw.Pubkey, + &i.RequestVtxoVw.Amount, + &i.RequestVtxoVw.RoundTx, + &i.RequestVtxoVw.SpentBy, + &i.RequestVtxoVw.Spent, + &i.RequestVtxoVw.Redeemed, + &i.RequestVtxoVw.Swept, + &i.RequestVtxoVw.ExpireAt, + &i.RequestVtxoVw.CreatedAt, + &i.RequestVtxoVw.RequestID, + &i.RequestVtxoVw.RedeemTx, ); err != nil { return nil, err } @@ -515,24 +515,24 @@ func (q *Queries) SelectRoundWithRoundTxId(ctx context.Context, txid string) ([] const selectSweepableRounds = `-- name: SelectSweepableRounds :many SELECT round.id, round.starting_timestamp, round.ending_timestamp, round.ended, round.failed, round.stage_code, round.txid, round.unsigned_tx, round.connector_address, round.dust_amount, round.version, round.swept, - round_payment_vw.id, round_payment_vw.round_id, + round_request_vw.id, round_request_vw.round_id, round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf, - payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.onchain_address, payment_receiver_vw.amount, - payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.created_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx + request_receiver_vw.request_id, request_receiver_vw.pubkey, request_receiver_vw.onchain_address, request_receiver_vw.amount, + request_vtxo_vw.txid, request_vtxo_vw.vout, request_vtxo_vw.pubkey, request_vtxo_vw.amount, request_vtxo_vw.round_tx, request_vtxo_vw.spent_by, request_vtxo_vw.spent, request_vtxo_vw.redeemed, request_vtxo_vw.swept, request_vtxo_vw.expire_at, request_vtxo_vw.created_at, request_vtxo_vw.request_id, request_vtxo_vw.redeem_tx FROM round - LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id + LEFT OUTER JOIN round_request_vw ON round.id=round_request_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id - LEFT OUTER JOIN payment_receiver_vw ON round_payment_vw.id=payment_receiver_vw.payment_id - LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id + LEFT OUTER JOIN request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id + LEFT OUTER JOIN request_vtxo_vw ON round_request_vw.id=request_vtxo_vw.request_id WHERE round.swept = false AND round.ended = true AND round.failed = false ` type SelectSweepableRoundsRow struct { Round Round - RoundPaymentVw RoundPaymentVw + RoundRequestVw RoundRequestVw RoundTxVw RoundTxVw - PaymentReceiverVw PaymentReceiverVw - PaymentVtxoVw PaymentVtxoVw + RequestReceiverVw RequestReceiverVw + RequestVtxoVw RequestVtxoVw } func (q *Queries) SelectSweepableRounds(ctx context.Context) ([]SelectSweepableRoundsRow, error) { @@ -557,8 +557,8 @@ func (q *Queries) SelectSweepableRounds(ctx context.Context) ([]SelectSweepableR &i.Round.DustAmount, &i.Round.Version, &i.Round.Swept, - &i.RoundPaymentVw.ID, - &i.RoundPaymentVw.RoundID, + &i.RoundRequestVw.ID, + &i.RoundRequestVw.RoundID, &i.RoundTxVw.ID, &i.RoundTxVw.Tx, &i.RoundTxVw.RoundID, @@ -568,23 +568,23 @@ func (q *Queries) SelectSweepableRounds(ctx context.Context) ([]SelectSweepableR &i.RoundTxVw.TreeLevel, &i.RoundTxVw.ParentTxid, &i.RoundTxVw.IsLeaf, - &i.PaymentReceiverVw.PaymentID, - &i.PaymentReceiverVw.Pubkey, - &i.PaymentReceiverVw.OnchainAddress, - &i.PaymentReceiverVw.Amount, - &i.PaymentVtxoVw.Txid, - &i.PaymentVtxoVw.Vout, - &i.PaymentVtxoVw.Pubkey, - &i.PaymentVtxoVw.Amount, - &i.PaymentVtxoVw.PoolTx, - &i.PaymentVtxoVw.SpentBy, - &i.PaymentVtxoVw.Spent, - &i.PaymentVtxoVw.Redeemed, - &i.PaymentVtxoVw.Swept, - &i.PaymentVtxoVw.ExpireAt, - &i.PaymentVtxoVw.CreatedAt, - &i.PaymentVtxoVw.PaymentID, - &i.PaymentVtxoVw.RedeemTx, + &i.RequestReceiverVw.RequestID, + &i.RequestReceiverVw.Pubkey, + &i.RequestReceiverVw.OnchainAddress, + &i.RequestReceiverVw.Amount, + &i.RequestVtxoVw.Txid, + &i.RequestVtxoVw.Vout, + &i.RequestVtxoVw.Pubkey, + &i.RequestVtxoVw.Amount, + &i.RequestVtxoVw.RoundTx, + &i.RequestVtxoVw.SpentBy, + &i.RequestVtxoVw.Spent, + &i.RequestVtxoVw.Redeemed, + &i.RequestVtxoVw.Swept, + &i.RequestVtxoVw.ExpireAt, + &i.RequestVtxoVw.CreatedAt, + &i.RequestVtxoVw.RequestID, + &i.RequestVtxoVw.RedeemTx, ); err != nil { return nil, err } @@ -600,7 +600,7 @@ func (q *Queries) SelectSweepableRounds(ctx context.Context) ([]SelectSweepableR } const selectSweepableVtxos = `-- name: SelectSweepableVtxos :many -SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo +SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.round_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.request_id, vtxo.redeem_tx FROM vtxo WHERE redeemed = false AND swept = false ` @@ -622,14 +622,14 @@ func (q *Queries) SelectSweepableVtxos(ctx context.Context) ([]SelectSweepableVt &i.Vtxo.Vout, &i.Vtxo.Pubkey, &i.Vtxo.Amount, - &i.Vtxo.PoolTx, + &i.Vtxo.RoundTx, &i.Vtxo.SpentBy, &i.Vtxo.Spent, &i.Vtxo.Redeemed, &i.Vtxo.Swept, &i.Vtxo.ExpireAt, &i.Vtxo.CreatedAt, - &i.Vtxo.PaymentID, + &i.Vtxo.RequestID, &i.Vtxo.RedeemTx, ); err != nil { return nil, err @@ -647,24 +647,24 @@ func (q *Queries) SelectSweepableVtxos(ctx context.Context) ([]SelectSweepableVt const selectSweptRounds = `-- name: SelectSweptRounds :many SELECT round.id, round.starting_timestamp, round.ending_timestamp, round.ended, round.failed, round.stage_code, round.txid, round.unsigned_tx, round.connector_address, round.dust_amount, round.version, round.swept, - round_payment_vw.id, round_payment_vw.round_id, + round_request_vw.id, round_request_vw.round_id, round_tx_vw.id, round_tx_vw.tx, round_tx_vw.round_id, round_tx_vw.type, round_tx_vw.position, round_tx_vw.txid, round_tx_vw.tree_level, round_tx_vw.parent_txid, round_tx_vw.is_leaf, - payment_receiver_vw.payment_id, payment_receiver_vw.pubkey, payment_receiver_vw.onchain_address, payment_receiver_vw.amount, - payment_vtxo_vw.txid, payment_vtxo_vw.vout, payment_vtxo_vw.pubkey, payment_vtxo_vw.amount, payment_vtxo_vw.pool_tx, payment_vtxo_vw.spent_by, payment_vtxo_vw.spent, payment_vtxo_vw.redeemed, payment_vtxo_vw.swept, payment_vtxo_vw.expire_at, payment_vtxo_vw.created_at, payment_vtxo_vw.payment_id, payment_vtxo_vw.redeem_tx + request_receiver_vw.request_id, request_receiver_vw.pubkey, request_receiver_vw.onchain_address, request_receiver_vw.amount, + request_vtxo_vw.txid, request_vtxo_vw.vout, request_vtxo_vw.pubkey, request_vtxo_vw.amount, request_vtxo_vw.round_tx, request_vtxo_vw.spent_by, request_vtxo_vw.spent, request_vtxo_vw.redeemed, request_vtxo_vw.swept, request_vtxo_vw.expire_at, request_vtxo_vw.created_at, request_vtxo_vw.request_id, request_vtxo_vw.redeem_tx FROM round - LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id + LEFT OUTER JOIN round_request_vw ON round.id=round_request_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id - LEFT OUTER JOIN payment_receiver_vw ON round_payment_vw.id=payment_receiver_vw.payment_id - LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id + LEFT OUTER JOIN request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id + LEFT OUTER JOIN request_vtxo_vw ON round_request_vw.id=request_vtxo_vw.request_id WHERE round.swept = true AND round.failed = false AND round.ended = true AND round.connector_address <> '' ` type SelectSweptRoundsRow struct { Round Round - RoundPaymentVw RoundPaymentVw + RoundRequestVw RoundRequestVw RoundTxVw RoundTxVw - PaymentReceiverVw PaymentReceiverVw - PaymentVtxoVw PaymentVtxoVw + RequestReceiverVw RequestReceiverVw + RequestVtxoVw RequestVtxoVw } func (q *Queries) SelectSweptRounds(ctx context.Context) ([]SelectSweptRoundsRow, error) { @@ -689,8 +689,8 @@ func (q *Queries) SelectSweptRounds(ctx context.Context) ([]SelectSweptRoundsRow &i.Round.DustAmount, &i.Round.Version, &i.Round.Swept, - &i.RoundPaymentVw.ID, - &i.RoundPaymentVw.RoundID, + &i.RoundRequestVw.ID, + &i.RoundRequestVw.RoundID, &i.RoundTxVw.ID, &i.RoundTxVw.Tx, &i.RoundTxVw.RoundID, @@ -700,23 +700,23 @@ func (q *Queries) SelectSweptRounds(ctx context.Context) ([]SelectSweptRoundsRow &i.RoundTxVw.TreeLevel, &i.RoundTxVw.ParentTxid, &i.RoundTxVw.IsLeaf, - &i.PaymentReceiverVw.PaymentID, - &i.PaymentReceiverVw.Pubkey, - &i.PaymentReceiverVw.OnchainAddress, - &i.PaymentReceiverVw.Amount, - &i.PaymentVtxoVw.Txid, - &i.PaymentVtxoVw.Vout, - &i.PaymentVtxoVw.Pubkey, - &i.PaymentVtxoVw.Amount, - &i.PaymentVtxoVw.PoolTx, - &i.PaymentVtxoVw.SpentBy, - &i.PaymentVtxoVw.Spent, - &i.PaymentVtxoVw.Redeemed, - &i.PaymentVtxoVw.Swept, - &i.PaymentVtxoVw.ExpireAt, - &i.PaymentVtxoVw.CreatedAt, - &i.PaymentVtxoVw.PaymentID, - &i.PaymentVtxoVw.RedeemTx, + &i.RequestReceiverVw.RequestID, + &i.RequestReceiverVw.Pubkey, + &i.RequestReceiverVw.OnchainAddress, + &i.RequestReceiverVw.Amount, + &i.RequestVtxoVw.Txid, + &i.RequestVtxoVw.Vout, + &i.RequestVtxoVw.Pubkey, + &i.RequestVtxoVw.Amount, + &i.RequestVtxoVw.RoundTx, + &i.RequestVtxoVw.SpentBy, + &i.RequestVtxoVw.Spent, + &i.RequestVtxoVw.Redeemed, + &i.RequestVtxoVw.Swept, + &i.RequestVtxoVw.ExpireAt, + &i.RequestVtxoVw.CreatedAt, + &i.RequestVtxoVw.RequestID, + &i.RequestVtxoVw.RedeemTx, ); err != nil { return nil, err } @@ -732,7 +732,7 @@ func (q *Queries) SelectSweptRounds(ctx context.Context) ([]SelectSweptRoundsRow } const selectVtxoByOutpoint = `-- name: SelectVtxoByOutpoint :one -SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo +SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.round_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.request_id, vtxo.redeem_tx FROM vtxo WHERE txid = ? AND vout = ? ` @@ -753,50 +753,50 @@ func (q *Queries) SelectVtxoByOutpoint(ctx context.Context, arg SelectVtxoByOutp &i.Vtxo.Vout, &i.Vtxo.Pubkey, &i.Vtxo.Amount, - &i.Vtxo.PoolTx, + &i.Vtxo.RoundTx, &i.Vtxo.SpentBy, &i.Vtxo.Spent, &i.Vtxo.Redeemed, &i.Vtxo.Swept, &i.Vtxo.ExpireAt, &i.Vtxo.CreatedAt, - &i.Vtxo.PaymentID, + &i.Vtxo.RequestID, &i.Vtxo.RedeemTx, ) return i, err } -const selectVtxosByPoolTxid = `-- name: SelectVtxosByPoolTxid :many -SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.pool_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.payment_id, vtxo.redeem_tx FROM vtxo -WHERE pool_tx = ? +const selectVtxosByRoundTxid = `-- name: SelectVtxosByRoundTxid :many +SELECT vtxo.txid, vtxo.vout, vtxo.pubkey, vtxo.amount, vtxo.round_tx, vtxo.spent_by, vtxo.spent, vtxo.redeemed, vtxo.swept, vtxo.expire_at, vtxo.created_at, vtxo.request_id, vtxo.redeem_tx FROM vtxo +WHERE round_tx = ? ` -type SelectVtxosByPoolTxidRow struct { +type SelectVtxosByRoundTxidRow struct { Vtxo Vtxo } -func (q *Queries) SelectVtxosByPoolTxid(ctx context.Context, poolTx string) ([]SelectVtxosByPoolTxidRow, error) { - rows, err := q.db.QueryContext(ctx, selectVtxosByPoolTxid, poolTx) +func (q *Queries) SelectVtxosByRoundTxid(ctx context.Context, roundTx string) ([]SelectVtxosByRoundTxidRow, error) { + rows, err := q.db.QueryContext(ctx, selectVtxosByRoundTxid, roundTx) if err != nil { return nil, err } defer rows.Close() - var items []SelectVtxosByPoolTxidRow + var items []SelectVtxosByRoundTxidRow for rows.Next() { - var i SelectVtxosByPoolTxidRow + var i SelectVtxosByRoundTxidRow if err := rows.Scan( &i.Vtxo.Txid, &i.Vtxo.Vout, &i.Vtxo.Pubkey, &i.Vtxo.Amount, - &i.Vtxo.PoolTx, + &i.Vtxo.RoundTx, &i.Vtxo.SpentBy, &i.Vtxo.Spent, &i.Vtxo.Redeemed, &i.Vtxo.Swept, &i.Vtxo.ExpireAt, &i.Vtxo.CreatedAt, - &i.Vtxo.PaymentID, + &i.Vtxo.RequestID, &i.Vtxo.RedeemTx, ); err != nil { return nil, err @@ -868,18 +868,18 @@ func (q *Queries) UpdateVtxoExpireAt(ctx context.Context, arg UpdateVtxoExpireAt return err } -const updateVtxoPaymentId = `-- name: UpdateVtxoPaymentId :exec -UPDATE vtxo SET payment_id = ? WHERE txid = ? AND vout = ? +const updateVtxoRequestId = `-- name: UpdateVtxoRequestId :exec +UPDATE vtxo SET request_id = ? WHERE txid = ? AND vout = ? ` -type UpdateVtxoPaymentIdParams struct { - PaymentID sql.NullString +type UpdateVtxoRequestIdParams struct { + RequestID sql.NullString Txid string Vout int64 } -func (q *Queries) UpdateVtxoPaymentId(ctx context.Context, arg UpdateVtxoPaymentIdParams) error { - _, err := q.db.ExecContext(ctx, updateVtxoPaymentId, arg.PaymentID, arg.Txid, arg.Vout) +func (q *Queries) UpdateVtxoRequestId(ctx context.Context, arg UpdateVtxoRequestIdParams) error { + _, err := q.db.ExecContext(ctx, updateVtxoRequestId, arg.RequestID, arg.Txid, arg.Vout) return err } @@ -916,31 +916,16 @@ func (q *Queries) UpsertEntityVtxo(ctx context.Context, arg UpsertEntityVtxoPara return err } -const upsertPayment = `-- name: UpsertPayment :exec -INSERT INTO payment (id, round_id) VALUES (?, ?) -ON CONFLICT(id) DO UPDATE SET round_id = EXCLUDED.round_id -` - -type UpsertPaymentParams struct { - ID string - RoundID string -} - -func (q *Queries) UpsertPayment(ctx context.Context, arg UpsertPaymentParams) error { - _, err := q.db.ExecContext(ctx, upsertPayment, arg.ID, arg.RoundID) - return err -} - const upsertReceiver = `-- name: UpsertReceiver :exec -INSERT INTO receiver (payment_id, pubkey, onchain_address, amount) VALUES (?, ?, ?, ?) -ON CONFLICT(payment_id, pubkey, onchain_address) DO UPDATE SET +INSERT INTO receiver (request_id, pubkey, onchain_address, amount) VALUES (?, ?, ?, ?) +ON CONFLICT(request_id, pubkey, onchain_address) DO UPDATE SET amount = EXCLUDED.amount, pubkey = EXCLUDED.pubkey, onchain_address = EXCLUDED.onchain_address ` type UpsertReceiverParams struct { - PaymentID string + RequestID string Pubkey sql.NullString OnchainAddress sql.NullString Amount int64 @@ -948,7 +933,7 @@ type UpsertReceiverParams struct { func (q *Queries) UpsertReceiver(ctx context.Context, arg UpsertReceiverParams) error { _, err := q.db.ExecContext(ctx, upsertReceiver, - arg.PaymentID, + arg.RequestID, arg.Pubkey, arg.OnchainAddress, arg.Amount, @@ -1057,12 +1042,27 @@ func (q *Queries) UpsertTransaction(ctx context.Context, arg UpsertTransactionPa return err } +const upsertTxRequest = `-- name: UpsertTxRequest :exec +INSERT INTO tx_request (id, round_id) VALUES (?, ?) +ON CONFLICT(id) DO UPDATE SET round_id = EXCLUDED.round_id +` + +type UpsertTxRequestParams struct { + ID string + RoundID string +} + +func (q *Queries) UpsertTxRequest(ctx context.Context, arg UpsertTxRequestParams) error { + _, err := q.db.ExecContext(ctx, upsertTxRequest, arg.ID, arg.RoundID) + return err +} + const upsertVtxo = `-- name: UpsertVtxo :exec -INSERT INTO vtxo (txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, created_at, redeem_tx) +INSERT INTO vtxo (txid, vout, pubkey, amount, round_tx, spent_by, spent, redeemed, swept, expire_at, created_at, redeem_tx) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET pubkey = EXCLUDED.pubkey, amount = EXCLUDED.amount, - pool_tx = EXCLUDED.pool_tx, + round_tx = EXCLUDED.round_tx, spent_by = EXCLUDED.spent_by, spent = EXCLUDED.spent, redeemed = EXCLUDED.redeemed, @@ -1077,7 +1077,7 @@ type UpsertVtxoParams struct { Vout int64 Pubkey string Amount int64 - PoolTx string + RoundTx string SpentBy string Spent bool Redeemed bool @@ -1093,7 +1093,7 @@ func (q *Queries) UpsertVtxo(ctx context.Context, arg UpsertVtxoParams) error { arg.Vout, arg.Pubkey, arg.Amount, - arg.PoolTx, + arg.RoundTx, arg.SpentBy, arg.Spent, arg.Redeemed, diff --git a/server/internal/infrastructure/db/sqlite/sqlc/query.sql b/server/internal/infrastructure/db/sqlite/sqlc/query.sql index 636c180..ca4058e 100644 --- a/server/internal/infrastructure/db/sqlite/sqlc/query.sql +++ b/server/internal/infrastructure/db/sqlite/sqlc/query.sql @@ -39,70 +39,70 @@ ON CONFLICT(id) DO UPDATE SET version = EXCLUDED.version, swept = EXCLUDED.swept; --- name: UpsertPayment :exec -INSERT INTO payment (id, round_id) VALUES (?, ?) +-- name: UpsertTxRequest :exec +INSERT INTO tx_request (id, round_id) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET round_id = EXCLUDED.round_id; -- name: UpsertReceiver :exec -INSERT INTO receiver (payment_id, pubkey, onchain_address, amount) VALUES (?, ?, ?, ?) -ON CONFLICT(payment_id, pubkey, onchain_address) DO UPDATE SET +INSERT INTO receiver (request_id, pubkey, onchain_address, amount) VALUES (?, ?, ?, ?) +ON CONFLICT(request_id, pubkey, onchain_address) DO UPDATE SET amount = EXCLUDED.amount, pubkey = EXCLUDED.pubkey, onchain_address = EXCLUDED.onchain_address; --- name: UpdateVtxoPaymentId :exec -UPDATE vtxo SET payment_id = ? WHERE txid = ? AND vout = ?; +-- name: UpdateVtxoRequestId :exec +UPDATE vtxo SET request_id = ? WHERE txid = ? AND vout = ?; -- name: SelectRoundWithRoundId :many SELECT sqlc.embed(round), - sqlc.embed(round_payment_vw), + sqlc.embed(round_request_vw), sqlc.embed(round_tx_vw), - sqlc.embed(payment_receiver_vw), - sqlc.embed(payment_vtxo_vw) + sqlc.embed(request_receiver_vw), + sqlc.embed(request_vtxo_vw) FROM round - LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id + LEFT OUTER JOIN round_request_vw ON round.id=round_request_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id - LEFT OUTER JOIN payment_receiver_vw ON round_payment_vw.id=payment_receiver_vw.payment_id - LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id + LEFT OUTER JOIN request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id + LEFT OUTER JOIN request_vtxo_vw ON round_request_vw.id=request_vtxo_vw.request_id WHERE round.id = ?; -- name: SelectRoundWithRoundTxId :many SELECT sqlc.embed(round), - sqlc.embed(round_payment_vw), + sqlc.embed(round_request_vw), sqlc.embed(round_tx_vw), - sqlc.embed(payment_receiver_vw), - sqlc.embed(payment_vtxo_vw) + sqlc.embed(request_receiver_vw), + sqlc.embed(request_vtxo_vw) FROM round - LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id + LEFT OUTER JOIN round_request_vw ON round.id=round_request_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id - LEFT OUTER JOIN payment_receiver_vw ON round_payment_vw.id=payment_receiver_vw.payment_id - LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id + LEFT OUTER JOIN request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id + LEFT OUTER JOIN request_vtxo_vw ON round_request_vw.id=request_vtxo_vw.request_id WHERE round.txid = ?; -- name: SelectSweepableRounds :many SELECT sqlc.embed(round), - sqlc.embed(round_payment_vw), + sqlc.embed(round_request_vw), sqlc.embed(round_tx_vw), - sqlc.embed(payment_receiver_vw), - sqlc.embed(payment_vtxo_vw) + sqlc.embed(request_receiver_vw), + sqlc.embed(request_vtxo_vw) FROM round - LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id + LEFT OUTER JOIN round_request_vw ON round.id=round_request_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id - LEFT OUTER JOIN payment_receiver_vw ON round_payment_vw.id=payment_receiver_vw.payment_id - LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id + LEFT OUTER JOIN request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id + LEFT OUTER JOIN request_vtxo_vw ON round_request_vw.id=request_vtxo_vw.request_id WHERE round.swept = false AND round.ended = true AND round.failed = false; -- name: SelectSweptRounds :many SELECT sqlc.embed(round), - sqlc.embed(round_payment_vw), + sqlc.embed(round_request_vw), sqlc.embed(round_tx_vw), - sqlc.embed(payment_receiver_vw), - sqlc.embed(payment_vtxo_vw) + sqlc.embed(request_receiver_vw), + sqlc.embed(request_vtxo_vw) FROM round - LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id + LEFT OUTER JOIN round_request_vw ON round.id=round_request_vw.round_id LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id - LEFT OUTER JOIN payment_receiver_vw ON round_payment_vw.id=payment_receiver_vw.payment_id - LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id + LEFT OUTER JOIN request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id + LEFT OUTER JOIN request_vtxo_vw ON round_request_vw.id=request_vtxo_vw.request_id WHERE round.swept = true AND round.failed = false AND round.ended = true AND round.connector_address <> ''; -- name: SelectRoundIdsInRange :many @@ -112,11 +112,11 @@ SELECT id FROM round WHERE starting_timestamp > ? AND starting_timestamp < ?; SELECT id FROM round; -- name: UpsertVtxo :exec -INSERT INTO vtxo (txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, created_at, redeem_tx) +INSERT INTO vtxo (txid, vout, pubkey, amount, round_tx, spent_by, spent, redeemed, swept, expire_at, created_at, redeem_tx) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET pubkey = EXCLUDED.pubkey, amount = EXCLUDED.amount, - pool_tx = EXCLUDED.pool_tx, + round_tx = EXCLUDED.round_tx, spent_by = EXCLUDED.spent_by, spent = EXCLUDED.spent, redeemed = EXCLUDED.redeemed, @@ -141,9 +141,9 @@ WHERE redeemed = false AND pubkey = ?; SELECT sqlc.embed(vtxo) FROM vtxo WHERE txid = ? AND vout = ?; --- name: SelectVtxosByPoolTxid :many +-- name: SelectVtxosByRoundTxid :many SELECT sqlc.embed(vtxo) FROM vtxo -WHERE pool_tx = ?; +WHERE round_tx = ?; -- name: MarkVtxoAsRedeemed :exec UPDATE vtxo SET redeemed = true WHERE txid = ? AND vout = ?; diff --git a/server/internal/infrastructure/db/sqlite/vtxo_repo.go b/server/internal/infrastructure/db/sqlite/vtxo_repo.go index f61b3ed..c3484c4 100644 --- a/server/internal/infrastructure/db/sqlite/vtxo_repo.go +++ b/server/internal/infrastructure/db/sqlite/vtxo_repo.go @@ -42,9 +42,9 @@ func (v *vxtoRepository) AddVtxos(ctx context.Context, vtxos []domain.Vtxo) erro ctx, queries.UpsertVtxoParams{ Txid: vtxo.Txid, Vout: int64(vtxo.VOut), - Pubkey: vtxo.Pubkey, + Pubkey: vtxo.PubKey, Amount: int64(vtxo.Amount), - PoolTx: vtxo.RoundTxid, + RoundTx: vtxo.RoundTxid, SpentBy: vtxo.SpentBy, Spent: vtxo.Spent, Redeemed: vtxo.Redeemed, @@ -150,7 +150,7 @@ func (v *vxtoRepository) GetVtxos(ctx context.Context, outpoints []domain.VtxoKe } func (v *vxtoRepository) GetVtxosForRound(ctx context.Context, txid string) ([]domain.Vtxo, error) { - res, err := v.querier.SelectVtxosByPoolTxid(ctx, txid) + res, err := v.querier.SelectVtxosByRoundTxid(ctx, txid) if err != nil { return nil, err } @@ -251,8 +251,8 @@ func rowToVtxo(row queries.Vtxo) domain.Vtxo { VOut: uint32(row.Vout), }, Amount: uint64(row.Amount), - Pubkey: row.Pubkey, - RoundTxid: row.PoolTx, + PubKey: row.Pubkey, + RoundTxid: row.RoundTx, SpentBy: row.SpentBy, Spent: row.Spent, Redeemed: row.Redeemed, diff --git a/server/internal/infrastructure/tx-builder/covenant/builder.go b/server/internal/infrastructure/tx-builder/covenant/builder.go index 996eaca..bc5a73d 100644 --- a/server/internal/infrastructure/tx-builder/covenant/builder.go +++ b/server/internal/infrastructure/tx-builder/covenant/builder.go @@ -315,41 +315,41 @@ func (b *txBuilder) VerifyForfeitTxs(vtxos []domain.Vtxo, connectors []string, f } func (b *txBuilder) BuildRoundTx( - aspPubkey *secp256k1.PublicKey, - payments []domain.Payment, + serverPubkey *secp256k1.PublicKey, + requests []domain.TxRequest, boardingInputs []ports.BoardingInput, sweptRounds []domain.Round, _ ...*secp256k1.PublicKey, // cosigners are not used in the covenant -) (roundTx string, congestionTree tree.CongestionTree, connectorAddress string, connectors []string, err error) { - // The creation of the tree and the pool tx are tightly coupled: +) (roundTx string, vtxoTree tree.VtxoTree, connectorAddress string, connectors []string, err error) { + // The creation of the tree and the round tx are tightly coupled: // - building the tree requires knowing the shared outpoint (txid:vout) - // - building the pool tx requires knowing the shared output script and amount + // - building the round tx requires knowing the shared output script and amount // The idea here is to first create all the data for the outputs of the txs - // of the congestion tree to calculate the shared output script and amount. - // With these data the pool tx can be created, and once the shared utxo - // outpoint is obtained, the congestion tree can be finally created. + // of the vtxo tree to calculate the shared output script and amount. + // With these data the round tx can be created, and once the shared utxo + // outpoint is obtained, the vtxo tree can be finally created. // The factory function `treeFactoryFn` returned below holds all outputs data // generated in the process and takes the shared utxo outpoint as argument. - // This is safe as the memory allocated for `craftCongestionTree` is freed - // only after `BuildPoolTx` returns. + // This is safe as the memory allocated for `BuildVtxoTree` is flushed + // only after `BuildRoundTx` returns. var sharedOutputScript []byte var sharedOutputAmount uint64 var treeFactoryFn tree.TreeFactory - if !isOnchainOnly(payments) { + if !isOnchainOnly(requests) { feeSatsPerNode, err := b.wallet.MinRelayFee(context.Background(), uint64(common.CovenantTreeTxSize)) if err != nil { return "", nil, "", nil, err } - vtxosLeaves, err := getOutputVtxosLeaves(payments) + vtxosLeaves, err := getOutputVtxosLeaves(requests) if err != nil { return "", nil, "", nil, err } - treeFactoryFn, sharedOutputScript, sharedOutputAmount, err = tree.CraftCongestionTree( - b.onchainNetwork().AssetID, aspPubkey, vtxosLeaves, feeSatsPerNode, b.roundLifetime, + treeFactoryFn, sharedOutputScript, sharedOutputAmount, err = tree.BuildVtxoTree( + b.onchainNetwork().AssetID, serverPubkey, vtxosLeaves, feeSatsPerNode, b.roundLifetime, ) if err != nil { return "", nil, "", nil, err @@ -361,8 +361,8 @@ func (b *txBuilder) BuildRoundTx( return } - ptx, err := b.createPoolTx( - sharedOutputAmount, sharedOutputScript, payments, boardingInputs, aspPubkey, connectorAddress, sweptRounds, + ptx, err := b.createRoundTx( + sharedOutputAmount, sharedOutputScript, requests, boardingInputs, serverPubkey, connectorAddress, sweptRounds, ) if err != nil { return @@ -374,7 +374,7 @@ func (b *txBuilder) BuildRoundTx( } if treeFactoryFn != nil { - congestionTree, err = treeFactoryFn(psetv2.InputArgs{ + vtxoTree, err = treeFactoryFn(psetv2.InputArgs{ Txid: unsignedTx.TxHash().String(), TxIndex: 0, }) @@ -388,7 +388,7 @@ func (b *txBuilder) BuildRoundTx( return } - if countSpentVtxos(payments) <= 0 { + if countSpentVtxos(requests) <= 0 { return } @@ -402,7 +402,7 @@ func (b *txBuilder) BuildRoundTx( return "", nil, "", nil, err } - connectorsPsets, err := b.createConnectors(roundTx, payments, connectorAddress, connectorAmount, connectorFeeAmount) + connectorsPsets, err := b.createConnectors(roundTx, requests, connectorAddress, connectorAmount, connectorFeeAmount) if err != nil { return "", nil, "", nil, err } @@ -477,7 +477,7 @@ func (b *txBuilder) verifyTapscriptPartialSigs(pset *psetv2.Pset) (bool, error) utx, _ := pset.UnsignedTx() txid := utx.TxHash().String() - aspPublicKey, err := b.wallet.GetPubkey(context.Background()) + serverPubkey, err := b.wallet.GetPubkey(context.Background()) if err != nil { return false, err } @@ -511,8 +511,8 @@ func (b *txBuilder) verifyTapscriptPartialSigs(pset *psetv2.Pset) (bool, error) } } - // we don't need to check if ASP signed - keys[hex.EncodeToString(schnorr.SerializePubKey(aspPublicKey))] = true + // we don't need to check if server signed + keys[hex.EncodeToString(schnorr.SerializePubKey(serverPubkey))] = true rootHash := tapLeaf.ControlBlock.RootHash(tapLeaf.Script) tapKeyFromControlBlock := taproot.ComputeTaprootOutputKey(tree.UnspendableKey(), rootHash[:]) @@ -629,15 +629,15 @@ func (b *txBuilder) FinalizeAndExtract(tx string) (string, error) { } func (b *txBuilder) FindLeaves( - congestionTree tree.CongestionTree, + vtxoTree tree.VtxoTree, fromtxid string, fromvout uint32, ) ([]tree.Node, error) { - allLeaves := congestionTree.Leaves() + allLeaves := vtxoTree.Leaves() foundLeaves := make([]tree.Node, 0) for _, leaf := range allLeaves { - branch, err := congestionTree.Branch(leaf.Txid) + branch, err := vtxoTree.Branch(leaf.Txid) if err != nil { return nil, err } @@ -669,16 +669,16 @@ func (b *txBuilder) FindLeaves( return foundLeaves, nil } -func (b *txBuilder) createPoolTx( +func (b *txBuilder) createRoundTx( sharedOutputAmount uint64, sharedOutputScript []byte, - payments []domain.Payment, + requests []domain.TxRequest, boardingInputs []ports.BoardingInput, - aspPubKey *secp256k1.PublicKey, + serverPubkey *secp256k1.PublicKey, connectorAddress string, sweptRounds []domain.Round, ) (*psetv2.Pset, error) { - aspScript, err := p2wpkhScript(aspPubKey, b.onchainNetwork()) + serverScript, err := p2wpkhScript(serverPubkey, b.onchainNetwork()) if err != nil { return nil, err } @@ -698,7 +698,7 @@ func (b *txBuilder) createPoolTx( return nil, err } - nbOfInputs := countSpentVtxos(payments) + nbOfInputs := countSpentVtxos(requests) connectorsAmount := (dustAmount + connectorMinRelayFee) * nbOfInputs if nbOfInputs > 1 { connectorsAmount -= connectorMinRelayFee @@ -725,7 +725,7 @@ func (b *txBuilder) createPoolTx( }) } - onchainOutputs, err := getOnchainOutputs(payments, b.onchainNetwork()) + onchainOutputs, err := getOnchainOutputs(requests, b.onchainNetwork()) if err != nil { return nil, err } @@ -760,7 +760,7 @@ func (b *txBuilder) createPoolTx( outputs = append(outputs, psetv2.OutputArgs{ Asset: b.onchainNetwork().AssetID, Amount: change, - Script: aspScript, + Script: serverScript, }) } } @@ -878,7 +878,7 @@ func (b *txBuilder) createPoolTx( { Asset: b.onchainNetwork().AssetID, Amount: change, - Script: aspScript, + Script: serverScript, }, }); err != nil { return nil, err @@ -904,7 +904,7 @@ func (b *txBuilder) createPoolTx( { Asset: b.onchainNetwork().AssetID, Amount: change, - Script: aspScript, + Script: serverScript, }, }); err != nil { return nil, err @@ -1009,24 +1009,24 @@ func (b *txBuilder) VerifyAndCombinePartialTx(dest string, src string) (string, } func (b *txBuilder) createConnectors( - roundTx string, payments []domain.Payment, + roundTx string, requests []domain.TxRequest, connectorAddress string, connectorAmount, feeAmount uint64, ) ([]*psetv2.Pset, error) { txid, _ := getTxid(roundTx) - aspScript, err := address.ToOutputScript(connectorAddress) + serverScript, err := address.ToOutputScript(connectorAddress) if err != nil { return nil, err } connectorOutput := psetv2.OutputArgs{ Asset: b.onchainNetwork().AssetID, - Script: aspScript, + Script: serverScript, Amount: connectorAmount, } - numberOfConnectors := countSpentVtxos(payments) + numberOfConnectors := countSpentVtxos(requests) previousInput := psetv2.InputArgs{ Txid: txid, @@ -1035,7 +1035,7 @@ func (b *txBuilder) createConnectors( if numberOfConnectors == 1 { outputs := []psetv2.OutputArgs{connectorOutput} - connectorTx, err := craftConnectorTx(previousInput, aspScript, outputs, feeAmount) + connectorTx, err := craftConnectorTx(previousInput, serverScript, outputs, feeAmount) if err != nil { return nil, err } @@ -1056,11 +1056,11 @@ func (b *txBuilder) createConnectors( if totalConnectorAmount > 0 { outputs = append(outputs, psetv2.OutputArgs{ Asset: b.onchainNetwork().AssetID, - Script: aspScript, + Script: serverScript, Amount: totalConnectorAmount, }) } - connectorTx, err := craftConnectorTx(previousInput, aspScript, outputs, feeAmount) + connectorTx, err := craftConnectorTx(previousInput, serverScript, outputs, feeAmount) if err != nil { return nil, err } diff --git a/server/internal/infrastructure/tx-builder/covenant/builder_test.go b/server/internal/infrastructure/tx-builder/covenant/builder_test.go index b693756..956920f 100644 --- a/server/internal/infrastructure/tx-builder/covenant/builder_test.go +++ b/server/internal/infrastructure/tx-builder/covenant/builder_test.go @@ -53,30 +53,30 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } -func TestBuildPoolTx(t *testing.T) { +func TestBuildRoundTx(t *testing.T) { builder := txbuilder.NewTxBuilder( wallet, common.Liquid, roundLifetime, boardingExitDelay, ) - fixtures, err := parsePoolTxFixtures() + fixtures, err := parseRoundTxFixtures() require.NoError(t, err) require.NotEmpty(t, fixtures) if len(fixtures.Valid) > 0 { t.Run("valid", func(t *testing.T) { for _, f := range fixtures.Valid { - poolTx, congestionTree, connAddr, _, err := builder.BuildRoundTx( - pubkey, f.Payments, []ports.BoardingInput{}, []domain.Round{}, + roundTx, vtxoTree, connAddr, _, err := builder.BuildRoundTx( + pubkey, f.Requests, []ports.BoardingInput{}, []domain.Round{}, ) require.NoError(t, err) - require.NotEmpty(t, poolTx) - require.NotEmpty(t, congestionTree) + require.NotEmpty(t, roundTx) + require.NotEmpty(t, vtxoTree) require.Equal(t, connectorAddress, connAddr) - require.Equal(t, f.ExpectedNumOfNodes, congestionTree.NumberOfNodes()) - require.Len(t, congestionTree.Leaves(), f.ExpectedNumOfLeaves) + require.Equal(t, f.ExpectedNumOfNodes, vtxoTree.NumberOfNodes()) + require.Len(t, vtxoTree.Leaves(), f.ExpectedNumOfLeaves) - err = tree.ValidateCongestionTree( - congestionTree, poolTx, pubkey, roundLifetime, + err = tree.ValidateVtxoTree( + vtxoTree, roundTx, pubkey, roundLifetime, ) require.NoError(t, err) } @@ -86,13 +86,13 @@ func TestBuildPoolTx(t *testing.T) { if len(fixtures.Invalid) > 0 { t.Run("invalid", func(t *testing.T) { for _, f := range fixtures.Invalid { - poolTx, congestionTree, connAddr, _, err := builder.BuildRoundTx( - pubkey, f.Payments, []ports.BoardingInput{}, []domain.Round{}, + roundTx, vtxoTree, connAddr, _, err := builder.BuildRoundTx( + pubkey, f.Requests, []ports.BoardingInput{}, []domain.Round{}, ) require.EqualError(t, err, f.ExpectedErr) - require.Empty(t, poolTx) + require.Empty(t, roundTx) require.Empty(t, connAddr) - require.Empty(t, congestionTree) + require.Empty(t, vtxoTree) } }) } @@ -117,19 +117,19 @@ func randomHex(len int) string { return hex.EncodeToString(buf) } -type poolTxFixtures struct { +type roundTxFixtures struct { Valid []struct { - Payments []domain.Payment + Requests []domain.TxRequest ExpectedNumOfNodes int ExpectedNumOfLeaves int } Invalid []struct { - Payments []domain.Payment + Requests []domain.TxRequest ExpectedErr string } } -func parsePoolTxFixtures() (*poolTxFixtures, error) { +func parseRoundTxFixtures() (*roundTxFixtures, error) { file, err := os.ReadFile("testdata/fixtures.json") if err != nil { return nil, err @@ -139,9 +139,9 @@ func parsePoolTxFixtures() (*poolTxFixtures, error) { return nil, err } - vv := v["buildPoolTx"].(map[string]interface{}) + vv := v["buildRoundTx"].(map[string]interface{}) file, _ = json.Marshal(vv) - var fixtures poolTxFixtures + var fixtures roundTxFixtures if err := json.Unmarshal(file, &fixtures); err != nil { return nil, err } diff --git a/server/internal/infrastructure/tx-builder/covenant/testdata/fixtures.json b/server/internal/infrastructure/tx-builder/covenant/testdata/fixtures.json index 1f88af0..33f365e 100644 --- a/server/internal/infrastructure/tx-builder/covenant/testdata/fixtures.json +++ b/server/internal/infrastructure/tx-builder/covenant/testdata/fixtures.json @@ -1,8 +1,8 @@ { - "buildPoolTx": { + "buildRoundTx": { "valid": [ { - "payments": [ + "requests": [ { "id": "0", "inputs": [ @@ -26,7 +26,7 @@ "expectedNumOfLeaves": 1 }, { - "payments": [ + "requests": [ { "id": "0", "inputs": [ @@ -54,7 +54,7 @@ "expectedNumOfLeaves": 2 }, { - "payments": [ + "requests": [ { "id": "0", "inputs": [ @@ -126,7 +126,7 @@ "expectedNumOfLeaves": 6 }, { - "payments": [ + "requests": [ { "id": "a242cdd8-f3d5-46c0-ae98-94135a2bee3f", "inputs": [ @@ -199,7 +199,7 @@ "buildForfeitTxs": { "valid": [ { - "payments": [ + "requests": [ { "id": "0", "inputs": [ @@ -230,8 +230,8 @@ ] } ], - "poolTx": "cHNldP8BAgQCAAAAAQQBAQEFAQMBBgEDAfsEAgAAAAABDiDk7dXxh4KQzgLO8i1ABtaLCe4aPL12GVhN1E9zM1ePLwEPBAAAAAABEAT/////AAEDCOgDAAAAAAAAAQQWABSNnpy01UJqd99eTg2M1IpdKId11gf8BHBzZXQCICWyUQcOKcoZBDzzPM1zJOLdqwPsxK4LXnfE/A5c9slaB/wEcHNldAgEAAAAAAABAwh4BQAAAAAAAAEEFgAUjZ6ctNVCanffXk4NjNSKXSiHddYH/ARwc2V0AiAlslEHDinKGQQ88zzNcyTi3asD7MSuC153xPwOXPbJWgf8BHBzZXQIBAAAAAAAAQMI9AEAAAAAAAABBAAH/ARwc2V0AiAlslEHDinKGQQ88zzNcyTi3asD7MSuC153xPwOXPbJWgf8BHBzZXQIBAAAAAAA", - "poolTxid": "7981fce656f266472cc742444527cb32a8bed8c90fed6d47adbfc4c8780d4d9a", + "roundTx": "cHNldP8BAgQCAAAAAQQBAQEFAQMBBgEDAfsEAgAAAAABDiDk7dXxh4KQzgLO8i1ABtaLCe4aPL12GVhN1E9zM1ePLwEPBAAAAAABEAT/////AAEDCOgDAAAAAAAAAQQWABSNnpy01UJqd99eTg2M1IpdKId11gf8BHBzZXQCICWyUQcOKcoZBDzzPM1zJOLdqwPsxK4LXnfE/A5c9slaB/wEcHNldAgEAAAAAAABAwh4BQAAAAAAAAEEFgAUjZ6ctNVCanffXk4NjNSKXSiHddYH/ARwc2V0AiAlslEHDinKGQQ88zzNcyTi3asD7MSuC153xPwOXPbJWgf8BHBzZXQIBAAAAAAAAQMI9AEAAAAAAAABBAAH/ARwc2V0AiAlslEHDinKGQQ88zzNcyTi3asD7MSuC153xPwOXPbJWgf8BHBzZXQIBAAAAAAA", + "roundTxid": "7981fce656f266472cc742444527cb32a8bed8c90fed6d47adbfc4c8780d4d9a", "expectedNumOfForfeitTxs": 4, "expectedNumOfConnectors": 1 } diff --git a/server/internal/infrastructure/tx-builder/covenant/utils.go b/server/internal/infrastructure/tx-builder/covenant/utils.go index c962531..ef78399 100644 --- a/server/internal/infrastructure/tx-builder/covenant/utils.go +++ b/server/internal/infrastructure/tx-builder/covenant/utils.go @@ -17,8 +17,8 @@ import ( "github.com/vulpemventures/go-elements/transaction" ) -func p2wpkhScript(publicKey *secp256k1.PublicKey, net *network.Network) ([]byte, error) { - payment := payment.FromPublicKey(publicKey, net, nil) +func p2wpkhScript(pubkey *secp256k1.PublicKey, net *network.Network) ([]byte, error) { + payment := payment.FromPublicKey(pubkey, net, nil) addr, err := payment.WitnessPubKeyHash() if err != nil { return nil, err @@ -46,11 +46,11 @@ func getPsetId(pset *psetv2.Pset) (string, error) { } func getOnchainOutputs( - payments []domain.Payment, net *network.Network, + requests []domain.TxRequest, net *network.Network, ) ([]psetv2.OutputArgs, error) { outputs := make([]psetv2.OutputArgs, 0) - for _, payment := range payments { - for _, receiver := range payment.Receivers { + for _, request := range requests { + for _, receiver := range request.Receivers { if receiver.IsOnchain() { receiverScript, err := address.ToOutputScript(receiver.OnchainAddress) if err != nil { @@ -69,14 +69,14 @@ func getOnchainOutputs( } func getOutputVtxosLeaves( - payments []domain.Payment, + requests []domain.TxRequest, ) ([]tree.VtxoLeaf, error) { receivers := make([]tree.VtxoLeaf, 0) - for _, payment := range payments { - for _, receiver := range payment.Receivers { + for _, request := range requests { + for _, receiver := range request.Receivers { if !receiver.IsOnchain() { receivers = append(receivers, tree.VtxoLeaf{ - Pubkey: receiver.Pubkey, + PubKey: receiver.PubKey, Amount: receiver.Amount, }) } @@ -104,10 +104,10 @@ func toWitnessUtxo(in ports.TxInput) (*transaction.TxOutput, error) { return transaction.NewTxOutput(assetBytes, valueBytes, scriptBytes), nil } -func countSpentVtxos(payments []domain.Payment) uint64 { +func countSpentVtxos(requests []domain.TxRequest) uint64 { var sum uint64 - for _, payment := range payments { - sum += uint64(len(payment.Inputs)) + for _, request := range requests { + sum += uint64(len(request.Inputs)) } return sum } @@ -144,9 +144,9 @@ func addInputs( return nil } -func isOnchainOnly(payments []domain.Payment) bool { - for _, p := range payments { - for _, r := range p.Receivers { +func isOnchainOnly(requests []domain.TxRequest) bool { + for _, request := range requests { + for _, r := range request.Receivers { if !r.IsOnchain() { return false } diff --git a/server/internal/infrastructure/tx-builder/covenantless/builder.go b/server/internal/infrastructure/tx-builder/covenantless/builder.go index 6cc3a99..ff4ffef 100644 --- a/server/internal/infrastructure/tx-builder/covenantless/builder.go +++ b/server/internal/infrastructure/tx-builder/covenantless/builder.go @@ -58,7 +58,7 @@ func (b *txBuilder) VerifyTapscriptPartialSigs(tx string) (bool, error) { func (b *txBuilder) verifyTapscriptPartialSigs(ptx *psbt.Packet) (bool, error) { txid := ptx.UnsignedTx.TxID() - aspPublicKey, err := b.wallet.GetPubkey(context.Background()) + serverPubkey, err := b.wallet.GetPubkey(context.Background()) if err != nil { return false, err } @@ -93,8 +93,8 @@ func (b *txBuilder) verifyTapscriptPartialSigs(ptx *psbt.Packet) (bool, error) { } } - // we don't need to check if ASP signed - keys[hex.EncodeToString(schnorr.SerializePubKey(aspPublicKey))] = true + // we don't need to check if server signed + keys[hex.EncodeToString(schnorr.SerializePubKey(serverPubkey))] = true if len(tapLeaf.ControlBlock) == 0 { return false, fmt.Errorf("missing control block for input %d", index) @@ -471,12 +471,12 @@ func (b *txBuilder) VerifyForfeitTxs(vtxos []domain.Vtxo, connectors []string, f } func (b *txBuilder) BuildRoundTx( - aspPubkey *secp256k1.PublicKey, - payments []domain.Payment, + serverPubkey *secp256k1.PublicKey, + requests []domain.TxRequest, boardingInputs []ports.BoardingInput, sweptRounds []domain.Round, cosigners ...*secp256k1.PublicKey, -) (roundTx string, congestionTree tree.CongestionTree, connectorAddress string, connectors []string, err error) { +) (roundTx string, vtxoTree tree.VtxoTree, connectorAddress string, connectors []string, err error) { var sharedOutputScript []byte var sharedOutputAmount int64 @@ -484,7 +484,7 @@ func (b *txBuilder) BuildRoundTx( return "", nil, "", nil, fmt.Errorf("missing cosigners") } - receivers, err := getOutputVtxosLeaves(payments) + receivers, err := getOutputVtxosLeaves(requests) if err != nil { return "", nil, "", nil, err } @@ -494,9 +494,9 @@ func (b *txBuilder) BuildRoundTx( return } - if !isOnchainOnly(payments) { + if !isOnchainOnly(requests) { sharedOutputScript, sharedOutputAmount, err = bitcointree.CraftSharedOutput( - cosigners, aspPubkey, receivers, feeAmount, b.roundLifetime, + cosigners, serverPubkey, receivers, feeAmount, b.roundLifetime, ) if err != nil { return @@ -509,7 +509,7 @@ func (b *txBuilder) BuildRoundTx( } ptx, err := b.createRoundTx( - sharedOutputAmount, sharedOutputScript, payments, boardingInputs, connectorAddress, sweptRounds, + sharedOutputAmount, sharedOutputScript, requests, boardingInputs, connectorAddress, sweptRounds, ) if err != nil { return @@ -520,21 +520,21 @@ func (b *txBuilder) BuildRoundTx( return } - if !isOnchainOnly(payments) { + if !isOnchainOnly(requests) { initialOutpoint := &wire.OutPoint{ Hash: ptx.UnsignedTx.TxHash(), Index: 0, } - congestionTree, err = bitcointree.CraftCongestionTree( - initialOutpoint, cosigners, aspPubkey, receivers, feeAmount, b.roundLifetime, + vtxoTree, err = bitcointree.BuildVtxoTree( + initialOutpoint, cosigners, serverPubkey, receivers, feeAmount, b.roundLifetime, ) if err != nil { return "", nil, "", nil, err } } - if countSpentVtxos(payments) <= 0 { + if countSpentVtxos(requests) <= 0 { return } @@ -553,7 +553,7 @@ func (b *txBuilder) BuildRoundTx( return "", nil, "", nil, err } - connectorsPsbts, err := b.createConnectors(roundTx, payments, connectorPkScript, minRelayFeeConnectorTx) + connectorsPsbts, err := b.createConnectors(roundTx, requests, connectorPkScript, minRelayFeeConnectorTx) if err != nil { return "", nil, "", nil, err } @@ -566,7 +566,7 @@ func (b *txBuilder) BuildRoundTx( connectors = append(connectors, b64) } - return roundTx, congestionTree, connectorAddress, connectors, nil + return roundTx, vtxoTree, connectorAddress, connectors, nil } func (b *txBuilder) GetSweepInput(node tree.Node) (lifetime int64, sweepInput ports.SweepInput, err error) { @@ -611,12 +611,12 @@ func (b *txBuilder) GetSweepInput(node tree.Node) (lifetime int64, sweepInput po return lifetime, sweepInput, nil } -func (b *txBuilder) FindLeaves(congestionTree tree.CongestionTree, fromtxid string, vout uint32) ([]tree.Node, error) { - allLeaves := congestionTree.Leaves() +func (b *txBuilder) FindLeaves(vtxoTree tree.VtxoTree, fromtxid string, vout uint32) ([]tree.Node, error) { + allLeaves := vtxoTree.Leaves() foundLeaves := make([]tree.Node, 0) for _, leaf := range allLeaves { - branch, err := congestionTree.Branch(leaf.Txid) + branch, err := vtxoTree.Branch(leaf.Txid) if err != nil { return nil, err } @@ -647,7 +647,7 @@ func (b *txBuilder) FindLeaves(congestionTree tree.CongestionTree, fromtxid stri func (b *txBuilder) createRoundTx( sharedOutputAmount int64, sharedOutputScript []byte, - payments []domain.Payment, + requests []domain.TxRequest, boardingInputs []ports.BoardingInput, connectorAddress string, sweptRounds []domain.Round, @@ -674,7 +674,7 @@ func (b *txBuilder) createRoundTx( connectorAmount := dustLimit - nbOfInputs := countSpentVtxos(payments) + nbOfInputs := countSpentVtxos(requests) connectorsAmount := (connectorAmount + connectorMinRelayFee) * nbOfInputs if nbOfInputs > 1 { connectorsAmount -= connectorMinRelayFee @@ -699,7 +699,7 @@ func (b *txBuilder) createRoundTx( }) } - onchainOutputs, err := getOnchainOutputs(payments, b.onchainNetwork()) + onchainOutputs, err := getOnchainOutputs(requests, b.onchainNetwork()) if err != nil { return nil, err } @@ -1021,9 +1021,9 @@ func (b *txBuilder) VerifyAndCombinePartialTx(dest string, src string) (string, } func (b *txBuilder) createConnectors( - poolTx string, payments []domain.Payment, connectorScript []byte, feeAmount uint64, + roundTx string, requests []domain.TxRequest, connectorScript []byte, feeAmount uint64, ) ([]*psbt.Packet, error) { - partialTx, err := psbt.NewFromRawBytes(strings.NewReader(poolTx), true) + partialTx, err := psbt.NewFromRawBytes(strings.NewReader(roundTx), true) if err != nil { return nil, err } @@ -1038,7 +1038,7 @@ func (b *txBuilder) createConnectors( Value: int64(connectorAmount), } - numberOfConnectors := countSpentVtxos(payments) + numberOfConnectors := countSpentVtxos(requests) previousInput := &wire.OutPoint{ Hash: partialTx.UnsignedTx.TxHash(), diff --git a/server/internal/infrastructure/tx-builder/covenantless/builder_test.go b/server/internal/infrastructure/tx-builder/covenantless/builder_test.go index 6121064..5398f14 100644 --- a/server/internal/infrastructure/tx-builder/covenantless/builder_test.go +++ b/server/internal/infrastructure/tx-builder/covenantless/builder_test.go @@ -55,12 +55,12 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } -func TestBuildPoolTx(t *testing.T) { +func TestBuildRoundTx(t *testing.T) { builder := txbuilder.NewTxBuilder( wallet, common.Bitcoin, roundLifetime, boardingExitDelay, ) - fixtures, err := parsePoolTxFixtures() + fixtures, err := parseRoundTxFixtures() require.NoError(t, err) require.NotEmpty(t, fixtures) @@ -68,25 +68,25 @@ func TestBuildPoolTx(t *testing.T) { t.Run("valid", func(t *testing.T) { for _, f := range fixtures.Valid { cosigners := make([]*secp256k1.PublicKey, 0) - for range f.Payments { + for range f.Requests { randKey, err := secp256k1.GeneratePrivateKey() require.NoError(t, err) cosigners = append(cosigners, randKey.PubKey()) } - poolTx, congestionTree, connAddr, _, err := builder.BuildRoundTx( - pubkey, f.Payments, []ports.BoardingInput{}, []domain.Round{}, cosigners..., + roundTx, vtxoTree, connAddr, _, err := builder.BuildRoundTx( + pubkey, f.Requests, []ports.BoardingInput{}, []domain.Round{}, cosigners..., ) require.NoError(t, err) - require.NotEmpty(t, poolTx) - require.NotEmpty(t, congestionTree) + require.NotEmpty(t, roundTx) + require.NotEmpty(t, vtxoTree) require.Equal(t, connectorAddress, connAddr) - require.Equal(t, f.ExpectedNumOfNodes, congestionTree.NumberOfNodes()) - require.Len(t, congestionTree.Leaves(), f.ExpectedNumOfLeaves) + require.Equal(t, f.ExpectedNumOfNodes, vtxoTree.NumberOfNodes()) + require.Len(t, vtxoTree.Leaves(), f.ExpectedNumOfLeaves) - err = bitcointree.ValidateCongestionTree( - congestionTree, poolTx, pubkey, roundLifetime, + err = bitcointree.ValidateVtxoTree( + vtxoTree, roundTx, pubkey, roundLifetime, ) require.NoError(t, err) } @@ -96,13 +96,13 @@ func TestBuildPoolTx(t *testing.T) { if len(fixtures.Invalid) > 0 { t.Run("invalid", func(t *testing.T) { for _, f := range fixtures.Invalid { - poolTx, congestionTree, connAddr, _, err := builder.BuildRoundTx( - pubkey, f.Payments, []ports.BoardingInput{}, []domain.Round{}, + roundTx, vtxoTree, connAddr, _, err := builder.BuildRoundTx( + pubkey, f.Requests, []ports.BoardingInput{}, []domain.Round{}, ) require.EqualError(t, err, f.ExpectedErr) - require.Empty(t, poolTx) + require.Empty(t, roundTx) require.Empty(t, connAddr) - require.Empty(t, congestionTree) + require.Empty(t, vtxoTree) } }) } @@ -127,19 +127,19 @@ func randomHex(len int) string { return hex.EncodeToString(buf) } -type poolTxFixtures struct { +type roundTxFixtures struct { Valid []struct { - Payments []domain.Payment + Requests []domain.TxRequest ExpectedNumOfNodes int ExpectedNumOfLeaves int } Invalid []struct { - Payments []domain.Payment + Requests []domain.TxRequest ExpectedErr string } } -func parsePoolTxFixtures() (*poolTxFixtures, error) { +func parseRoundTxFixtures() (*roundTxFixtures, error) { file, err := os.ReadFile("testdata/fixtures.json") if err != nil { return nil, err @@ -149,9 +149,9 @@ func parsePoolTxFixtures() (*poolTxFixtures, error) { return nil, err } - vv := v["buildPoolTx"].(map[string]interface{}) + vv := v["buildRoundTx"].(map[string]interface{}) file, _ = json.Marshal(vv) - var fixtures poolTxFixtures + var fixtures roundTxFixtures if err := json.Unmarshal(file, &fixtures); err != nil { return nil, err } diff --git a/server/internal/infrastructure/tx-builder/covenantless/testdata/fixtures.json b/server/internal/infrastructure/tx-builder/covenantless/testdata/fixtures.json index 30c4968..8dad2f7 100644 --- a/server/internal/infrastructure/tx-builder/covenantless/testdata/fixtures.json +++ b/server/internal/infrastructure/tx-builder/covenantless/testdata/fixtures.json @@ -1,8 +1,8 @@ { - "buildPoolTx": { + "buildRoundTx": { "valid": [ { - "payments": [ + "requests": [ { "id": "0", "inputs": [ @@ -26,7 +26,7 @@ "expectedNumOfLeaves": 1 }, { - "payments": [ + "requests": [ { "id": "0", "inputs": [ @@ -54,7 +54,7 @@ "expectedNumOfLeaves": 2 }, { - "payments": [ + "requests": [ { "id": "0", "inputs": [ @@ -126,7 +126,7 @@ "expectedNumOfLeaves": 6 }, { - "payments": [ + "requests": [ { "id": "a242cdd8-f3d5-46c0-ae98-94135a2bee3f", "inputs": [ @@ -199,7 +199,7 @@ "buildForfeitTxs": { "valid": [ { - "payments": [ + "requests": [ { "id": "a242cdd8-f3d5-46c0-ae98-94135a2bee3f", "inputs": [ @@ -263,8 +263,8 @@ ] } ], - "poolTx": "cHNidP8BALICAAAAAnonOnsJBkHUUaKf/7fdS0/sVyBCgDPusYzGSZZiXPbtAAAAAAD/////VLtr81ZII3QJnXgrIwgcnbsq3aa4L3qdHOAn2evlFtEAAAAAAP////8CohIAAAAAAAAiUSBZarBUuSIHnlkuIoel9MmvexqTGK8jCZaRjt8L+Pb3s+gDAAAAAAAAIlEgI95L4kHEn2fAA+vysD+RIR4eD3AIQwc+FyCInJ8HivYAAAAAAAEBIOgDAAAAAAAAF6kU6p9IboLvs92Dpp/Zbj8BE3V9oDyHAAEBIOgDAAAAAAAAF6kU6p9IboLvs92Dpp/Zbj8BE3V9oDyHAAAA", - "poolTxid": "7c0c10756cdb9ab8e605f1c82e25989761308cf4c60e6a6f42b72d46144c4ce0", + "roundTx": "cHNidP8BALICAAAAAnonOnsJBkHUUaKf/7fdS0/sVyBCgDPusYzGSZZiXPbtAAAAAAD/////VLtr81ZII3QJnXgrIwgcnbsq3aa4L3qdHOAn2evlFtEAAAAAAP////8CohIAAAAAAAAiUSBZarBUuSIHnlkuIoel9MmvexqTGK8jCZaRjt8L+Pb3s+gDAAAAAAAAIlEgI95L4kHEn2fAA+vysD+RIR4eD3AIQwc+FyCInJ8HivYAAAAAAAEBIOgDAAAAAAAAF6kU6p9IboLvs92Dpp/Zbj8BE3V9oDyHAAEBIOgDAAAAAAAAF6kU6p9IboLvs92Dpp/Zbj8BE3V9oDyHAAAA", + "roundTxid": "7c0c10756cdb9ab8e605f1c82e25989761308cf4c60e6a6f42b72d46144c4ce0", "expectedNumOfForfeitTxs": 25, "expectedNumOfConnectors": 4 } diff --git a/server/internal/infrastructure/tx-builder/covenantless/utils.go b/server/internal/infrastructure/tx-builder/covenantless/utils.go index 574a2f3..4a31d8f 100644 --- a/server/internal/infrastructure/tx-builder/covenantless/utils.go +++ b/server/internal/infrastructure/tx-builder/covenantless/utils.go @@ -12,11 +12,11 @@ import ( ) func getOnchainOutputs( - payments []domain.Payment, network *chaincfg.Params, + requests []domain.TxRequest, network *chaincfg.Params, ) ([]*wire.TxOut, error) { outputs := make([]*wire.TxOut, 0) - for _, payment := range payments { - for _, receiver := range payment.Receivers { + for _, request := range requests { + for _, receiver := range request.Receivers { if receiver.IsOnchain() { receiverAddr, err := btcutil.DecodeAddress(receiver.OnchainAddress, network) if err != nil { @@ -39,14 +39,14 @@ func getOnchainOutputs( } func getOutputVtxosLeaves( - payments []domain.Payment, + requests []domain.TxRequest, ) ([]tree.VtxoLeaf, error) { leaves := make([]tree.VtxoLeaf, 0) - for _, payment := range payments { - for _, receiver := range payment.Receivers { + for _, request := range requests { + for _, receiver := range request.Receivers { if !receiver.IsOnchain() { leaves = append(leaves, tree.VtxoLeaf{ - Pubkey: receiver.Pubkey, + PubKey: receiver.PubKey, Amount: receiver.Amount, }) } @@ -55,10 +55,10 @@ func getOutputVtxosLeaves( return leaves, nil } -func countSpentVtxos(payments []domain.Payment) uint64 { +func countSpentVtxos(requests []domain.TxRequest) uint64 { var sum uint64 - for _, payment := range payments { - sum += uint64(len(payment.Inputs)) + for _, request := range requests { + sum += uint64(len(request.Inputs)) } return sum } @@ -67,9 +67,9 @@ func taprootOutputScript(taprootKey *secp256k1.PublicKey) ([]byte, error) { return txscript.NewScriptBuilder().AddOp(txscript.OP_1).AddData(schnorr.SerializePubKey(taprootKey)).Script() } -func isOnchainOnly(payments []domain.Payment) bool { - for _, p := range payments { - for _, r := range p.Receivers { +func isOnchainOnly(requests []domain.TxRequest) bool { + for _, request := range requests { + for _, r := range request.Receivers { if !r.IsOnchain() { return false } diff --git a/server/internal/infrastructure/wallet/btc-embedded/psbt.go b/server/internal/infrastructure/wallet/btc-embedded/psbt.go index eab2a07..59e4ed9 100644 --- a/server/internal/infrastructure/wallet/btc-embedded/psbt.go +++ b/server/internal/infrastructure/wallet/btc-embedded/psbt.go @@ -73,7 +73,7 @@ func (s *service) signPsbt(packet *psbt.Packet, inputsToSign []int) ([]uint32, e isTaproot := txscript.IsPayToTaproot(in.WitnessUtxo.PkScript) if len(in.TaprootLeafScript) > 0 { - managedAddress = s.aspKeyAddr + managedAddress = s.serverKeyAddr } else { var err error managedAddress, _, _, err = s.wallet.ScriptForOutput(in.WitnessUtxo) diff --git a/server/internal/infrastructure/wallet/btc-embedded/wallet.go b/server/internal/infrastructure/wallet/btc-embedded/wallet.go index 4388e7a..3ed3944 100644 --- a/server/internal/infrastructure/wallet/btc-embedded/wallet.go +++ b/server/internal/infrastructure/wallet/btc-embedded/wallet.go @@ -74,8 +74,8 @@ const ( connectorAccount accountName = "default" // this account won't be restored by lnd, but it's not a problem cause it does not track any funds - // it's used to derive a constant public key to be used as "ASP key" in Vtxo scripts - aspKeyAccount accountName = "asp" + // it's used to derive a constant public key to be used as "server key" in Vtxo scripts + serverKeyAccount accountName = "server" // https://github.com/bitcoin/bitcoin/blob/439e58c4d8194ca37f70346727d31f52e69592ec/src/policy/policy.cpp#L23C8-L23C11 // biggest input size to compute the maximum dust amount @@ -112,8 +112,8 @@ type service struct { watchedScriptsLock sync.RWMutex watchedScripts map[string]struct{} - // holds the data related to the ASP key used in Vtxo scripts - aspKeyAddr waddrmgr.ManagedPubKeyAddress + // holds the data related to the server key used in Vtxo scripts + serverKeyAddr waddrmgr.ManagedPubKeyAddress isSynced bool syncedCh chan struct{} @@ -411,12 +411,12 @@ func (s *service) Unlock(_ context.Context, password string) error { return fmt.Errorf("failed to start wallet: %s", err) } - addrs, err := wallet.ListAddresses(string(aspKeyAccount), false) + addrs, err := wallet.ListAddresses(string(serverKeyAccount), false) if err != nil { return err } for info, addrs := range addrs { - if info.AccountName != string(aspKeyAccount) { + if info.AccountName != string(serverKeyAccount) { continue } @@ -443,7 +443,7 @@ func (s *service) Unlock(_ context.Context, password string) error { return fmt.Errorf("failed to cast address to managed pubkey address") } - s.aspKeyAddr = managedPubkeyAddr + s.serverKeyAddr = managedPubkeyAddr break } } @@ -556,7 +556,7 @@ func (s *service) GetPubkey(ctx context.Context) (*secp256k1.PublicKey, error) { if !s.isLoaded() { return nil, ErrNotLoaded } - return s.aspKeyAddr.PubKey(), nil + return s.serverKeyAddr.PubKey(), nil } func (s *service) GetForfeitAddress(ctx context.Context) (string, error) { @@ -1093,16 +1093,16 @@ func (s *service) GetTransaction(ctx context.Context, txid string) (string, erro } func (s *service) SignMessage(ctx context.Context, message []byte) ([]byte, error) { - if s.aspKeyAddr == nil { + if s.serverKeyAddr == nil { return nil, fmt.Errorf("wallet not initialized or locked") } - privKey, err := s.aspKeyAddr.PrivKey() + prvkey, err := s.serverKeyAddr.PrivKey() if err != nil { return nil, err } - sig, err := schnorr.Sign(privKey, message) + sig, err := schnorr.Sign(prvkey, message) if err != nil { return nil, err } @@ -1116,7 +1116,7 @@ func (s *service) VerifyMessageSignature(ctx context.Context, message, signature return false, err } - return sig.Verify(message, s.aspKeyAddr.PubKey()), nil + return sig.Verify(message, s.serverKeyAddr.PubKey()), nil } func (s *service) castNotification(tx *wtxmgr.TxRecord) map[string][]ports.VtxoWithValue { @@ -1187,7 +1187,7 @@ func (s *service) create(mnemonic, password string, addrGap uint32) error { defer wallet.InternalWallet().Lock() - if err := s.initAspKeyAccount(wallet); err != nil { + if err := s.initServerKeyAccount(wallet); err != nil { return err } @@ -1195,7 +1195,7 @@ func (s *service) create(mnemonic, password string, addrGap uint32) error { return fmt.Errorf("failed to start wallet: %s", err) } - if err := s.initAspKeyAddress(wallet); err != nil { + if err := s.initServerKeyAddress(wallet); err != nil { return err } @@ -1251,8 +1251,8 @@ func (s *service) listenToSynced() { } } -// initAspKeyAccount creates the asp key account if it doesn't exist -func (s *service) initAspKeyAccount(wallet *btcwallet.BtcWallet) error { +// initServerKeyAccount creates the server key account if it doesn't exist +func (s *service) initServerKeyAccount(wallet *btcwallet.BtcWallet) error { w := wallet.InternalWallet() p2trAccounts, err := w.Accounts(p2trKeyScope) @@ -1260,45 +1260,45 @@ func (s *service) initAspKeyAccount(wallet *btcwallet.BtcWallet) error { return fmt.Errorf("failed to list wallet accounts: %s", err) } - var aspKeyAccountNumber uint32 + var serverKeyAccountNumber uint32 if p2trAccounts != nil { for _, account := range p2trAccounts.Accounts { - if account.AccountName == string(aspKeyAccount) { - aspKeyAccountNumber = account.AccountNumber + if account.AccountName == string(serverKeyAccount) { + serverKeyAccountNumber = account.AccountNumber break } } } - if aspKeyAccountNumber == 0 { - log.Debug("creating asp key account") - aspKeyAccountNumber, err = w.NextAccount(p2trKeyScope, string(aspKeyAccount)) + if serverKeyAccountNumber == 0 { + log.Debug("creating server key account") + serverKeyAccountNumber, err = w.NextAccount(p2trKeyScope, string(serverKeyAccount)) if err != nil { - return fmt.Errorf("failed to create %s: %s", aspKeyAccount, err) + return fmt.Errorf("failed to create %s: %s", serverKeyAccount, err) } } - log.Debugf("key account number: %d", aspKeyAccountNumber) + log.Debugf("key account number: %d", serverKeyAccountNumber) return nil } -// initAspKeyAddress generates the asp key address if it doesn't exist -// it also cache the address in s.aspKeyAddr field -func (s *service) initAspKeyAddress(wallet *btcwallet.BtcWallet) error { - addrs, err := wallet.ListAddresses(string(aspKeyAccount), false) +// initServerKeyAddress generates the server key address if it doesn't exist +// it also cache the address in s.serverKeyAddr field +func (s *service) initServerKeyAddress(wallet *btcwallet.BtcWallet) error { + addrs, err := wallet.ListAddresses(string(serverKeyAccount), false) if err != nil { return err } if len(addrs) == 0 { - aspKeyAddr, err := wallet.NewAddress(lnwallet.TaprootPubkey, false, string(aspKeyAccount)) + serverKeyAddr, err := wallet.NewAddress(lnwallet.TaprootPubkey, false, string(serverKeyAccount)) if err != nil { return err } - addrInfos, err := wallet.AddressInfo(aspKeyAddr) + addrInfos, err := wallet.AddressInfo(serverKeyAddr) if err != nil { return err } @@ -1308,10 +1308,10 @@ func (s *service) initAspKeyAddress(wallet *btcwallet.BtcWallet) error { return fmt.Errorf("failed to cast address to managed pubkey address") } - s.aspKeyAddr = managedAddr + s.serverKeyAddr = managedAddr } else { for info, addrs := range addrs { - if info.AccountName != string(aspKeyAccount) { + if info.AccountName != string(serverKeyAccount) { continue } @@ -1338,7 +1338,7 @@ func (s *service) initAspKeyAddress(wallet *btcwallet.BtcWallet) error { return fmt.Errorf("failed to cast address to managed pubkey address") } - s.aspKeyAddr = managedPubkeyAddr + s.serverKeyAddr = managedPubkeyAddr break } } diff --git a/server/internal/interface/grpc/handlers/adminservice.go b/server/internal/interface/grpc/handlers/adminservice.go index 84d4ed8..5a1ea3f 100644 --- a/server/internal/interface/grpc/handlers/adminservice.go +++ b/server/internal/interface/grpc/handlers/adminservice.go @@ -3,6 +3,7 @@ package handlers import ( "context" "fmt" + "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" @@ -14,15 +15,15 @@ import ( type adminHandler struct { adminService application.AdminService - aspService application.Service + arkService application.Service noteUriPrefix string } func NewAdminHandler( - adminService application.AdminService, aspService application.Service, noteUriPrefix string, + adminService application.AdminService, arkService application.Service, noteUriPrefix string, ) arkv1.AdminServiceServer { - return &adminHandler{adminService, aspService, noteUriPrefix} + return &adminHandler{adminService, arkService, noteUriPrefix} } func (a *adminHandler) GetRoundDetails(ctx context.Context, req *arkv1.GetRoundDetailsRequest) (*arkv1.GetRoundDetailsResponse, error) { @@ -134,7 +135,7 @@ func (a *adminHandler) GetMarketHourConfig( ctx context.Context, request *arkv1.GetMarketHourConfigRequest, ) (*arkv1.GetMarketHourConfigResponse, error) { - config, err := a.aspService.GetMarketHourConfig(ctx) + config, err := a.arkService.GetMarketHourConfig(ctx) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -153,7 +154,7 @@ func (a *adminHandler) UpdateMarketHourConfig( ctx context.Context, req *arkv1.UpdateMarketHourConfigRequest, ) (*arkv1.UpdateMarketHourConfigResponse, error) { - if err := a.aspService.UpdateMarketHourConfig( + if err := a.arkService.UpdateMarketHourConfig( ctx, req.GetConfig().GetStartTime().AsTime(), req.GetConfig().GetEndTime().AsTime(), diff --git a/server/internal/interface/grpc/handlers/arkservice.go b/server/internal/interface/grpc/handlers/arkservice.go index ae2a01e..3e3ec13 100644 --- a/server/internal/interface/grpc/handlers/arkservice.go +++ b/server/internal/interface/grpc/handlers/arkservice.go @@ -36,7 +36,7 @@ func NewHandler(service application.Service) arkv1.ArkServiceServer { } go h.listenToEvents() - go h.listenToPaymentEvents() + go h.listenToTxEvents() return h } @@ -124,14 +124,14 @@ func (h *handler) RegisterInputsForNextRound( return nil, status.Error(codes.InvalidArgument, "cannot mix vtxos and notes") } - paymentID := "" + requestID := "" if len(vtxosInputs) > 0 { inputs, err := parseInputs(vtxosInputs) if err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } - paymentID, err = h.svc.SpendVtxos(ctx, inputs) + requestID, err = h.svc.SpendVtxos(ctx, inputs) if err != nil { return nil, err } @@ -142,7 +142,7 @@ func (h *handler) RegisterInputsForNextRound( if err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } - paymentID, err = h.svc.SpendNotes(ctx, notes) + requestID, err = h.svc.SpendNotes(ctx, notes) if err != nil { return nil, err } @@ -150,13 +150,13 @@ func (h *handler) RegisterInputsForNextRound( pubkey := req.GetEphemeralPubkey() if len(pubkey) > 0 { - if err := h.svc.RegisterCosignerPubkey(ctx, paymentID, pubkey); err != nil { + if err := h.svc.RegisterCosignerPubkey(ctx, requestID, pubkey); err != nil { return nil, err } } return &arkv1.RegisterInputsForNextRoundResponse{ - Id: paymentID, + RequestId: requestID, }, nil } @@ -168,7 +168,7 @@ func (h *handler) RegisterOutputsForNextRound( return nil, status.Error(codes.InvalidArgument, err.Error()) } - if err := h.svc.ClaimVtxos(ctx, req.GetId(), receivers); err != nil { + if err := h.svc.ClaimVtxos(ctx, req.GetRequestId(), receivers); err != nil { return nil, err } @@ -199,13 +199,13 @@ func (h *handler) SubmitTreeNonces( return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key") } - cosignerPublicKey, err := secp256k1.ParsePubKey(pubkeyBytes) + cosignerPubkey, 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, + ctx, roundID, cosignerPubkey, encodedNonces, ); err != nil { return nil, err } @@ -237,13 +237,13 @@ func (h *handler) SubmitTreeSignatures( return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key") } - cosignerPublicKey, err := secp256k1.ParsePubKey(pubkeyBytes) + cosignerPubkey, 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, + ctx, roundID, cosignerPubkey, encodedSignatures, ); err != nil { return nil, err } @@ -299,11 +299,11 @@ func (h *handler) GetEventStream( func (h *handler) Ping( ctx context.Context, req *arkv1.PingRequest, ) (*arkv1.PingResponse, error) { - if req.GetPaymentId() == "" { - return nil, status.Error(codes.InvalidArgument, "missing payment id") + if req.GetRequestId() == "" { + return nil, status.Error(codes.InvalidArgument, "missing request id") } - if err := h.svc.UpdatePaymentStatus(ctx, req.GetPaymentId()); err != nil { + if err := h.svc.UpdateTxRequestStatus(ctx, req.GetRequestId()); err != nil { return nil, err } @@ -344,7 +344,7 @@ func (h *handler) GetRound( Start: round.StartingTimestamp, End: round.EndingTimestamp, RoundTx: round.UnsignedTx, - VtxoTree: congestionTree(round.CongestionTree).toProto(), + VtxoTree: vtxoTree(round.VtxoTree).toProto(), ForfeitTxs: round.ForfeitTxs, Connectors: round.Connectors, Stage: stage(round.Stage).toProto(), @@ -363,7 +363,7 @@ func (h *handler) GetRound( Start: round.StartingTimestamp, End: round.EndingTimestamp, RoundTx: round.UnsignedTx, - VtxoTree: congestionTree(round.CongestionTree).toProto(), + VtxoTree: vtxoTree(round.VtxoTree).toProto(), ForfeitTxs: round.ForfeitTxs, Connectors: round.Connectors, Stage: stage(round.Stage).toProto(), @@ -390,7 +390,7 @@ func (h *handler) GetRoundById( Start: round.StartingTimestamp, End: round.EndingTimestamp, RoundTx: round.UnsignedTx, - VtxoTree: congestionTree(round.CongestionTree).toProto(), + VtxoTree: vtxoTree(round.VtxoTree).toProto(), ForfeitTxs: round.ForfeitTxs, Connectors: round.Connectors, Stage: stage(round.Stage).toProto(), @@ -494,7 +494,7 @@ func (h *handler) listenToEvents() { RoundFinalization: &arkv1.RoundFinalizationEvent{ Id: e.Id, RoundTx: e.RoundTx, - VtxoTree: congestionTree(e.CongestionTree).toProto(), + VtxoTree: vtxoTree(e.VtxoTree).toProto(), Connectors: e.Connectors, MinRelayFeeRate: e.MinRelayFeeRate, }, @@ -530,7 +530,7 @@ func (h *handler) listenToEvents() { RoundSigning: &arkv1.RoundSigningEvent{ Id: e.Id, CosignersPubkeys: cosignersKeys, - UnsignedVtxoTree: congestionTree(e.UnsignedVtxoTree).toProto(), + UnsignedVtxoTree: vtxoTree(e.UnsignedVtxoTree).toProto(), UnsignedRoundTx: e.UnsignedRoundTx, }, }, @@ -563,54 +563,37 @@ func (h *handler) listenToEvents() { } } -func (h *handler) listenToPaymentEvents() { - paymentEventsCh := h.svc.GetTransactionEventsChannel(context.Background()) - for event := range paymentEventsCh { - var paymentEvent *arkv1.GetTransactionsStreamResponse +func (h *handler) listenToTxEvents() { + eventsCh := h.svc.GetTransactionEventsChannel(context.Background()) + for event := range eventsCh { + var txEvent *arkv1.GetTransactionsStreamResponse switch event.Type() { case application.RoundTransaction: - paymentEvent = &arkv1.GetTransactionsStreamResponse{ + txEvent = &arkv1.GetTransactionsStreamResponse{ Tx: &arkv1.GetTransactionsStreamResponse_Round{ - Round: convertRoundPaymentEvent(event.(application.RoundTransactionEvent)), + Round: roundTxEvent(event.(application.RoundTransactionEvent)).toProto(), }, } case application.RedeemTransaction: - paymentEvent = &arkv1.GetTransactionsStreamResponse{ + txEvent = &arkv1.GetTransactionsStreamResponse{ Tx: &arkv1.GetTransactionsStreamResponse_Redeem{ - Redeem: convertAsyncPaymentEvent(event.(application.RedeemTransactionEvent)), + Redeem: redeemTxEvent(event.(application.RedeemTransactionEvent)).toProto(), }, } } - if paymentEvent != nil { + if txEvent != nil { logrus.Debugf("forwarding event to %d listeners", len(h.transactionsListenerHandler.listeners)) for _, l := range h.transactionsListenerHandler.listeners { go func(l *listener[*arkv1.GetTransactionsStreamResponse]) { - l.ch <- paymentEvent + l.ch <- txEvent }(l) } } } } -func convertRoundPaymentEvent(e application.RoundTransactionEvent) *arkv1.RoundTransaction { - return &arkv1.RoundTransaction{ - Txid: e.RoundTxID, - SpentVtxos: vtxoKeyList(e.SpentVtxos).toProto(), - SpendableVtxos: vtxoList(e.SpendableVtxos).toProto(), - ClaimedBoardingUtxos: vtxoKeyList(e.ClaimedBoardingInputs).toProto(), - } -} - -func convertAsyncPaymentEvent(e application.RedeemTransactionEvent) *arkv1.RedeemTransaction { - return &arkv1.RedeemTransaction{ - Txid: e.AsyncTxID, - SpentVtxos: vtxoKeyList(e.SpentVtxos).toProto(), - SpendableVtxos: vtxoList(e.SpendableVtxos).toProto(), - } -} - type listener[T any] struct { id string ch chan T diff --git a/server/internal/interface/grpc/handlers/parser.go b/server/internal/interface/grpc/handlers/parser.go index 246536c..f0cd71e 100644 --- a/server/internal/interface/grpc/handlers/parser.go +++ b/server/internal/interface/grpc/handlers/parser.go @@ -73,7 +73,7 @@ func parseReceiver(out *arkv1.Output) (domain.Receiver, error) { return domain.Receiver{ Amount: out.GetAmount(), - Pubkey: hex.EncodeToString(schnorr.SerializePubKey(decodedAddr.VtxoTapKey)), + PubKey: hex.EncodeToString(schnorr.SerializePubKey(decodedAddr.VtxoTapKey)), }, nil } @@ -117,7 +117,7 @@ func (v vtxoList) toProto() []*arkv1.Vtxo { Swept: vv.Swept, RedeemTx: vv.RedeemTx, IsPending: len(vv.RedeemTx) > 0, - Pubkey: vv.Pubkey, + Pubkey: vv.PubKey, CreatedAt: vv.CreatedAt, }) } @@ -138,9 +138,9 @@ func (v vtxoKeyList) toProto() []*arkv1.Outpoint { return list } -type congestionTree tree.CongestionTree +type vtxoTree tree.VtxoTree -func (t congestionTree) toProto() *arkv1.Tree { +func (t vtxoTree) toProto() *arkv1.Tree { levels := make([]*arkv1.TreeLevel, 0, len(t)) for _, level := range t { levelProto := &arkv1.TreeLevel{ @@ -182,6 +182,27 @@ func (s stage) toProto() arkv1.RoundStage { } } +type roundTxEvent application.RoundTransactionEvent + +func (e roundTxEvent) toProto() *arkv1.RoundTransaction { + return &arkv1.RoundTransaction{ + Txid: e.RoundTxid, + SpentVtxos: vtxoKeyList(e.SpentVtxos).toProto(), + SpendableVtxos: vtxoList(e.SpendableVtxos).toProto(), + ClaimedBoardingUtxos: vtxoKeyList(e.ClaimedBoardingInputs).toProto(), + } +} + +type redeemTxEvent application.RedeemTransactionEvent + +func (e redeemTxEvent) toProto() *arkv1.RedeemTransaction { + return &arkv1.RedeemTransaction{ + Txid: e.RedeemTxid, + SpentVtxos: vtxoKeyList(e.SpentVtxos).toProto(), + SpendableVtxos: vtxoList(e.SpendableVtxos).toProto(), + } +} + func parseSignedVtxoOutpoints(signedVtxoOutpoints []*arkv1.SignedVtxoOutpoint) ([]application.SignedVtxoOutpoint, error) { if len(signedVtxoOutpoints) <= 0 { return nil, fmt.Errorf("missing signed vtxo outpoints") diff --git a/server/test/e2e/covenant/e2e_test.go b/server/test/e2e/covenant/e2e_test.go index 651ef24..e034caa 100644 --- a/server/test/e2e/covenant/e2e_test.go +++ b/server/test/e2e/covenant/e2e_test.go @@ -39,14 +39,14 @@ func TestMain(m *testing.M) { time.Sleep(10 * time.Second) - if err := setupAspWallet(); err != nil { + if err := setupServerWallet(); err != nil { fmt.Println(err) os.Exit(1) } time.Sleep(3 * time.Second) - _, err = runArkCommand("init", "--asp-url", "localhost:6060", "--password", utils.Password, "--network", common.LiquidRegTest.Name, "--explorer", "http://chopsticks-liquid:3000") + _, err = runArkCommand("init", "--server-url", "localhost:6060", "--password", utils.Password, "--network", common.LiquidRegTest.Name, "--explorer", "http://chopsticks-liquid:3000") if err != nil { fmt.Printf("error initializing ark config: %s", err) os.Exit(1) @@ -194,7 +194,7 @@ func TestReactToSpentVtxosRedemption(t *testing.T) { require.NoError(t, err) } - // give time for the ASP to detect and process the fraud + // give time for the server to detect and process the fraud time.Sleep(18 * time.Second) balance, err := client.Balance(ctx, true) @@ -238,7 +238,7 @@ func runArkCommand(arg ...string) (string, error) { return utils.RunCommand("docker", args...) } -func setupAspWallet() error { +func setupServerWallet() error { adminHttpClient := &http.Client{ Timeout: 15 * time.Second, } @@ -320,7 +320,7 @@ func setupAspWallet() error { return nil } -func setupArkSDK(t *testing.T) (arksdk.ArkClient, client.ASPClient) { +func setupArkSDK(t *testing.T) (arksdk.ArkClient, client.TransportClient) { appDataStore, err := store.NewStore(store.Config{ ConfigStoreType: types.FileStore, AppDataStoreType: types.KVStore, @@ -334,7 +334,7 @@ func setupArkSDK(t *testing.T) (arksdk.ArkClient, client.ASPClient) { err = client.Init(context.Background(), arksdk.InitArgs{ WalletType: arksdk.SingleKeyWallet, ClientType: arksdk.GrpcClient, - AspUrl: "localhost:6060", + ServerUrl: "localhost:6060", Password: utils.Password, }) require.NoError(t, err) diff --git a/server/test/e2e/covenantless/e2e_test.go b/server/test/e2e/covenantless/e2e_test.go index 1523797..398d382 100644 --- a/server/test/e2e/covenantless/e2e_test.go +++ b/server/test/e2e/covenantless/e2e_test.go @@ -43,14 +43,14 @@ func TestMain(m *testing.M) { os.Exit(1) } - if err := setupAspWallet(); err != nil { + if err := setupServerWallet(); err != nil { fmt.Println(err) os.Exit(1) } time.Sleep(3 * time.Second) - _, err = runClarkCommand("init", "--asp-url", "localhost:7070", "--password", utils.Password, "--network", "regtest", "--explorer", "http://chopsticks:3000") + _, err = runClarkCommand("init", "--server-url", "localhost:7070", "--password", utils.Password, "--network", "regtest", "--explorer", "http://chopsticks:3000") if err != nil { fmt.Printf("error initializing ark config: %s", err) os.Exit(1) @@ -161,12 +161,12 @@ func TestCollaborativeExit(t *testing.T) { require.NoError(t, err) } -func TestReactToSpentVtxosRedemption(t *testing.T) { +func TestReactToRedemptionOfRefreshedVtxos(t *testing.T) { ctx := context.Background() client, grpcClient := setupArkSDK(t) defer grpcClient.Close() - offchainAddress, boardingAddress, err := client.Receive(ctx) + _, boardingAddress, err := client.Receive(ctx) require.NoError(t, err) _, err = utils.RunCommand("nigiri", "faucet", boardingAddress) @@ -177,11 +177,11 @@ func TestReactToSpentVtxosRedemption(t *testing.T) { _, err = client.Settle(ctx) require.NoError(t, err) - _, err = client.SendOffChain(ctx, false, []arksdk.Receiver{arksdk.NewBitcoinReceiver(offchainAddress, 1000)}) - require.NoError(t, err) - time.Sleep(2 * time.Second) + _, err = client.Settle(ctx) + require.NoError(t, err) + _, spentVtxos, err := client.ListVtxos(ctx) require.NoError(t, err) require.NotEmpty(t, spentVtxos) @@ -204,7 +204,7 @@ func TestReactToSpentVtxosRedemption(t *testing.T) { require.NoError(t, err) } - // give time for the ASP to detect and process the fraud + // give time for the server to detect and process the fraud time.Sleep(20 * time.Second) balance, err := client.Balance(ctx, false) @@ -213,7 +213,7 @@ func TestReactToSpentVtxosRedemption(t *testing.T) { require.Empty(t, balance.OnchainBalance.LockedAmount) } -func TestReactToAsyncSpentVtxosRedemption(t *testing.T) { +func TestReactToRedemptionOfVtxosSpentOOR(t *testing.T) { ctx := context.Background() sdkClient, grpcClient := setupArkSDK(t) defer grpcClient.Close() @@ -270,7 +270,7 @@ func TestReactToAsyncSpentVtxosRedemption(t *testing.T) { require.NoError(t, err) } - // give time for the ASP to detect and process the fraud + // give time for the server to detect and process the fraud time.Sleep(50 * time.Second) balance, err := sdkClient.Balance(ctx, false) @@ -279,7 +279,7 @@ func TestReactToAsyncSpentVtxosRedemption(t *testing.T) { require.Empty(t, balance.OnchainBalance.LockedAmount) } -func TestChainAsyncPayments(t *testing.T) { +func TestChainOutOfRoundTransactions(t *testing.T) { var receive utils.ArkReceive receiveStr, err := runClarkCommand("receive") require.NoError(t, err) @@ -315,7 +315,7 @@ func TestChainAsyncPayments(t *testing.T) { require.NotZero(t, balance.Offchain.Total) } -func TestAliceSeveralPaymentsToBob(t *testing.T) { +func TestAliceSendsSeveralTimesToBob(t *testing.T) { ctx := context.Background() alice, grpcAlice := setupArkSDK(t) defer grpcAlice.Close() @@ -331,6 +331,11 @@ func TestAliceSeveralPaymentsToBob(t *testing.T) { time.Sleep(5 * time.Second) + _, err = alice.Settle(ctx) + require.NoError(t, err) + + time.Sleep(5 * time.Second) + bobAddress, _, err := bob.Receive(ctx) require.NoError(t, err) @@ -424,7 +429,7 @@ func TestSweep(t *testing.T) { time.Sleep(3 * time.Second) - secretKey, publicKey, npub, err := utils.GetNostrKeys() + secretKey, pubkey, npub, err := utils.GetNostrKeys() require.NoError(t, err) _, err = runClarkCommand("register-nostr", "--profile", npub, "--password", utils.Password) @@ -443,7 +448,7 @@ func TestSweep(t *testing.T) { }, { Tags: nostr.TagMap{ - "p": []string{publicKey}, + "p": []string{pubkey}, }, }, }) @@ -487,7 +492,7 @@ func runClarkCommand(arg ...string) (string, error) { return utils.RunDockerExec("clarkd", args...) } -func setupAspWallet() error { +func setupServerWallet() error { adminHttpClient := &http.Client{ Timeout: 15 * time.Second, } @@ -594,7 +599,7 @@ func setupAspWallet() error { return nil } -func setupArkSDK(t *testing.T) (arksdk.ArkClient, client.ASPClient) { +func setupArkSDK(t *testing.T) (arksdk.ArkClient, client.TransportClient) { appDataStore, err := store.NewStore(store.Config{ ConfigStoreType: types.FileStore, AppDataStoreType: types.KVStore, @@ -608,7 +613,7 @@ func setupArkSDK(t *testing.T) (arksdk.ArkClient, client.ASPClient) { err = client.Init(context.Background(), arksdk.InitArgs{ WalletType: arksdk.SingleKeyWallet, ClientType: arksdk.GrpcClient, - AspUrl: "localhost:7070", + ServerUrl: "localhost:7070", Password: utils.Password, }) require.NoError(t, err) diff --git a/server/test/e2e/test_utils.go b/server/test/e2e/test_utils.go index 494182f..346e981 100644 --- a/server/test/e2e/test_utils.go +++ b/server/test/e2e/test_utils.go @@ -118,15 +118,15 @@ func newCommand(name string, arg ...string) *exec.Cmd { // nostr // use nak utils https://github.com/fiatjaf/nak -func GetNostrKeys() (secretKey, publicKey string, npub string, err error) { +func GetNostrKeys() (secretKey, pubkey string, npub string, err error) { secretKey = NostrTestingSecretKey - publicKey, err = nostr.GetPublicKey(secretKey) + pubkey, err = nostr.GetPublicKey(secretKey) if err != nil { return } - npub, err = nip19.EncodePublicKey(publicKey) + npub, err = nip19.EncodePublicKey(pubkey) if err != nil { return }