mirror of
https://github.com/aljazceru/ark.git
synced 2025-12-17 04:04:21 +01:00
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
This commit is contained in:
committed by
GitHub
parent
12d666bfdf
commit
7f937e8418
@@ -32,10 +32,10 @@ For a quick-start with Docker, head over to our [Quick Start guide](https://arkd
|
|||||||
## Repository Structure
|
## Repository Structure
|
||||||
|
|
||||||
- [`api-spec`](./api-spec/): Ark Protocol Buffer API specification
|
- [`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
|
- [`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.
|
- [`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 Service Provider (ASP) - the always-on daemon
|
- [`server`](./server/): `arkd` Ark server - the always-on daemon
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
|||||||
@@ -163,7 +163,7 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/v1/round/ping/{paymentId}": {
|
"/v1/round/ping/{requestId}": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "ArkService_Ping",
|
"operationId": "ArkService_Ping",
|
||||||
"responses": {
|
"responses": {
|
||||||
@@ -182,7 +182,8 @@
|
|||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "paymentId",
|
"name": "requestId",
|
||||||
|
"description": "The id used to register inputs and ouptuts.",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -770,7 +771,7 @@
|
|||||||
"title": "VTXO outpoint signed with script's secret key"
|
"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": {
|
"v1PingResponse": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
@@ -821,18 +822,16 @@
|
|||||||
"v1RegisterInputsForNextRoundResponse": {
|
"v1RegisterInputsForNextRoundResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"requestId": {
|
||||||
"type": "string",
|
"type": "string"
|
||||||
"description": "Mocks wabisabi's blinded credentials."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"v1RegisterOutputsForNextRoundRequest": {
|
"v1RegisterOutputsForNextRoundRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"requestId": {
|
||||||
"type": "string",
|
"type": "string"
|
||||||
"description": "Mocks wabisabi's blinded credentials."
|
|
||||||
},
|
},
|
||||||
"outputs": {
|
"outputs": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
@@ -840,7 +839,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"$ref": "#/definitions/v1Output"
|
"$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": {
|
"signedRoundTx": {
|
||||||
"type": "string",
|
"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."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ service ArkService {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/* In-Round Payment APIs */
|
/* In-Round Transaction APIs */
|
||||||
|
|
||||||
rpc RegisterInputsForNextRound(RegisterInputsForNextRoundRequest) returns (RegisterInputsForNextRoundResponse) {
|
rpc RegisterInputsForNextRound(RegisterInputsForNextRoundRequest) returns (RegisterInputsForNextRoundResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
@@ -58,10 +58,12 @@ service ArkService {
|
|||||||
};
|
};
|
||||||
rpc Ping(PingRequest) returns (PingResponse) {
|
rpc Ping(PingRequest) returns (PingResponse) {
|
||||||
option (google.api.http) = {
|
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) {
|
rpc SubmitRedeemTx(SubmitRedeemTxRequest) returns (SubmitRedeemTxResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/v1/redeem-tx"
|
post: "/v1/redeem-tx"
|
||||||
@@ -134,7 +136,7 @@ message GetBoardingAddressResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In-Round Payment API messages */
|
/* In-Round Transaction API messages */
|
||||||
|
|
||||||
message RegisterInputsForNextRoundRequest {
|
message RegisterInputsForNextRoundRequest {
|
||||||
repeated Input inputs = 1;
|
repeated Input inputs = 1;
|
||||||
@@ -142,14 +144,12 @@ message RegisterInputsForNextRoundRequest {
|
|||||||
repeated string notes = 3;
|
repeated string notes = 3;
|
||||||
}
|
}
|
||||||
message RegisterInputsForNextRoundResponse {
|
message RegisterInputsForNextRoundResponse {
|
||||||
// Mocks wabisabi's blinded credentials.
|
string request_id = 1;
|
||||||
string id = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message RegisterOutputsForNextRoundRequest {
|
message RegisterOutputsForNextRoundRequest {
|
||||||
// Mocks wabisabi's blinded credentials.
|
string request_id = 1;
|
||||||
string id = 1;
|
// List of receivers for to convert to leaves in the next VTXO tree.
|
||||||
// List of receivers for a registered payment.
|
|
||||||
repeated Output outputs = 2;
|
repeated Output outputs = 2;
|
||||||
}
|
}
|
||||||
message RegisterOutputsForNextRoundResponse {}
|
message RegisterOutputsForNextRoundResponse {}
|
||||||
@@ -171,7 +171,7 @@ message SubmitTreeSignaturesResponse {}
|
|||||||
message SubmitSignedForfeitTxsRequest {
|
message SubmitSignedForfeitTxsRequest {
|
||||||
// Forfeit txs signed by the user.
|
// Forfeit txs signed by the user.
|
||||||
repeated string signed_forfeit_txs = 1;
|
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;
|
optional string signed_round_tx = 2;
|
||||||
}
|
}
|
||||||
message SubmitSignedForfeitTxsResponse {}
|
message SubmitSignedForfeitTxsResponse {}
|
||||||
@@ -188,7 +188,8 @@ message GetEventStreamResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message PingRequest {
|
message PingRequest {
|
||||||
string payment_id = 1;
|
// The id used to register inputs and ouptuts.
|
||||||
|
string request_id = 1;
|
||||||
}
|
}
|
||||||
message PingResponse {}
|
message PingResponse {}
|
||||||
|
|
||||||
@@ -343,7 +344,7 @@ message RedeemTransaction {
|
|||||||
repeated Vtxo spendable_vtxos = 3;
|
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 {
|
message OwnershipProof {
|
||||||
string control_block = 1;
|
string control_block = 1;
|
||||||
string script = 2;
|
string script = 2;
|
||||||
|
|||||||
@@ -439,8 +439,7 @@ type RegisterInputsForNextRoundResponse struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// Mocks wabisabi's blinded credentials.
|
RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
|
||||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RegisterInputsForNextRoundResponse) Reset() {
|
func (x *RegisterInputsForNextRoundResponse) Reset() {
|
||||||
@@ -475,9 +474,9 @@ func (*RegisterInputsForNextRoundResponse) Descriptor() ([]byte, []int) {
|
|||||||
return file_ark_v1_service_proto_rawDescGZIP(), []int{5}
|
return file_ark_v1_service_proto_rawDescGZIP(), []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RegisterInputsForNextRoundResponse) GetId() string {
|
func (x *RegisterInputsForNextRoundResponse) GetRequestId() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Id
|
return x.RequestId
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -487,9 +486,8 @@ type RegisterOutputsForNextRoundRequest struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// Mocks wabisabi's blinded credentials.
|
RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
|
||||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
// List of receivers for to convert to leaves in the next VTXO tree.
|
||||||
// List of receivers for a registered payment.
|
|
||||||
Outputs []*Output `protobuf:"bytes,2,rep,name=outputs,proto3" json:"outputs,omitempty"`
|
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}
|
return file_ark_v1_service_proto_rawDescGZIP(), []int{6}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RegisterOutputsForNextRoundRequest) GetId() string {
|
func (x *RegisterOutputsForNextRoundRequest) GetRequestId() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Id
|
return x.RequestId
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -786,7 +784,7 @@ type SubmitSignedForfeitTxsRequest struct {
|
|||||||
|
|
||||||
// Forfeit txs signed by the user.
|
// Forfeit txs signed by the user.
|
||||||
SignedForfeitTxs []string `protobuf:"bytes,1,rep,name=signed_forfeit_txs,json=signedForfeitTxs,proto3" json:"signed_forfeit_txs,omitempty"`
|
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"`
|
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
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
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() {
|
func (x *PingRequest) Reset() {
|
||||||
@@ -1075,9 +1074,9 @@ func (*PingRequest) Descriptor() ([]byte, []int) {
|
|||||||
return file_ark_v1_service_proto_rawDescGZIP(), []int{16}
|
return file_ark_v1_service_proto_rawDescGZIP(), []int{16}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *PingRequest) GetPaymentId() string {
|
func (x *PingRequest) GetRequestId() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.PaymentId
|
return x.RequestId
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -2658,7 +2657,7 @@ func (x *RedeemTransaction) GetSpendableVtxos() []*Vtxo {
|
|||||||
return nil
|
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 {
|
type OwnershipProof struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
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,
|
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,
|
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,
|
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,
|
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,
|
0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72,
|
||||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x5e, 0x0a, 0x22, 0x52,
|
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f,
|
0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x6d, 0x0a, 0x22, 0x52, 0x65,
|
||||||
0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72,
|
||||||
0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
|
0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
0x64, 0x12, 0x28, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03,
|
0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01,
|
||||||
0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12,
|
||||||
0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x22, 0x25, 0x0a, 0x23, 0x52,
|
0x28, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
|
||||||
0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f,
|
0x32, 0x0e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74,
|
||||||
0x72, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x22, 0x25, 0x0a, 0x23, 0x52, 0x65, 0x67,
|
||||||
0x73, 0x65, 0x22, 0x6d, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65,
|
0x69, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x4e,
|
||||||
0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a,
|
0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||||
0x08, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x22, 0x6d, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f,
|
||||||
0x07, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b,
|
0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x72,
|
||||||
0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79,
|
0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72,
|
||||||
0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x18,
|
0x6f, 0x75, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79,
|
||||||
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x1f,
|
||||||
0x73, 0x22, 0x1a, 0x0a, 0x18, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e,
|
0x0a, 0x0b, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20,
|
||||||
0x6f, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x79, 0x0a,
|
0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x22,
|
||||||
0x1b, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61,
|
0x1a, 0x0a, 0x18, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x6e,
|
||||||
0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08,
|
0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x79, 0x0a, 0x1b, 0x53,
|
||||||
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
|
||||||
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65,
|
0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x6f,
|
||||||
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12,
|
0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x6f,
|
||||||
0x27, 0x0a, 0x0f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72,
|
0x75, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18,
|
||||||
0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x72, 0x65, 0x65, 0x53, 0x69,
|
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a,
|
||||||
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x1e, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x6d,
|
0x0f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73,
|
||||||
0x69, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 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,
|
||||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8e, 0x01, 0x0a, 0x1d, 0x53, 0x75, 0x62,
|
0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x1e, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74,
|
||||||
0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74,
|
0x54, 0x72, 0x65, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65,
|
||||||
0x54, 0x78, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x69,
|
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8e, 0x01, 0x0a, 0x1d, 0x53, 0x75, 0x62, 0x6d, 0x69,
|
||||||
0x67, 0x6e, 0x65, 0x64, 0x5f, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73,
|
0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78,
|
||||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f,
|
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x69, 0x67, 0x6e,
|
||||||
0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x2b, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e,
|
0x65, 0x64, 0x5f, 0x66, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x5f, 0x74, 0x78, 0x73, 0x18, 0x01,
|
||||||
0x65, 0x64, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28,
|
0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66,
|
||||||
0x09, 0x48, 0x00, 0x52, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x6e, 0x64,
|
0x65, 0x69, 0x74, 0x54, 0x78, 0x73, 0x12, 0x2b, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x65, 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, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48,
|
||||||
0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, 0x22, 0x20, 0x0a, 0x1e, 0x53, 0x75, 0x62,
|
0x00, 0x52, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x78,
|
||||||
0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74,
|
0x88, 0x01, 0x01, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x72,
|
||||||
0x54, 0x78, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x0a, 0x15, 0x47,
|
0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x78, 0x22, 0x20, 0x0a, 0x1e, 0x53, 0x75, 0x62, 0x6d, 0x69,
|
||||||
0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71,
|
0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x66, 0x65, 0x69, 0x74, 0x54, 0x78,
|
||||||
0x75, 0x65, 0x73, 0x74, 0x22, 0xa7, 0x03, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e,
|
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74,
|
||||||
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,
|
|
||||||
0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65,
|
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,
|
0x73, 0x74, 0x22, 0xa7, 0x03, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53,
|
||||||
0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a,
|
||||||
0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f,
|
0x12, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74,
|
||||||
0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x30, 0x01, 0x12, 0x56, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67,
|
0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e,
|
||||||
0x12, 0x13, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65,
|
0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61,
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50,
|
0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x72, 0x6f, 0x75,
|
||||||
0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4,
|
0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46,
|
||||||
0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x70,
|
0x0a, 0x0f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65,
|
||||||
0x69, 0x6e, 0x67, 0x2f, 0x7b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d,
|
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31,
|
||||||
0x12, 0x69, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d,
|
0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45,
|
||||||
0x54, 0x78, 0x12, 0x1d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d,
|
0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6e,
|
||||||
0x69, 0x74, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x0c, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f,
|
||||||
0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69,
|
0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x61,
|
||||||
0x74, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x61, 0x69, 0x6c, 0x65,
|
||||||
0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x76,
|
0x64, 0x48, 0x00, 0x52, 0x0b, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64,
|
||||||
0x31, 0x2f, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x2d, 0x74, 0x78, 0x12, 0x57, 0x0a, 0x08, 0x47,
|
0x12, 0x40, 0x0a, 0x0d, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e,
|
||||||
0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31,
|
0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31,
|
||||||
0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65,
|
||||||
0x1a, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75,
|
0x6e, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x69,
|
||||||
0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93,
|
0x6e, 0x67, 0x12, 0x6f, 0x0a, 0x1e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e,
|
||||||
0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x7b, 0x74,
|
0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72,
|
||||||
0x78, 0x69, 0x64, 0x7d, 0x12, 0x64, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64,
|
0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x72, 0x6b,
|
||||||
0x42, 0x79, 0x49, 0x64, 0x12, 0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
|
0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67,
|
||||||
0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x45,
|
||||||
0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f,
|
0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1b, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x69, 0x67,
|
||||||
0x75, 0x6e, 0x64, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
0x6e, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61,
|
||||||
0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75,
|
0x74, 0x65, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x2c, 0x0a, 0x0b,
|
||||||
0x6e, 0x64, 0x2f, 0x69, 0x64, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x5d, 0x0a, 0x09, 0x4c, 0x69,
|
0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72,
|
||||||
0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31,
|
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x0e, 0x0a, 0x0c, 0x50, 0x69,
|
||||||
0x74, 0x1a, 0x19, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56,
|
0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x34, 0x0a, 0x15, 0x53, 0x75,
|
||||||
0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3,
|
0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x71, 0x75,
|
||||||
0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x2f,
|
0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x5f, 0x74, 0x78,
|
||||||
0x7b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0x80, 0x01, 0x0a, 0x15, 0x47, 0x65,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x54, 0x78,
|
||||||
0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72,
|
0x22, 0x42, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x64, 0x65, 0x65, 0x6d,
|
||||||
0x65, 0x61, 0x6d, 0x12, 0x24, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
|
0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x69,
|
||||||
0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x74, 0x72, 0x65,
|
0x67, 0x6e, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x64, 0x65, 0x65, 0x6d, 0x5f, 0x74, 0x78, 0x18, 0x01,
|
||||||
0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x72, 0x6b, 0x2e,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x52, 0x65, 0x64, 0x65,
|
||||||
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
|
0x65, 0x6d, 0x54, 0x78, 0x22, 0x25, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64,
|
||||||
0x6e, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18,
|
||||||
0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x72,
|
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x22, 0x37, 0x0a, 0x10, 0x47,
|
||||||
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x30, 0x01, 0x12, 0x73, 0x0a, 0x11,
|
0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||||
0x53, 0x65, 0x74, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e,
|
0x23, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d,
|
||||||
0x74, 0x12, 0x20, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4e, 0x6f,
|
0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x05, 0x72,
|
||||||
0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75,
|
0x6f, 0x75, 0x6e, 0x64, 0x22, 0x25, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64,
|
||||||
0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74,
|
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,
|
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,
|
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4f, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
|
||||||
0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78, 0x6f, 0x2f, 0x6e, 0x6f, 0x73, 0x74,
|
0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65,
|
||||||
0x72, 0x12, 0x83, 0x01, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x73, 0x74,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x01,
|
||||||
0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x61, 0x72, 0x6b,
|
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69,
|
||||||
0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52,
|
0x67, 0x6e, 0x65, 0x64, 0x56, 0x74, 0x78, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||||
0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
0x52, 0x05, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x1e, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74,
|
||||||
0x24, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e,
|
0x65, 0x4e, 0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52,
|
||||||
0x6f, 0x73, 0x74, 0x72, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73,
|
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x0a, 0x0a, 0x54, 0x61, 0x70, 0x73, 0x63,
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a,
|
0x72, 0x69, 0x70, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73,
|
||||||
0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78, 0x6f, 0x2f, 0x6e, 0x6f, 0x73, 0x74, 0x72,
|
0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x22,
|
||||||
0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x92, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e,
|
0x85, 0x02, 0x0a, 0x0a, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x48, 0x6f, 0x75, 0x72, 0x12, 0x42,
|
||||||
0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50,
|
0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d,
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||||
0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x6b, 0x2d, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x61,
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
|
||||||
0x72, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x73, 0x70, 0x65, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74,
|
0x61, 0x6d, 0x70, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69,
|
||||||
0x6f, 0x62, 0x75, 0x66, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x72, 0x6b, 0x2f, 0x76, 0x31, 0x3b,
|
0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74,
|
||||||
0x61, 0x72, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x41, 0x72,
|
0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||||
0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, 0x41, 0x72, 0x6b, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x12,
|
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
|
||||||
0x41, 0x72, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
|
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x6e, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x64, 0x54, 0x69,
|
||||||
0x74, 0x61, 0xea, 0x02, 0x07, 0x41, 0x72, 0x6b, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72,
|
0x6d, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01,
|
||||||
0x6f, 0x74, 0x6f, 0x33,
|
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 (
|
var (
|
||||||
|
|||||||
@@ -233,14 +233,14 @@ func request_ArkService_Ping_0(ctx context.Context, marshaler runtime.Marshaler,
|
|||||||
_ = err
|
_ = err
|
||||||
)
|
)
|
||||||
|
|
||||||
val, ok = pathParams["payment_id"]
|
val, ok = pathParams["request_id"]
|
||||||
if !ok {
|
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 {
|
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))
|
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
|
_ = err
|
||||||
)
|
)
|
||||||
|
|
||||||
val, ok = pathParams["payment_id"]
|
val, ok = pathParams["request_id"]
|
||||||
if !ok {
|
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 {
|
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)
|
msg, err := server.Ping(ctx, &protoReq)
|
||||||
@@ -722,7 +722,7 @@ func RegisterArkServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
var err error
|
var err error
|
||||||
var annotatedContext context.Context
|
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 {
|
if err != nil {
|
||||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
return
|
return
|
||||||
@@ -1119,7 +1119,7 @@ func RegisterArkServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
var err error
|
var err error
|
||||||
var annotatedContext context.Context
|
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 {
|
if err != nil {
|
||||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
return
|
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_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"}, ""))
|
pattern_ArkService_SubmitRedeemTx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "redeem-tx"}, ""))
|
||||||
|
|
||||||
|
|||||||
@@ -97,8 +97,8 @@ var (
|
|||||||
Usage: "optional private key to encrypt",
|
Usage: "optional private key to encrypt",
|
||||||
}
|
}
|
||||||
urlFlag = &cli.StringFlag{
|
urlFlag = &cli.StringFlag{
|
||||||
Name: "asp-url",
|
Name: "server-url",
|
||||||
Usage: "the url of the ASP to connect to",
|
Usage: "the url of the Ark server to connect to",
|
||||||
Required: true,
|
Required: true,
|
||||||
}
|
}
|
||||||
receiversFlag = &cli.StringFlag{
|
receiversFlag = &cli.StringFlag{
|
||||||
@@ -150,7 +150,7 @@ var (
|
|||||||
var (
|
var (
|
||||||
initCommand = cli.Command{
|
initCommand = cli.Command{
|
||||||
Name: "init",
|
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 {
|
Action: func(ctx *cli.Context) error {
|
||||||
return initArkSdk(ctx)
|
return initArkSdk(ctx)
|
||||||
},
|
},
|
||||||
@@ -180,7 +180,7 @@ var (
|
|||||||
}
|
}
|
||||||
settleCmd = cli.Command{
|
settleCmd = cli.Command{
|
||||||
Name: "settle",
|
Name: "settle",
|
||||||
Usage: "Settle onboarding funds or oor payments",
|
Usage: "Settle onboarding or pending funds",
|
||||||
Action: func(ctx *cli.Context) error {
|
Action: func(ctx *cli.Context) error {
|
||||||
return settle(ctx)
|
return settle(ctx)
|
||||||
},
|
},
|
||||||
@@ -196,7 +196,7 @@ var (
|
|||||||
}
|
}
|
||||||
sendCommand = cli.Command{
|
sendCommand = cli.Command{
|
||||||
Name: "send",
|
Name: "send",
|
||||||
Usage: "Send funds onchain, offchain, or asynchronously",
|
Usage: "Send funds offchain",
|
||||||
Action: func(ctx *cli.Context) error {
|
Action: func(ctx *cli.Context) error {
|
||||||
return send(ctx)
|
return send(ctx)
|
||||||
},
|
},
|
||||||
@@ -243,7 +243,7 @@ func initArkSdk(ctx *cli.Context) error {
|
|||||||
ctx.Context, arksdk.InitArgs{
|
ctx.Context, arksdk.InitArgs{
|
||||||
ClientType: clientType,
|
ClientType: clientType,
|
||||||
WalletType: arksdk.SingleKeyWallet,
|
WalletType: arksdk.SingleKeyWallet,
|
||||||
AspUrl: ctx.String(urlFlag.Name),
|
ServerUrl: ctx.String(urlFlag.Name),
|
||||||
Seed: ctx.String(privateKeyFlag.Name),
|
Seed: ctx.String(privateKeyFlag.Name),
|
||||||
Password: string(password),
|
Password: string(password),
|
||||||
ExplorerURL: ctx.String(explorerFlag.Name),
|
ExplorerURL: ctx.String(explorerFlag.Name),
|
||||||
@@ -258,8 +258,8 @@ func config(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cfg := map[string]interface{}{
|
cfg := map[string]interface{}{
|
||||||
"asp_url": cfgData.AspUrl,
|
"server_url": cfgData.ServerUrl,
|
||||||
"asp_pubkey": hex.EncodeToString(cfgData.AspPubkey.SerializeCompressed()),
|
"server_pubkey": hex.EncodeToString(cfgData.ServerPubKey.SerializeCompressed()),
|
||||||
"wallet_type": cfgData.WalletType,
|
"wallet_type": cfgData.WalletType,
|
||||||
"client_tyep": cfgData.ClientType,
|
"client_tyep": cfgData.ClientType,
|
||||||
"network": cfgData.Network.Name,
|
"network": cfgData.Network.Name,
|
||||||
@@ -368,7 +368,7 @@ func send(ctx *cli.Context) error {
|
|||||||
if isBitcoin {
|
if isBitcoin {
|
||||||
return sendCovenantLess(ctx, receivers)
|
return sendCovenantLess(ctx, receivers)
|
||||||
}
|
}
|
||||||
return sendCovenant(ctx.Context, receivers)
|
return sendCovenant(ctx, receivers)
|
||||||
}
|
}
|
||||||
|
|
||||||
func balance(ctx *cli.Context) error {
|
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 {
|
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)
|
computeExpiration := ctx.Bool(enableExpiryCoinselectFlag.Name)
|
||||||
redeemTx, err := arkSdkClient.SendAsync(
|
redeemTx, err := arkSdkClient.SendOffChain(
|
||||||
ctx.Context, computeExpiration, receivers,
|
ctx.Context, computeExpiration, offchainReceivers,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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()})
|
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
|
var onchainReceivers, offchainReceivers []arksdk.Receiver
|
||||||
|
|
||||||
for _, receiver := range receivers {
|
for _, receiver := range receivers {
|
||||||
@@ -552,22 +570,21 @@ func sendCovenant(ctx context.Context, receivers []arksdk.Receiver) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(onchainReceivers) > 0 {
|
if len(onchainReceivers) > 0 {
|
||||||
txID, err := arkSdkClient.SendOnChain(ctx, onchainReceivers)
|
txID, err := arkSdkClient.SendOnChain(ctx.Context, onchainReceivers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return printJSON(map[string]interface{}{"txid": txID})
|
return printJSON(map[string]interface{}{"txid": txID})
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(offchainReceivers) > 0 {
|
computeExpiration := ctx.Bool(enableExpiryCoinselectFlag.Name)
|
||||||
txID, err := arkSdkClient.SendOffChain(ctx, false, offchainReceivers)
|
txid, err := arkSdkClient.SendOffChain(
|
||||||
if err != nil {
|
ctx.Context, computeExpiration, offchainReceivers,
|
||||||
return err
|
)
|
||||||
}
|
if err != nil {
|
||||||
return printJSON(map[string]interface{}{"txid": txID})
|
return err
|
||||||
}
|
}
|
||||||
|
return printJSON(map[string]interface{}{"txid": txid})
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readPassword(ctx *cli.Context) ([]byte, error) {
|
func readPassword(ctx *cli.Context) ([]byte, error) {
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ import (
|
|||||||
|
|
||||||
// CraftSharedOutput returns the taproot script and the amount of the initial root output
|
// CraftSharedOutput returns the taproot script and the amount of the initial root output
|
||||||
func CraftSharedOutput(
|
func CraftSharedOutput(
|
||||||
cosigners []*secp256k1.PublicKey, aspPubkey *secp256k1.PublicKey, receivers []tree.VtxoLeaf,
|
cosigners []*secp256k1.PublicKey, server *secp256k1.PublicKey, receivers []tree.VtxoLeaf,
|
||||||
feeSatsPerNode uint64, roundLifetime int64,
|
feeSatsPerNode uint64, roundLifetime int64,
|
||||||
) ([]byte, int64, error) {
|
) ([]byte, int64, error) {
|
||||||
aggregatedKey, _, err := createAggregatedKeyWithSweep(
|
aggregatedKey, _, err := createAggregatedKeyWithSweep(
|
||||||
cosigners, aspPubkey, roundLifetime,
|
cosigners, server, roundLifetime,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
@@ -34,21 +34,21 @@ func CraftSharedOutput(
|
|||||||
|
|
||||||
amount := root.getAmount() + int64(feeSatsPerNode)
|
amount := root.getAmount() + int64(feeSatsPerNode)
|
||||||
|
|
||||||
scriptPubKey, err := common.P2TRScript(aggregatedKey.FinalKey)
|
scriptPubkey, err := common.P2TRScript(aggregatedKey.FinalKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return scriptPubKey, amount, err
|
return scriptPubkey, amount, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CraftCongestionTree creates all the tree's transactions
|
// BuildVtxoTree creates all the tree's transactions
|
||||||
func CraftCongestionTree(
|
func BuildVtxoTree(
|
||||||
initialInput *wire.OutPoint, cosigners []*secp256k1.PublicKey, aspPubkey *secp256k1.PublicKey, receivers []tree.VtxoLeaf,
|
initialInput *wire.OutPoint, cosigners []*secp256k1.PublicKey, server *secp256k1.PublicKey, receivers []tree.VtxoLeaf,
|
||||||
feeSatsPerNode uint64, roundLifetime int64,
|
feeSatsPerNode uint64, roundLifetime int64,
|
||||||
) (tree.CongestionTree, error) {
|
) (tree.VtxoTree, error) {
|
||||||
aggregatedKey, sweepTapLeaf, err := createAggregatedKeyWithSweep(
|
aggregatedKey, sweepTapLeaf, err := createAggregatedKeyWithSweep(
|
||||||
cosigners, aspPubkey, roundLifetime,
|
cosigners, server, roundLifetime,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -59,7 +59,7 @@ func CraftCongestionTree(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
congestionTree := make(tree.CongestionTree, 0)
|
vtxoTree := make(tree.VtxoTree, 0)
|
||||||
|
|
||||||
ins := []*wire.OutPoint{initialInput}
|
ins := []*wire.OutPoint{initialInput}
|
||||||
nodes := []node{root}
|
nodes := []node{root}
|
||||||
@@ -95,12 +95,12 @@ func CraftCongestionTree(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
congestionTree = append(congestionTree, treeLevel)
|
vtxoTree = append(vtxoTree, treeLevel)
|
||||||
nodes = append([]node{}, nextNodes...)
|
nodes = append([]node{}, nextNodes...)
|
||||||
ins = append([]*wire.OutPoint{}, nextInputsArgs...)
|
ins = append([]*wire.OutPoint{}, nextInputsArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return congestionTree, nil
|
return vtxoTree, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type node interface {
|
type node interface {
|
||||||
@@ -252,7 +252,7 @@ func createRootNode(
|
|||||||
|
|
||||||
nodes := make([]node, 0, len(receivers))
|
nodes := make([]node, 0, len(receivers))
|
||||||
for _, r := range receivers {
|
for _, r := range receivers {
|
||||||
pubkeyBytes, err := hex.DecodeString(r.Pubkey)
|
pubkeyBytes, err := hex.DecodeString(r.PubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -280,10 +280,10 @@ func createRootNode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createAggregatedKeyWithSweep(
|
func createAggregatedKeyWithSweep(
|
||||||
cosigners []*secp256k1.PublicKey, aspPubkey *secp256k1.PublicKey, roundLifetime int64,
|
cosigners []*secp256k1.PublicKey, server *secp256k1.PublicKey, roundLifetime int64,
|
||||||
) (*musig2.AggregateKey, *psbt.TaprootTapLeafScript, error) {
|
) (*musig2.AggregateKey, *psbt.TaprootTapLeafScript, error) {
|
||||||
sweepClosure := &tree.CSVSigClosure{
|
sweepClosure := &tree.CSVSigClosure{
|
||||||
MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{aspPubkey}},
|
MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{server}},
|
||||||
Seconds: uint(roundLifetime),
|
Seconds: uint(roundLifetime),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,29 +7,24 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func BuildForfeitTxs(
|
func BuildForfeitTxs(
|
||||||
connectorTx *psbt.Packet,
|
connectorTx *psbt.Packet, vtxoInput *wire.OutPoint,
|
||||||
vtxoInput *wire.OutPoint,
|
vtxoAmount, connectorAmount, feeAmount uint64,
|
||||||
vtxoAmount,
|
vtxoScript, serverScript []byte,
|
||||||
connectorAmount,
|
|
||||||
feeAmount uint64,
|
|
||||||
vtxoScript,
|
|
||||||
aspScript []byte,
|
|
||||||
) (forfeitTxs []*psbt.Packet, err error) {
|
) (forfeitTxs []*psbt.Packet, err error) {
|
||||||
|
version := int32(2)
|
||||||
|
locktime := uint32(0)
|
||||||
connectors, prevouts := getConnectorInputs(connectorTx, int64(connectorAmount))
|
connectors, prevouts := getConnectorInputs(connectorTx, int64(connectorAmount))
|
||||||
|
|
||||||
for i, connectorInput := range connectors {
|
for i, connectorInput := range connectors {
|
||||||
connectorPrevout := prevouts[i]
|
connectorPrevout := prevouts[i]
|
||||||
|
|
||||||
partialTx, err := psbt.New(
|
ins := []*wire.OutPoint{connectorInput, vtxoInput}
|
||||||
[]*wire.OutPoint{connectorInput, vtxoInput},
|
outs := []*wire.TxOut{{
|
||||||
[]*wire.TxOut{{
|
Value: int64(vtxoAmount) + int64(connectorAmount) - int64(feeAmount),
|
||||||
Value: int64(vtxoAmount) + int64(connectorAmount) - int64(feeAmount),
|
PkScript: serverScript,
|
||||||
PkScript: aspScript,
|
}}
|
||||||
}},
|
sequences := []uint32{wire.MaxTxInSequenceNum, wire.MaxTxInSequenceNum}
|
||||||
2,
|
partialTx, err := psbt.New(ins, outs, version, locktime, sequences)
|
||||||
0,
|
|
||||||
[]uint32{wire.MaxTxInSequenceNum, wire.MaxTxInSequenceNum},
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrCongestionTreeNotSet = errors.New("congestion tree not set")
|
ErrMissingVtxoTree = errors.New("missing vtxo tree")
|
||||||
ErrAggregateKeyNotSet = errors.New("aggregate key not set")
|
ErrMissingAggregateKey = errors.New("missing aggregate key")
|
||||||
)
|
)
|
||||||
|
|
||||||
type Musig2Nonce struct {
|
type Musig2Nonce struct {
|
||||||
@@ -62,7 +62,7 @@ type CoordinatorSession interface {
|
|||||||
AggregateNonces() (TreeNonces, error)
|
AggregateNonces() (TreeNonces, error)
|
||||||
AddSig(*btcec.PublicKey, TreePartialSigs) error
|
AddSig(*btcec.PublicKey, TreePartialSigs) error
|
||||||
// SignTree combines the signatures and add them to the tree's psbts
|
// 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 {
|
func (n TreeNonces) Encode(w io.Writer) error {
|
||||||
@@ -111,7 +111,7 @@ func ValidateTreeSigs(
|
|||||||
scriptRoot []byte,
|
scriptRoot []byte,
|
||||||
finalAggregatedKey *btcec.PublicKey,
|
finalAggregatedKey *btcec.PublicKey,
|
||||||
roundSharedOutputAmount int64,
|
roundSharedOutputAmount int64,
|
||||||
vtxoTree tree.CongestionTree,
|
vtxoTree tree.VtxoTree,
|
||||||
) error {
|
) error {
|
||||||
prevoutFetcherFactory, err := prevOutFetcherFactory(finalAggregatedKey, vtxoTree, roundSharedOutputAmount)
|
prevoutFetcherFactory, err := prevOutFetcherFactory(finalAggregatedKey, vtxoTree, roundSharedOutputAmount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -163,7 +163,7 @@ func ValidateTreeSigs(
|
|||||||
func NewTreeSignerSession(
|
func NewTreeSignerSession(
|
||||||
signer *btcec.PrivateKey,
|
signer *btcec.PrivateKey,
|
||||||
roundSharedOutputAmount int64,
|
roundSharedOutputAmount int64,
|
||||||
vtxoTree tree.CongestionTree,
|
vtxoTree tree.VtxoTree,
|
||||||
scriptRoot []byte,
|
scriptRoot []byte,
|
||||||
) SignerSession {
|
) SignerSession {
|
||||||
return &treeSignerSession{
|
return &treeSignerSession{
|
||||||
@@ -176,7 +176,7 @@ func NewTreeSignerSession(
|
|||||||
|
|
||||||
type treeSignerSession struct {
|
type treeSignerSession struct {
|
||||||
secretKey *btcec.PrivateKey
|
secretKey *btcec.PrivateKey
|
||||||
tree tree.CongestionTree
|
tree tree.VtxoTree
|
||||||
myNonces [][]*musig2.Nonces
|
myNonces [][]*musig2.Nonces
|
||||||
keys []*btcec.PublicKey
|
keys []*btcec.PublicKey
|
||||||
aggregateNonces TreeNonces
|
aggregateNonces TreeNonces
|
||||||
@@ -187,7 +187,7 @@ type treeSignerSession struct {
|
|||||||
|
|
||||||
func (t *treeSignerSession) generateNonces() error {
|
func (t *treeSignerSession) generateNonces() error {
|
||||||
if t.tree == nil {
|
if t.tree == nil {
|
||||||
return ErrCongestionTreeNotSet
|
return ErrMissingVtxoTree
|
||||||
}
|
}
|
||||||
|
|
||||||
myNonces := make([][]*musig2.Nonces, 0)
|
myNonces := make([][]*musig2.Nonces, 0)
|
||||||
@@ -213,7 +213,7 @@ func (t *treeSignerSession) generateNonces() error {
|
|||||||
|
|
||||||
func (t *treeSignerSession) GetNonces() (TreeNonces, error) {
|
func (t *treeSignerSession) GetNonces() (TreeNonces, error) {
|
||||||
if t.tree == nil {
|
if t.tree == nil {
|
||||||
return nil, ErrCongestionTreeNotSet
|
return nil, ErrMissingVtxoTree
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.myNonces == nil {
|
if t.myNonces == nil {
|
||||||
@@ -267,11 +267,11 @@ func (t *treeSignerSession) SetAggregatedNonces(nonces TreeNonces) error {
|
|||||||
|
|
||||||
func (t *treeSignerSession) Sign() (TreePartialSigs, error) {
|
func (t *treeSignerSession) Sign() (TreePartialSigs, error) {
|
||||||
if t.tree == nil {
|
if t.tree == nil {
|
||||||
return nil, ErrCongestionTreeNotSet
|
return nil, ErrMissingVtxoTree
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.keys == nil {
|
if t.keys == nil {
|
||||||
return nil, ErrAggregateKeyNotSet
|
return nil, ErrMissingAggregateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.aggregateNonces == nil {
|
if t.aggregateNonces == nil {
|
||||||
@@ -331,7 +331,7 @@ func (t *treeSignerSession) signPartial(partialTx *psbt.Packet, posx int, posy i
|
|||||||
|
|
||||||
type treeCoordinatorSession struct {
|
type treeCoordinatorSession struct {
|
||||||
scriptRoot []byte
|
scriptRoot []byte
|
||||||
tree tree.CongestionTree
|
tree tree.VtxoTree
|
||||||
keys []*btcec.PublicKey
|
keys []*btcec.PublicKey
|
||||||
nonces []TreeNonces
|
nonces []TreeNonces
|
||||||
sigs []TreePartialSigs
|
sigs []TreePartialSigs
|
||||||
@@ -340,7 +340,7 @@ type treeCoordinatorSession struct {
|
|||||||
|
|
||||||
func NewTreeCoordinatorSession(
|
func NewTreeCoordinatorSession(
|
||||||
roundSharedOutputAmount int64,
|
roundSharedOutputAmount int64,
|
||||||
vtxoTree tree.CongestionTree,
|
vtxoTree tree.VtxoTree,
|
||||||
scriptRoot []byte,
|
scriptRoot []byte,
|
||||||
keys []*btcec.PublicKey,
|
keys []*btcec.PublicKey,
|
||||||
) (CoordinatorSession, error) {
|
) (CoordinatorSession, error) {
|
||||||
@@ -428,7 +428,7 @@ func (t *treeCoordinatorSession) AggregateNonces() (TreeNonces, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SignTree implements CoordinatorSession.
|
// SignTree implements CoordinatorSession.
|
||||||
func (t *treeCoordinatorSession) SignTree() (tree.CongestionTree, error) {
|
func (t *treeCoordinatorSession) SignTree() (tree.VtxoTree, error) {
|
||||||
var missingSigs int
|
var missingSigs int
|
||||||
for _, sig := range t.sigs {
|
for _, sig := range t.sigs {
|
||||||
if sig == nil {
|
if sig == nil {
|
||||||
@@ -508,7 +508,7 @@ func (t *treeCoordinatorSession) SignTree() (tree.CongestionTree, error) {
|
|||||||
|
|
||||||
func prevOutFetcherFactory(
|
func prevOutFetcherFactory(
|
||||||
finalAggregatedKey *btcec.PublicKey,
|
finalAggregatedKey *btcec.PublicKey,
|
||||||
vtxoTree tree.CongestionTree,
|
vtxoTree tree.VtxoTree,
|
||||||
roundSharedOutputAmount int64,
|
roundSharedOutputAmount int64,
|
||||||
) (
|
) (
|
||||||
func(partial *psbt.Packet) (txscript.PrevOutputFetcher, error),
|
func(partial *psbt.Packet) (txscript.PrevOutputFetcher, error),
|
||||||
|
|||||||
@@ -28,33 +28,33 @@ func TestRoundTripSignTree(t *testing.T) {
|
|||||||
for _, f := range fixtures.Valid {
|
for _, f := range fixtures.Valid {
|
||||||
// Generate 20 cosigners
|
// Generate 20 cosigners
|
||||||
cosigners := make([]*secp256k1.PrivateKey, 20)
|
cosigners := make([]*secp256k1.PrivateKey, 20)
|
||||||
cosignerPubKeys := make([]*btcec.PublicKey, 20)
|
cosignerPubkeys := make([]*btcec.PublicKey, 20)
|
||||||
for i := 0; i < 20; i++ {
|
for i := 0; i < 20; i++ {
|
||||||
privKey, err := secp256k1.GeneratePrivateKey()
|
prvkey, err := secp256k1.GeneratePrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
cosigners[i] = privKey
|
cosigners[i] = prvkey
|
||||||
cosignerPubKeys[i] = privKey.PubKey()
|
cosignerPubkeys[i] = prvkey.PubKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
asp, err := secp256k1.GeneratePrivateKey()
|
server, err := secp256k1.GeneratePrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, sharedOutputAmount, err := bitcointree.CraftSharedOutput(
|
_, sharedOutputAmount, err := bitcointree.CraftSharedOutput(
|
||||||
cosignerPubKeys,
|
cosignerPubkeys,
|
||||||
asp.PubKey(),
|
server.PubKey(),
|
||||||
castReceivers(f.Receivers),
|
castReceivers(f.Receivers),
|
||||||
minRelayFee,
|
minRelayFee,
|
||||||
lifetime,
|
lifetime,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
vtxoTree, err := bitcointree.CraftCongestionTree(
|
vtxoTree, err := bitcointree.BuildVtxoTree(
|
||||||
&wire.OutPoint{
|
&wire.OutPoint{
|
||||||
Hash: *testTxid,
|
Hash: *testTxid,
|
||||||
Index: 0,
|
Index: 0,
|
||||||
},
|
},
|
||||||
cosignerPubKeys,
|
cosignerPubkeys,
|
||||||
asp.PubKey(),
|
server.PubKey(),
|
||||||
castReceivers(f.Receivers),
|
castReceivers(f.Receivers),
|
||||||
minRelayFee,
|
minRelayFee,
|
||||||
lifetime,
|
lifetime,
|
||||||
@@ -62,7 +62,7 @@ func TestRoundTripSignTree(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
sweepClosure := &tree.CSVSigClosure{
|
sweepClosure := &tree.CSVSigClosure{
|
||||||
MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{asp.PubKey()}},
|
MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{server.PubKey()}},
|
||||||
Seconds: uint(lifetime),
|
Seconds: uint(lifetime),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,11 +73,11 @@ func TestRoundTripSignTree(t *testing.T) {
|
|||||||
sweepTapTree := txscript.AssembleTaprootScriptTree(sweepTapLeaf)
|
sweepTapTree := txscript.AssembleTaprootScriptTree(sweepTapLeaf)
|
||||||
root := sweepTapTree.RootNode.TapHash()
|
root := sweepTapTree.RootNode.TapHash()
|
||||||
|
|
||||||
aspCoordinator, err := bitcointree.NewTreeCoordinatorSession(
|
serverCoordinator, err := bitcointree.NewTreeCoordinatorSession(
|
||||||
sharedOutputAmount,
|
sharedOutputAmount,
|
||||||
vtxoTree,
|
vtxoTree,
|
||||||
root.CloneBytes(),
|
root.CloneBytes(),
|
||||||
cosignerPubKeys,
|
cosignerPubkeys,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -91,16 +91,16 @@ func TestRoundTripSignTree(t *testing.T) {
|
|||||||
for i, session := range signerSessions {
|
for i, session := range signerSessions {
|
||||||
nonces, err := session.GetNonces()
|
nonces, err := session.GetNonces()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = aspCoordinator.AddNonce(cosignerPubKeys[i], nonces)
|
err = serverCoordinator.AddNonce(cosignerPubkeys[i], nonces)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
aggregatedNonce, err := aspCoordinator.AggregateNonces()
|
aggregatedNonce, err := serverCoordinator.AggregateNonces()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Set keys and aggregated nonces for all signers
|
// Set keys and aggregated nonces for all signers
|
||||||
for _, session := range signerSessions {
|
for _, session := range signerSessions {
|
||||||
err = session.SetKeys(cosignerPubKeys)
|
err = session.SetKeys(cosignerPubkeys)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = session.SetAggregatedNonces(aggregatedNonce)
|
err = session.SetAggregatedNonces(aggregatedNonce)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -110,15 +110,15 @@ func TestRoundTripSignTree(t *testing.T) {
|
|||||||
for i, session := range signerSessions {
|
for i, session := range signerSessions {
|
||||||
sig, err := session.Sign()
|
sig, err := session.Sign()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = aspCoordinator.AddSig(cosignerPubKeys[i], sig)
|
err = serverCoordinator.AddSig(cosignerPubkeys[i], sig)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
signedTree, err := aspCoordinator.SignTree()
|
signedTree, err := serverCoordinator.SignTree()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// verify the tree
|
// verify the tree
|
||||||
aggregatedKey, err := bitcointree.AggregateKeys(cosignerPubKeys, root.CloneBytes())
|
aggregatedKey, err := bitcointree.AggregateKeys(cosignerPubkeys, root.CloneBytes())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = bitcointree.ValidateTreeSigs(
|
err = bitcointree.ValidateTreeSigs(
|
||||||
@@ -140,7 +140,7 @@ func castReceivers(receivers []receiverFixture) []tree.VtxoLeaf {
|
|||||||
receiversOut := make([]tree.VtxoLeaf, 0, len(receivers))
|
receiversOut := make([]tree.VtxoLeaf, 0, len(receivers))
|
||||||
for _, r := range receivers {
|
for _, r := range receivers {
|
||||||
receiversOut = append(receiversOut, tree.VtxoLeaf{
|
receiversOut = append(receiversOut, tree.VtxoLeaf{
|
||||||
Pubkey: r.Pubkey,
|
PubKey: r.Pubkey,
|
||||||
Amount: uint64(r.Amount),
|
Amount: uint64(r.Amount),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package bitcointree
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -15,36 +14,36 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidPoolTransaction = errors.New("invalid pool transaction")
|
ErrInvalidRoundTx = fmt.Errorf("invalid round transaction")
|
||||||
ErrInvalidPoolTransactionOutputs = errors.New("invalid number of outputs in pool transaction")
|
ErrInvalidRoundTxOutputs = fmt.Errorf("invalid number of outputs in round transaction")
|
||||||
ErrEmptyTree = errors.New("empty congestion tree")
|
ErrEmptyTree = fmt.Errorf("empty vtxo tree")
|
||||||
ErrInvalidRootLevel = errors.New("root level must have only one node")
|
ErrInvalidRootLevel = fmt.Errorf("root level must have only one node")
|
||||||
ErrNoLeaves = errors.New("no leaves in the tree")
|
ErrNoLeaves = fmt.Errorf("no leaves in the tree")
|
||||||
ErrNodeTransactionEmpty = errors.New("node transaction is empty")
|
ErrNodeTxEmpty = fmt.Errorf("node transaction is empty")
|
||||||
ErrNodeTxidEmpty = errors.New("node txid is empty")
|
ErrNodeTxidEmpty = fmt.Errorf("node txid is empty")
|
||||||
ErrNodeParentTxidEmpty = errors.New("node parent txid is empty")
|
ErrNodeParentTxidEmpty = fmt.Errorf("node parent txid is empty")
|
||||||
ErrNodeTxidDifferent = errors.New("node txid differs from node transaction")
|
ErrNodeTxidDifferent = fmt.Errorf("node txid differs from node transaction")
|
||||||
ErrNumberOfInputs = errors.New("node transaction should have only one input")
|
ErrNumberOfInputs = fmt.Errorf("node transaction should have only one input")
|
||||||
ErrNumberOfOutputs = errors.New("node transaction should have only three or two outputs")
|
ErrNumberOfOutputs = fmt.Errorf("node transaction should have only three or two outputs")
|
||||||
ErrParentTxidInput = errors.New("parent txid should be the input of the node transaction")
|
ErrParentTxidInput = fmt.Errorf("parent txid should be the input of the node transaction")
|
||||||
ErrNumberOfChildren = errors.New("node branch transaction should have two children")
|
ErrNumberOfChildren = fmt.Errorf("node branch transaction should have two children")
|
||||||
ErrLeafChildren = errors.New("leaf node should have max 1 child")
|
ErrLeafChildren = fmt.Errorf("leaf node should have max 1 child")
|
||||||
ErrInvalidChildTxid = errors.New("invalid child txid")
|
ErrInvalidChildTxid = fmt.Errorf("invalid child txid")
|
||||||
ErrNumberOfTapscripts = errors.New("input should have 1 tapscript leaf")
|
ErrNumberOfTapscripts = fmt.Errorf("input should have 1 tapscript leaf")
|
||||||
ErrInternalKey = errors.New("invalid taproot internal key")
|
ErrInternalKey = fmt.Errorf("invalid taproot internal key")
|
||||||
ErrInvalidTaprootScript = errors.New("invalid taproot script")
|
ErrInvalidTaprootScript = fmt.Errorf("invalid taproot script")
|
||||||
ErrInvalidControlBlock = errors.New("invalid control block")
|
ErrInvalidControlBlock = fmt.Errorf("invalid control block")
|
||||||
ErrInvalidTaprootScriptLen = errors.New("invalid taproot script length (expected 32 bytes)")
|
ErrInvalidTaprootScriptLen = fmt.Errorf("invalid taproot script length (expected 32 bytes)")
|
||||||
ErrInvalidLeafTaprootScript = errors.New("invalid leaf taproot script")
|
ErrInvalidLeafTaprootScript = fmt.Errorf("invalid leaf taproot script")
|
||||||
ErrInvalidAmount = errors.New("children amount is different from parent amount")
|
ErrInvalidAmount = fmt.Errorf("children amount is different from parent amount")
|
||||||
ErrInvalidSweepSequence = errors.New("invalid sweep sequence")
|
ErrInvalidSweepSequence = fmt.Errorf("invalid sweep sequence")
|
||||||
ErrInvalidASP = errors.New("invalid ASP")
|
ErrInvalidServer = fmt.Errorf("invalid server")
|
||||||
ErrMissingFeeOutput = errors.New("missing fee output")
|
ErrMissingFeeOutput = fmt.Errorf("missing fee output")
|
||||||
ErrInvalidLeftOutput = errors.New("invalid left output")
|
ErrInvalidLeftOutput = fmt.Errorf("invalid left output")
|
||||||
ErrInvalidRightOutput = errors.New("invalid right output")
|
ErrInvalidRightOutput = fmt.Errorf("invalid right output")
|
||||||
ErrMissingSweepTapscript = errors.New("missing sweep tapscript")
|
ErrMissingSweepTapscript = fmt.Errorf("missing sweep tapscript")
|
||||||
ErrInvalidLeaf = errors.New("leaf node shouldn't have children")
|
ErrInvalidLeaf = fmt.Errorf("leaf node shouldn't have children")
|
||||||
ErrWrongPoolTxID = errors.New("root input should be the pool tx outpoint")
|
ErrWrongRoundTxid = fmt.Errorf("the input of the tree root is not the round tx's shared output")
|
||||||
)
|
)
|
||||||
|
|
||||||
// 0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0
|
// 0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0
|
||||||
@@ -62,28 +61,28 @@ func UnspendableKey() *secp256k1.PublicKey {
|
|||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateCongestionTree checks if the given congestion tree is valid
|
// ValidateVtxoTree checks if the given vtxo tree is valid
|
||||||
// poolTxID & poolTxIndex & poolTxAmount are used to validate the root input outpoint
|
// roundTxid & roundTxIndex & roundTxAmount are used to validate the root input outpoint
|
||||||
// aspPublicKey & roundLifetime are used to validate the sweep tapscript leaves
|
// serverPubkey & roundLifetime are used to validate the sweep tapscript leaves
|
||||||
// besides that, the function validates:
|
// besides that, the function validates:
|
||||||
// - the number of nodes
|
// - the number of nodes
|
||||||
// - the number of leaves
|
// - the number of leaves
|
||||||
// - children coherence with parent
|
// - children coherence with parent
|
||||||
// - every control block and taproot output scripts
|
// - every control block and taproot output scripts
|
||||||
// - input and output amounts
|
// - input and output amounts
|
||||||
func ValidateCongestionTree(
|
func ValidateVtxoTree(
|
||||||
vtxoTree tree.CongestionTree, poolTx string, aspPublicKey *secp256k1.PublicKey, roundLifetime int64,
|
vtxoTree tree.VtxoTree, roundTx string, serverPubkey *secp256k1.PublicKey, roundLifetime int64,
|
||||||
) error {
|
) error {
|
||||||
poolTransaction, err := psbt.NewFromRawBytes(strings.NewReader(poolTx), true)
|
roundTransaction, err := psbt.NewFromRawBytes(strings.NewReader(roundTx), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrInvalidPoolTransaction
|
return ErrInvalidRoundTx
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(poolTransaction.Outputs) < sharedOutputIndex+1 {
|
if len(roundTransaction.Outputs) < sharedOutputIndex+1 {
|
||||||
return ErrInvalidPoolTransactionOutputs
|
return ErrInvalidRoundTxOutputs
|
||||||
}
|
}
|
||||||
|
|
||||||
poolTxAmount := poolTransaction.UnsignedTx.TxOut[sharedOutputIndex].Value
|
roundTxAmount := roundTransaction.UnsignedTx.TxOut[sharedOutputIndex].Value
|
||||||
|
|
||||||
nbNodes := vtxoTree.NumberOfNodes()
|
nbNodes := vtxoTree.NumberOfNodes()
|
||||||
if nbNodes == 0 {
|
if nbNodes == 0 {
|
||||||
@@ -94,7 +93,7 @@ func ValidateCongestionTree(
|
|||||||
return ErrInvalidRootLevel
|
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
|
rootPsetB64 := vtxoTree[0][0].Tx
|
||||||
rootPset, err := psbt.NewFromRawBytes(strings.NewReader(rootPsetB64), true)
|
rootPset, err := psbt.NewFromRawBytes(strings.NewReader(rootPsetB64), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -106,9 +105,9 @@ func ValidateCongestionTree(
|
|||||||
}
|
}
|
||||||
|
|
||||||
rootInput := rootPset.UnsignedTx.TxIn[0]
|
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 {
|
rootInput.PreviousOutPoint.Index != sharedOutputIndex {
|
||||||
return ErrWrongPoolTxID
|
return ErrWrongRoundTxid
|
||||||
}
|
}
|
||||||
|
|
||||||
sumRootValue := int64(0)
|
sumRootValue := int64(0)
|
||||||
@@ -116,7 +115,7 @@ func ValidateCongestionTree(
|
|||||||
sumRootValue += output.Value
|
sumRootValue += output.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
if sumRootValue >= poolTxAmount {
|
if sumRootValue >= roundTxAmount {
|
||||||
return ErrInvalidAmount
|
return ErrInvalidAmount
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +124,7 @@ func ValidateCongestionTree(
|
|||||||
}
|
}
|
||||||
|
|
||||||
sweepClosure := &tree.CSVSigClosure{
|
sweepClosure := &tree.CSVSigClosure{
|
||||||
MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{aspPublicKey}},
|
MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{serverPubkey}},
|
||||||
Seconds: uint(roundLifetime),
|
Seconds: uint(roundLifetime),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,9 +151,9 @@ func ValidateCongestionTree(
|
|||||||
return nil
|
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 == "" {
|
if node.Tx == "" {
|
||||||
return ErrNodeTransactionEmpty
|
return ErrNodeTxEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.Txid == "" {
|
if node.Txid == "" {
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ func ParseVtxoScript(scripts []string) (VtxoScript, error) {
|
|||||||
return nil, fmt.Errorf("invalid vtxo scripts: %s", scripts)
|
return nil, fmt.Errorf("invalid vtxo scripts: %s", scripts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDefaultVtxoScript(owner, asp *secp256k1.PublicKey, exitDelay uint) VtxoScript {
|
func NewDefaultVtxoScript(owner, server *secp256k1.PublicKey, exitDelay uint) VtxoScript {
|
||||||
base := tree.NewDefaultVtxoScript(owner, asp, exitDelay)
|
base := tree.NewDefaultVtxoScript(owner, server, exitDelay)
|
||||||
|
|
||||||
return &TapscriptsVtxoScript{*base}
|
return &TapscriptsVtxoScript{*base}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ import (
|
|||||||
"github.com/vulpemventures/go-elements/psetv2"
|
"github.com/vulpemventures/go-elements/psetv2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ValidateConnectors(poolTx string, connectors []string) error {
|
func ValidateConnectors(roundTx string, connectors []string) error {
|
||||||
ptx, err := psetv2.NewPsetFromBase64(poolTx)
|
ptx, err := psetv2.NewPsetFromBase64(roundTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid pool tx: %s", err)
|
return fmt.Errorf("invalid round tx: %s", err)
|
||||||
}
|
}
|
||||||
utx, err := ptx.UnsignedTx()
|
utx, err := ptx.UnsignedTx()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid pool tx: %s", err)
|
return fmt.Errorf("invalid round tx: %s", err)
|
||||||
}
|
}
|
||||||
prevConnectorTxid := utx.TxHash().String()
|
prevConnectorTxid := utx.TxHash().String()
|
||||||
prevConnectorVout := uint32(1)
|
prevConnectorVout := uint32(1)
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ import (
|
|||||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
"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)) })"
|
const DefaultVtxoDescriptorTemplate = "tr(%s,{ and(pk(%s), pk(%s)), and(older(%d), pk(%s)) })"
|
||||||
|
|
||||||
func ParseDefaultVtxoDescriptor(
|
func ParseDefaultVtxoDescriptor(
|
||||||
descriptor string,
|
descriptor string,
|
||||||
) (user, asp *secp256k1.PublicKey, timeout uint, err error) {
|
) (user, server *secp256k1.PublicKey, timeout uint, err error) {
|
||||||
desc, err := ParseTaprootDescriptor(descriptor)
|
desc, err := ParseTaprootDescriptor(descriptor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, err
|
return nil, nil, 0, err
|
||||||
@@ -42,7 +42,7 @@ func ParseDefaultVtxoDescriptor(
|
|||||||
return nil, nil, 0, err
|
return nil, nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
asp, err = schnorr.ParsePubKey(keyBytes)
|
server, err = schnorr.ParsePubKey(keyBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, err
|
return nil, nil, 0, err
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ func ParseDefaultVtxoDescriptor(
|
|||||||
return nil, nil, 0, errors.New("boarding descriptor is invalid")
|
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")
|
return nil, nil, 0, errors.New("boarding descriptor is invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,24 +8,24 @@ import (
|
|||||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
"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 {
|
type Address struct {
|
||||||
HRP string
|
HRP string
|
||||||
Asp *secp256k1.PublicKey
|
Server *secp256k1.PublicKey
|
||||||
VtxoTapKey *secp256k1.PublicKey
|
VtxoTapKey *secp256k1.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode converts the address to its bech32m string representation
|
// Encode converts the address to its bech32m string representation
|
||||||
func (a *Address) Encode() (string, error) {
|
func (a *Address) Encode() (string, error) {
|
||||||
if a.Asp == nil {
|
if a.Server == nil {
|
||||||
return "", fmt.Errorf("missing asp public key")
|
return "", fmt.Errorf("missing server public key")
|
||||||
}
|
}
|
||||||
if a.VtxoTapKey == nil {
|
if a.VtxoTapKey == nil {
|
||||||
return "", fmt.Errorf("missing vtxo tap public key")
|
return "", fmt.Errorf("missing vtxo tap public key")
|
||||||
}
|
}
|
||||||
|
|
||||||
combinedKey := append(
|
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)
|
grp, err := bech32.ConvertBits(combinedKey, 8, 5, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -52,19 +52,19 @@ func DecodeAddress(addr string) (*Address, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
aKey, err := schnorr.ParsePubKey(grp[:32])
|
serverKey, err := schnorr.ParsePubKey(grp[:32])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse public key: %s", err)
|
return nil, fmt.Errorf("failed to parse public key: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
vtxoKey, err := schnorr.ParsePubKey(grp[32:])
|
vtxoKey, err := schnorr.ParsePubKey(grp[32:])
|
||||||
if err != nil {
|
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{
|
return &Address{
|
||||||
HRP: prefix,
|
HRP: prefix,
|
||||||
Asp: aKey,
|
Server: serverKey,
|
||||||
VtxoTapKey: vtxoKey,
|
VtxoTapKey: vtxoKey,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ func TestAddressEncoding(t *testing.T) {
|
|||||||
fixtures := struct {
|
fixtures := struct {
|
||||||
Address struct {
|
Address struct {
|
||||||
Valid []struct {
|
Valid []struct {
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr"`
|
||||||
ExpectedUserKey string `json:"expectedUserKey"`
|
ExpectedUserKey string `json:"expectedUserKey"`
|
||||||
ExpectedAspKey string `json:"expectedAspKey"`
|
ExpectedServerKey string `json:"expectedServerKey"`
|
||||||
} `json:"valid"`
|
} `json:"valid"`
|
||||||
Invalid []struct {
|
Invalid []struct {
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr"`
|
||||||
@@ -43,14 +43,14 @@ func TestAddressEncoding(t *testing.T) {
|
|||||||
addr, err := common.DecodeAddress(f.Addr)
|
addr, err := common.DecodeAddress(f.Addr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, addr.HRP)
|
require.NotEmpty(t, addr.HRP)
|
||||||
require.NotNil(t, addr.Asp)
|
require.NotNil(t, addr.Server)
|
||||||
require.NotNil(t, addr.VtxoTapKey)
|
require.NotNil(t, addr.VtxoTapKey)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, f.ExpectedUserKey, hex.EncodeToString(addr.VtxoTapKey.SerializeCompressed()))
|
require.Equal(t, f.ExpectedUserKey, hex.EncodeToString(addr.VtxoTapKey.SerializeCompressed()))
|
||||||
|
|
||||||
require.NoError(t, err)
|
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()
|
encoded, err := addr.Encode()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func ComputeForfeitTxFee(
|
|||||||
feeRate chainfee.SatPerKVByte,
|
feeRate chainfee.SatPerKVByte,
|
||||||
tapscript *waddrmgr.Tapscript,
|
tapscript *waddrmgr.Tapscript,
|
||||||
witnessSize int,
|
witnessSize int,
|
||||||
aspScriptClass txscript.ScriptClass,
|
serverScriptClass txscript.ScriptClass,
|
||||||
) (uint64, error) {
|
) (uint64, error) {
|
||||||
txWeightEstimator := &input.TxWeightEstimator{}
|
txWeightEstimator := &input.TxWeightEstimator{}
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ func ComputeForfeitTxFee(
|
|||||||
tapscript,
|
tapscript,
|
||||||
)
|
)
|
||||||
|
|
||||||
switch aspScriptClass {
|
switch serverScriptClass {
|
||||||
case txscript.PubKeyHashTy:
|
case txscript.PubKeyHashTy:
|
||||||
txWeightEstimator.AddP2PKHOutput()
|
txWeightEstimator.AddP2PKHOutput()
|
||||||
case txscript.ScriptHashTy:
|
case txscript.ScriptHashTy:
|
||||||
@@ -52,7 +52,7 @@ func ComputeForfeitTxFee(
|
|||||||
case txscript.WitnessV1TaprootTy:
|
case txscript.WitnessV1TaprootTy:
|
||||||
txWeightEstimator.AddP2TROutput()
|
txWeightEstimator.AddP2TROutput()
|
||||||
default:
|
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
|
return uint64(feeRate.FeeForVSize(lntypes.VByte(txWeightEstimator.VSize())).ToUnit(btcutil.AmountSatoshi)), nil
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
{
|
{
|
||||||
"addr": "tark1x0lm8hhr2wc6n6lyemtyh9rz8rg2ftpkfun46aca56kjg3ws0tsztfpuanaquxc6faedvjk3tax0575y6perapg3e95654pk8r4fjecs5fyd2",
|
"addr": "tark1x0lm8hhr2wc6n6lyemtyh9rz8rg2ftpkfun46aca56kjg3ws0tsztfpuanaquxc6faedvjk3tax0575y6perapg3e95654pk8r4fjecs5fyd2",
|
||||||
"expectedUserKey": "0225a43cecfa0e1b1a4f72d64ad15f4cfa7a84d0723e8511c969aa543638ea9967",
|
"expectedUserKey": "0225a43cecfa0e1b1a4f72d64ad15f4cfa7a84d0723e8511c969aa543638ea9967",
|
||||||
"expectedAspKey": "0233ffb3dee353b1a9ebe4ced64b946238d0a4ac364f275d771da6ad2445d07ae0"
|
"expectedServerKey": "0233ffb3dee353b1a9ebe4ced64b946238d0a4ac364f275d771da6ad2445d07ae0"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"invalid": [
|
"invalid": [
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ import (
|
|||||||
"github.com/vulpemventures/go-elements/taproot"
|
"github.com/vulpemventures/go-elements/taproot"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CraftCongestionTree(
|
func BuildVtxoTree(
|
||||||
asset string, aspPubkey *secp256k1.PublicKey, receivers []VtxoLeaf,
|
asset string, serverPubkey *secp256k1.PublicKey, receivers []VtxoLeaf,
|
||||||
feeSatsPerNode uint64, roundLifetime int64,
|
feeSatsPerNode uint64, roundLifetime int64,
|
||||||
) (
|
) (
|
||||||
buildCongestionTree TreeFactory,
|
factoryFn TreeFactory,
|
||||||
sharedOutputScript []byte, sharedOutputAmount uint64, err error,
|
sharedOutputScript []byte, sharedOutputAmount uint64, err error,
|
||||||
) {
|
) {
|
||||||
root, err := createPartialCongestionTree(
|
root, err := buildTreeNodes(
|
||||||
asset, aspPubkey, receivers, feeSatsPerNode, roundLifetime,
|
asset, serverPubkey, receivers, feeSatsPerNode, roundLifetime,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -36,7 +36,7 @@ func CraftCongestionTree(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
sharedOutputAmount = root.getAmount() + root.feeSats
|
sharedOutputAmount = root.getAmount() + root.feeSats
|
||||||
buildCongestionTree = root.createFinalCongestionTree()
|
factoryFn = root.buildVtxoTree()
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -321,16 +321,16 @@ func (n *node) getTx(
|
|||||||
return pset, nil
|
return pset, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *node) createFinalCongestionTree() TreeFactory {
|
func (n *node) buildVtxoTree() TreeFactory {
|
||||||
return func(poolTxInput psetv2.InputArgs) (CongestionTree, error) {
|
return func(roundTxInput psetv2.InputArgs) (VtxoTree, error) {
|
||||||
congestionTree := make(CongestionTree, 0)
|
vtxoTree := make(VtxoTree, 0)
|
||||||
|
|
||||||
_, taprootTree, err := n.getWitnessData()
|
_, taprootTree, err := n.getWitnessData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ins := []psetv2.InputArgs{poolTxInput}
|
ins := []psetv2.InputArgs{roundTxInput}
|
||||||
inTrees := []*taproot.IndexedElementsTapScriptTree{taprootTree}
|
inTrees := []*taproot.IndexedElementsTapScriptTree{taprootTree}
|
||||||
nodes := []*node{n}
|
nodes := []*node{n}
|
||||||
|
|
||||||
@@ -366,7 +366,7 @@ func (n *node) createFinalCongestionTree() TreeFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
congestionTree = append(congestionTree, treeLevel)
|
vtxoTree = append(vtxoTree, treeLevel)
|
||||||
nodes = append([]*node{}, nextNodes...)
|
nodes = append([]*node{}, nextNodes...)
|
||||||
ins = append([]psetv2.InputArgs{}, nextInputsArgs...)
|
ins = append([]psetv2.InputArgs{}, nextInputsArgs...)
|
||||||
inTrees = append(
|
inTrees = append(
|
||||||
@@ -374,12 +374,12 @@ func (n *node) createFinalCongestionTree() TreeFactory {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return congestionTree, nil
|
return vtxoTree, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createPartialCongestionTree(
|
func buildTreeNodes(
|
||||||
asset string, aspPubkey *secp256k1.PublicKey, receivers []VtxoLeaf,
|
asset string, serverPubkey *secp256k1.PublicKey, receivers []VtxoLeaf,
|
||||||
feeSatsPerNode uint64, roundLifetime int64,
|
feeSatsPerNode uint64, roundLifetime int64,
|
||||||
) (root *node, err error) {
|
) (root *node, err error) {
|
||||||
if len(receivers) == 0 {
|
if len(receivers) == 0 {
|
||||||
@@ -388,7 +388,7 @@ func createPartialCongestionTree(
|
|||||||
|
|
||||||
nodes := make([]*node, 0, len(receivers))
|
nodes := make([]*node, 0, len(receivers))
|
||||||
for _, r := range receivers {
|
for _, r := range receivers {
|
||||||
pubkeyBytes, err := hex.DecodeString(r.Pubkey)
|
pubkeyBytes, err := hex.DecodeString(r.PubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -399,7 +399,7 @@ func createPartialCongestionTree(
|
|||||||
}
|
}
|
||||||
|
|
||||||
leafNode := &node{
|
leafNode := &node{
|
||||||
sweepKey: aspPubkey,
|
sweepKey: serverPubkey,
|
||||||
receivers: []vtxoOutput{{pubkey, r.Amount}},
|
receivers: []vtxoOutput{{pubkey, r.Amount}},
|
||||||
asset: asset,
|
asset: asset,
|
||||||
feeSats: feeSatsPerNode,
|
feeSats: feeSatsPerNode,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"errors"
|
"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 {
|
type Node struct {
|
||||||
Txid string
|
Txid string
|
||||||
Tx string
|
Tx string
|
||||||
@@ -14,28 +14,28 @@ type Node struct {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
ErrParentNotFound = errors.New("parent not found")
|
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
|
// 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
|
// Root returns the root node of the vtxo tree
|
||||||
func (c CongestionTree) Root() (Node, error) {
|
func (c VtxoTree) Root() (Node, error) {
|
||||||
if len(c) <= 0 {
|
if len(c) <= 0 {
|
||||||
return Node{}, errors.New("empty congestion tree")
|
return Node{}, errors.New("empty vtxo tree")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c[0]) <= 0 {
|
if len(c[0]) <= 0 {
|
||||||
return Node{}, errors.New("empty congestion tree")
|
return Node{}, errors.New("empty vtxo tree")
|
||||||
}
|
}
|
||||||
|
|
||||||
return c[0][0], nil
|
return c[0][0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Leaves returns the leaves of the congestion tree (the vtxos txs)
|
// Leaves returns the leaves of the vtxo tree
|
||||||
func (c CongestionTree) Leaves() []Node {
|
func (c VtxoTree) Leaves() []Node {
|
||||||
leaves := c[len(c)-1]
|
leaves := c[len(c)-1]
|
||||||
for _, level := range c[:len(c)-1] {
|
for _, level := range c[:len(c)-1] {
|
||||||
for _, node := range level {
|
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
|
// 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
|
var children []Node
|
||||||
for _, level := range c {
|
for _, level := range c {
|
||||||
for _, node := range level {
|
for _, node := range level {
|
||||||
@@ -62,8 +62,8 @@ func (c CongestionTree) Children(nodeTxid string) []Node {
|
|||||||
return children
|
return children
|
||||||
}
|
}
|
||||||
|
|
||||||
// NumberOfNodes returns the total number of pset in the congestion tree
|
// NumberOfNodes returns the total number of pset in the vtxo tree
|
||||||
func (c CongestionTree) NumberOfNodes() int {
|
func (c VtxoTree) NumberOfNodes() int {
|
||||||
var count int
|
var count int
|
||||||
for _, level := range c {
|
for _, level := range c {
|
||||||
count += len(level)
|
count += len(level)
|
||||||
@@ -71,8 +71,8 @@ func (c CongestionTree) NumberOfNodes() int {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
// Branch returns the branch of the given vtxo txid from root to leaf in the order of the congestion tree
|
// Branch returns the branch of the given vtxo txid from root to leaf in the order of the vtxo tree
|
||||||
func (c CongestionTree) Branch(vtxoTxid string) ([]Node, error) {
|
func (c VtxoTree) Branch(vtxoTxid string) ([]Node, error) {
|
||||||
branch := make([]Node, 0)
|
branch := make([]Node, 0)
|
||||||
|
|
||||||
leaves := c.Leaves()
|
leaves := c.Leaves()
|
||||||
@@ -102,7 +102,7 @@ func (c CongestionTree) Branch(vtxoTxid string) ([]Node, error) {
|
|||||||
return branch, nil
|
return branch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n Node) findParent(tree CongestionTree) (Node, error) {
|
func (n Node) findParent(tree VtxoTree) (Node, error) {
|
||||||
for _, level := range tree {
|
for _, level := range tree {
|
||||||
for _, node := range level {
|
for _, node := range level {
|
||||||
if node.Txid == n.ParentTxid {
|
if node.Txid == n.ParentTxid {
|
||||||
|
|||||||
@@ -8,13 +8,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func BuildForfeitTxs(
|
func BuildForfeitTxs(
|
||||||
connectorTx *psetv2.Pset,
|
connectorTx *psetv2.Pset, vtxoInput psetv2.InputArgs,
|
||||||
vtxoInput psetv2.InputArgs,
|
vtxoAmount, connectorAmount, feeAmount uint64,
|
||||||
vtxoAmount,
|
vtxoScript, serverScript []byte,
|
||||||
connectorAmount,
|
|
||||||
feeAmount uint64,
|
|
||||||
vtxoScript,
|
|
||||||
aspScript []byte,
|
|
||||||
) (forfeitTxs []*psetv2.Pset, err error) {
|
) (forfeitTxs []*psetv2.Pset, err error) {
|
||||||
connectors, prevouts := getConnectorInputs(connectorTx, connectorAmount)
|
connectors, prevouts := getConnectorInputs(connectorTx, connectorAmount)
|
||||||
|
|
||||||
@@ -63,7 +59,7 @@ func BuildForfeitTxs(
|
|||||||
{
|
{
|
||||||
Asset: asset,
|
Asset: asset,
|
||||||
Amount: vtxoAmount + connectorAmount - feeAmount,
|
Amount: vtxoAmount + connectorAmount - feeAmount,
|
||||||
Script: aspScript,
|
Script: serverScript,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Asset: asset,
|
Asset: asset,
|
||||||
|
|||||||
@@ -281,10 +281,10 @@ func (f *MultisigClosure) Witness(controlBlock []byte, signatures map[string][]b
|
|||||||
|
|
||||||
// Add signatures in the reverse order as public keys
|
// Add signatures in the reverse order as public keys
|
||||||
for i := len(f.PubKeys) - 1; i >= 0; i-- {
|
for i := len(f.PubKeys) - 1; i >= 0; i-- {
|
||||||
pubKey := f.PubKeys[i]
|
pubkey := f.PubKeys[i]
|
||||||
sig, ok := signatures[hex.EncodeToString(schnorr.SerializePubKey(pubKey))]
|
sig, ok := signatures[hex.EncodeToString(schnorr.SerializePubKey(pubkey))]
|
||||||
if !ok {
|
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)
|
witness = append(witness, sig)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,17 +36,17 @@ func TestRoundTripCSV(t *testing.T) {
|
|||||||
|
|
||||||
func TestMultisigClosure(t *testing.T) {
|
func TestMultisigClosure(t *testing.T) {
|
||||||
// Generate some test keys
|
// Generate some test keys
|
||||||
privKey1, err := secp256k1.GeneratePrivateKey()
|
prvkey1, err := secp256k1.GeneratePrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pubKey1 := privKey1.PubKey()
|
pubkey1 := prvkey1.PubKey()
|
||||||
|
|
||||||
privKey2, err := secp256k1.GeneratePrivateKey()
|
prvkey2, err := secp256k1.GeneratePrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pubKey2 := privKey2.PubKey()
|
pubkey2 := prvkey2.PubKey()
|
||||||
|
|
||||||
t.Run("valid 2-of-2 multisig", func(t *testing.T) {
|
t.Run("valid 2-of-2 multisig", func(t *testing.T) {
|
||||||
closure := &tree.MultisigClosure{
|
closure := &tree.MultisigClosure{
|
||||||
PubKeys: []*secp256k1.PublicKey{pubKey1, pubKey2},
|
PubKeys: []*secp256k1.PublicKey{pubkey1, pubkey2},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate script
|
// Generate script
|
||||||
@@ -62,18 +62,18 @@ func TestMultisigClosure(t *testing.T) {
|
|||||||
|
|
||||||
// Compare serialized pubkeys
|
// Compare serialized pubkeys
|
||||||
require.Equal(t,
|
require.Equal(t,
|
||||||
schnorr.SerializePubKey(pubKey1),
|
schnorr.SerializePubKey(pubkey1),
|
||||||
schnorr.SerializePubKey(decodedClosure.PubKeys[0]),
|
schnorr.SerializePubKey(decodedClosure.PubKeys[0]),
|
||||||
)
|
)
|
||||||
require.Equal(t,
|
require.Equal(t,
|
||||||
schnorr.SerializePubKey(pubKey2),
|
schnorr.SerializePubKey(pubkey2),
|
||||||
schnorr.SerializePubKey(decodedClosure.PubKeys[1]),
|
schnorr.SerializePubKey(decodedClosure.PubKeys[1]),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("valid single key multisig", func(t *testing.T) {
|
t.Run("valid single key multisig", func(t *testing.T) {
|
||||||
closure := &tree.MultisigClosure{
|
closure := &tree.MultisigClosure{
|
||||||
PubKeys: []*secp256k1.PublicKey{pubKey1},
|
PubKeys: []*secp256k1.PublicKey{pubkey1},
|
||||||
}
|
}
|
||||||
|
|
||||||
script, err := closure.Script()
|
script, err := closure.Script()
|
||||||
@@ -87,7 +87,7 @@ func TestMultisigClosure(t *testing.T) {
|
|||||||
|
|
||||||
// Compare serialized pubkey
|
// Compare serialized pubkey
|
||||||
require.Equal(t,
|
require.Equal(t,
|
||||||
schnorr.SerializePubKey(pubKey1),
|
schnorr.SerializePubKey(pubkey1),
|
||||||
schnorr.SerializePubKey(decodedClosure.PubKeys[0]),
|
schnorr.SerializePubKey(decodedClosure.PubKeys[0]),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -110,9 +110,9 @@ func TestMultisigClosure(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("invalid script - missing checksig", func(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 := []byte{txscript.OP_DATA_32}
|
||||||
script = append(script, pubKeyBytes...)
|
script = append(script, pubkeyBytes...)
|
||||||
// Missing OP_CHECKSIG
|
// Missing OP_CHECKSIG
|
||||||
|
|
||||||
closure := &tree.MultisigClosure{}
|
closure := &tree.MultisigClosure{}
|
||||||
@@ -122,9 +122,9 @@ func TestMultisigClosure(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("invalid script - extra data after checksig", func(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 := []byte{txscript.OP_DATA_32}
|
||||||
script = append(script, pubKeyBytes...)
|
script = append(script, pubkeyBytes...)
|
||||||
script = append(script, txscript.OP_CHECKSIG)
|
script = append(script, txscript.OP_CHECKSIG)
|
||||||
script = append(script, 0x00) // Extra unwanted byte
|
script = append(script, 0x00) // Extra unwanted byte
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ func TestMultisigClosure(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("witness size", func(t *testing.T) {
|
t.Run("witness size", func(t *testing.T) {
|
||||||
closure := &tree.MultisigClosure{
|
closure := &tree.MultisigClosure{
|
||||||
PubKeys: []*secp256k1.PublicKey{pubKey1, pubKey2},
|
PubKeys: []*secp256k1.PublicKey{pubkey1, pubkey2},
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, 128, closure.WitnessSize()) // 64 * 2 bytes
|
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) {
|
t.Run("valid 12-of-12 multisig", func(t *testing.T) {
|
||||||
// Generate 12 keys
|
// Generate 12 keys
|
||||||
pubKeys := make([]*secp256k1.PublicKey, 12)
|
pubkeys := make([]*secp256k1.PublicKey, 12)
|
||||||
for i := 0; i < 12; i++ {
|
for i := 0; i < 12; i++ {
|
||||||
privKey, err := secp256k1.GeneratePrivateKey()
|
prvkey, err := secp256k1.GeneratePrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pubKeys[i] = privKey.PubKey()
|
pubkeys[i] = prvkey.PubKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
closure := &tree.MultisigClosure{
|
closure := &tree.MultisigClosure{
|
||||||
PubKeys: pubKeys,
|
PubKeys: pubkeys,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate script
|
// Generate script
|
||||||
@@ -169,7 +169,7 @@ func TestMultisigClosure(t *testing.T) {
|
|||||||
// Compare all serialized pubkeys
|
// Compare all serialized pubkeys
|
||||||
for i := 0; i < 12; i++ {
|
for i := 0; i < 12; i++ {
|
||||||
require.Equal(t,
|
require.Equal(t,
|
||||||
schnorr.SerializePubKey(pubKeys[i]),
|
schnorr.SerializePubKey(pubkeys[i]),
|
||||||
schnorr.SerializePubKey(decodedClosure.PubKeys[i]),
|
schnorr.SerializePubKey(decodedClosure.PubKeys[i]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -181,18 +181,18 @@ func TestMultisigClosure(t *testing.T) {
|
|||||||
|
|
||||||
func TestCSVSigClosure(t *testing.T) {
|
func TestCSVSigClosure(t *testing.T) {
|
||||||
// Generate test keys
|
// Generate test keys
|
||||||
privKey1, err := secp256k1.GeneratePrivateKey()
|
prvkey1, err := secp256k1.GeneratePrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pubKey1 := privKey1.PubKey()
|
pubkey1 := prvkey1.PubKey()
|
||||||
|
|
||||||
privKey2, err := secp256k1.GeneratePrivateKey()
|
prvkey2, err := secp256k1.GeneratePrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pubKey2 := privKey2.PubKey()
|
pubkey2 := prvkey2.PubKey()
|
||||||
|
|
||||||
t.Run("valid single key CSV", func(t *testing.T) {
|
t.Run("valid single key CSV", func(t *testing.T) {
|
||||||
csvSig := &tree.CSVSigClosure{
|
csvSig := &tree.CSVSigClosure{
|
||||||
MultisigClosure: tree.MultisigClosure{
|
MultisigClosure: tree.MultisigClosure{
|
||||||
PubKeys: []*secp256k1.PublicKey{pubKey1},
|
PubKeys: []*secp256k1.PublicKey{pubkey1},
|
||||||
},
|
},
|
||||||
Seconds: 1024,
|
Seconds: 1024,
|
||||||
}
|
}
|
||||||
@@ -207,7 +207,7 @@ func TestCSVSigClosure(t *testing.T) {
|
|||||||
require.Equal(t, uint32(1024), uint32(decodedCSV.Seconds))
|
require.Equal(t, uint32(1024), uint32(decodedCSV.Seconds))
|
||||||
require.Equal(t, 1, len(decodedCSV.PubKeys))
|
require.Equal(t, 1, len(decodedCSV.PubKeys))
|
||||||
require.Equal(t,
|
require.Equal(t,
|
||||||
schnorr.SerializePubKey(pubKey1),
|
schnorr.SerializePubKey(pubkey1),
|
||||||
schnorr.SerializePubKey(decodedCSV.PubKeys[0]),
|
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) {
|
t.Run("valid 2-of-2 CSV", func(t *testing.T) {
|
||||||
csvSig := &tree.CSVSigClosure{
|
csvSig := &tree.CSVSigClosure{
|
||||||
MultisigClosure: tree.MultisigClosure{
|
MultisigClosure: tree.MultisigClosure{
|
||||||
PubKeys: []*secp256k1.PublicKey{pubKey1, pubKey2},
|
PubKeys: []*secp256k1.PublicKey{pubkey1, pubkey2},
|
||||||
},
|
},
|
||||||
Seconds: 2016, // ~2 weeks
|
Seconds: 2016, // ~2 weeks
|
||||||
}
|
}
|
||||||
@@ -230,11 +230,11 @@ func TestCSVSigClosure(t *testing.T) {
|
|||||||
require.Equal(t, uint32(2016), uint32(decodedCSV.Seconds))
|
require.Equal(t, uint32(2016), uint32(decodedCSV.Seconds))
|
||||||
require.Equal(t, 2, len(decodedCSV.PubKeys))
|
require.Equal(t, 2, len(decodedCSV.PubKeys))
|
||||||
require.Equal(t,
|
require.Equal(t,
|
||||||
schnorr.SerializePubKey(pubKey1),
|
schnorr.SerializePubKey(pubkey1),
|
||||||
schnorr.SerializePubKey(decodedCSV.PubKeys[0]),
|
schnorr.SerializePubKey(decodedCSV.PubKeys[0]),
|
||||||
)
|
)
|
||||||
require.Equal(t,
|
require.Equal(t,
|
||||||
schnorr.SerializePubKey(pubKey2),
|
schnorr.SerializePubKey(pubkey2),
|
||||||
schnorr.SerializePubKey(decodedCSV.PubKeys[1]),
|
schnorr.SerializePubKey(decodedCSV.PubKeys[1]),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -248,9 +248,9 @@ func TestCSVSigClosure(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("invalid CSV value", func(t *testing.T) {
|
t.Run("invalid CSV value", func(t *testing.T) {
|
||||||
// Create a script with invalid CSV value
|
// Create a script with invalid CSV value
|
||||||
pubKeyBytes := schnorr.SerializePubKey(pubKey1)
|
pubkeyBytes := schnorr.SerializePubKey(pubkey1)
|
||||||
script := []byte{txscript.OP_DATA_32}
|
script := []byte{txscript.OP_DATA_32}
|
||||||
script = append(script, pubKeyBytes...)
|
script = append(script, pubkeyBytes...)
|
||||||
script = append(script, txscript.OP_CHECKSIG)
|
script = append(script, txscript.OP_CHECKSIG)
|
||||||
script = append(script, 0xFF) // Invalid CSV value
|
script = append(script, 0xFF) // Invalid CSV value
|
||||||
|
|
||||||
@@ -263,7 +263,7 @@ func TestCSVSigClosure(t *testing.T) {
|
|||||||
t.Run("witness size", func(t *testing.T) {
|
t.Run("witness size", func(t *testing.T) {
|
||||||
csvSig := &tree.CSVSigClosure{
|
csvSig := &tree.CSVSigClosure{
|
||||||
MultisigClosure: tree.MultisigClosure{
|
MultisigClosure: tree.MultisigClosure{
|
||||||
PubKeys: []*secp256k1.PublicKey{pubKey1, pubKey2},
|
PubKeys: []*secp256k1.PublicKey{pubkey1, pubkey2},
|
||||||
},
|
},
|
||||||
Seconds: 1024,
|
Seconds: 1024,
|
||||||
}
|
}
|
||||||
@@ -274,7 +274,7 @@ func TestCSVSigClosure(t *testing.T) {
|
|||||||
t.Run("max timelock", func(t *testing.T) {
|
t.Run("max timelock", func(t *testing.T) {
|
||||||
csvSig := &tree.CSVSigClosure{
|
csvSig := &tree.CSVSigClosure{
|
||||||
MultisigClosure: tree.MultisigClosure{
|
MultisigClosure: tree.MultisigClosure{
|
||||||
PubKeys: []*secp256k1.PublicKey{pubKey1},
|
PubKeys: []*secp256k1.PublicKey{pubkey1},
|
||||||
},
|
},
|
||||||
Seconds: 65535, // Maximum allowed value
|
Seconds: 65535, // Maximum allowed value
|
||||||
}
|
}
|
||||||
@@ -438,22 +438,22 @@ func TestCSVSigClosureWitness(t *testing.T) {
|
|||||||
|
|
||||||
func TestDecodeChecksigAdd(t *testing.T) {
|
func TestDecodeChecksigAdd(t *testing.T) {
|
||||||
// Generate some test public keys
|
// Generate some test public keys
|
||||||
pubKey1, err := secp256k1.GeneratePrivateKey()
|
pubkey1, err := secp256k1.GeneratePrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pubKey2, err := secp256k1.GeneratePrivateKey()
|
pubkey2, err := secp256k1.GeneratePrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pubKey3, err := secp256k1.GeneratePrivateKey()
|
pubkey3, err := secp256k1.GeneratePrivateKey()
|
||||||
require.NoError(t, err)
|
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
|
// Create a script for 3-of-3 multisig using CHECKSIGADD
|
||||||
scriptBuilder := txscript.NewScriptBuilder().
|
scriptBuilder := txscript.NewScriptBuilder().
|
||||||
AddData(schnorr.SerializePubKey(pubKeys[0])).
|
AddData(schnorr.SerializePubKey(pubkeys[0])).
|
||||||
AddOp(txscript.OP_CHECKSIG).
|
AddOp(txscript.OP_CHECKSIG).
|
||||||
AddData(schnorr.SerializePubKey(pubKeys[1])).
|
AddData(schnorr.SerializePubKey(pubkeys[1])).
|
||||||
AddOp(txscript.OP_CHECKSIGADD).
|
AddOp(txscript.OP_CHECKSIGADD).
|
||||||
AddData(schnorr.SerializePubKey(pubKeys[2])).
|
AddData(schnorr.SerializePubKey(pubkeys[2])).
|
||||||
AddOp(txscript.OP_CHECKSIGADD).
|
AddOp(txscript.OP_CHECKSIGADD).
|
||||||
AddInt64(3).
|
AddInt64(3).
|
||||||
AddOp(txscript.OP_EQUAL)
|
AddOp(txscript.OP_EQUAL)
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import (
|
|||||||
"github.com/vulpemventures/go-elements/psetv2"
|
"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 {
|
type VtxoLeaf struct {
|
||||||
Pubkey string
|
PubKey string
|
||||||
Amount uint64
|
Amount uint64
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,37 +13,37 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidPoolTransaction = errors.New("invalid pool transaction")
|
ErrInvalidRoundTx = fmt.Errorf("invalid round transaction")
|
||||||
ErrInvalidPoolTransactionOutputs = errors.New("invalid number of outputs in pool transaction")
|
ErrInvalidRoundTxOutputs = fmt.Errorf("invalid number of outputs in round transaction")
|
||||||
ErrEmptyTree = errors.New("empty congestion tree")
|
ErrEmptyTree = fmt.Errorf("empty vtxo tree")
|
||||||
ErrInvalidRootLevel = errors.New("root level must have only one node")
|
ErrInvalidRootLevel = fmt.Errorf("root level must have only one node")
|
||||||
ErrNoLeaves = errors.New("no leaves in the tree")
|
ErrNoLeaves = fmt.Errorf("no leaves in the tree")
|
||||||
ErrNodeTransactionEmpty = errors.New("node transaction is empty")
|
ErrNodeTxEmpty = fmt.Errorf("node transaction is empty")
|
||||||
ErrNodeTxidEmpty = errors.New("node txid is empty")
|
ErrNodeTxidEmpty = fmt.Errorf("node txid is empty")
|
||||||
ErrNodeParentTxidEmpty = errors.New("node parent txid is empty")
|
ErrNodeParentTxidEmpty = fmt.Errorf("node parent txid is empty")
|
||||||
ErrNodeTxidDifferent = errors.New("node txid differs from node transaction")
|
ErrNodeTxidDifferent = fmt.Errorf("node txid differs from node transaction")
|
||||||
ErrNumberOfInputs = errors.New("node transaction should have only one input")
|
ErrNumberOfInputs = fmt.Errorf("node transaction should have only one input")
|
||||||
ErrNumberOfOutputs = errors.New("node transaction should have only three or two outputs")
|
ErrNumberOfOutputs = fmt.Errorf("node transaction should have only three or two outputs")
|
||||||
ErrParentTxidInput = errors.New("parent txid should be the input of the node transaction")
|
ErrParentTxidInput = fmt.Errorf("parent txid should be the input of the node transaction")
|
||||||
ErrNumberOfChildren = errors.New("node branch transaction should have two children")
|
ErrNumberOfChildren = fmt.Errorf("node branch transaction should have two children")
|
||||||
ErrLeafChildren = errors.New("leaf node should have max 1 child")
|
ErrLeafChildren = fmt.Errorf("leaf node should have max 1 child")
|
||||||
ErrInvalidChildTxid = errors.New("invalid child txid")
|
ErrInvalidChildTxid = fmt.Errorf("invalid child txid")
|
||||||
ErrNumberOfTapscripts = errors.New("input should have two tapscripts leaves")
|
ErrNumberOfTapscripts = fmt.Errorf("input should have 1 tapscript leaf")
|
||||||
ErrInternalKey = errors.New("taproot internal key is not unspendable")
|
ErrInternalKey = fmt.Errorf("invalid taproot internal key")
|
||||||
ErrInvalidTaprootScript = errors.New("invalid taproot script")
|
ErrInvalidTaprootScript = fmt.Errorf("invalid taproot script")
|
||||||
ErrInvalidTaprootScriptLen = errors.New("invalid taproot script length (expected 32 bytes)")
|
ErrInvalidTaprootScriptLen = fmt.Errorf("invalid taproot script length (expected 32 bytes)")
|
||||||
ErrInvalidLeafTaprootScript = errors.New("invalid leaf taproot script")
|
ErrInvalidLeafTaprootScript = fmt.Errorf("invalid leaf taproot script")
|
||||||
ErrInvalidAmount = errors.New("children amount is different from parent amount")
|
ErrInvalidAmount = fmt.Errorf("children amount is different from parent amount")
|
||||||
ErrInvalidAsset = errors.New("invalid output asset")
|
ErrInvalidAsset = errors.New("invalid output asset")
|
||||||
ErrInvalidSweepSequence = errors.New("invalid sweep sequence")
|
ErrInvalidSweepSequence = fmt.Errorf("invalid sweep sequence")
|
||||||
ErrInvalidASP = errors.New("invalid ASP")
|
ErrInvalidServer = fmt.Errorf("invalid server")
|
||||||
ErrMissingFeeOutput = errors.New("missing fee output")
|
ErrMissingFeeOutput = fmt.Errorf("missing fee output")
|
||||||
ErrInvalidLeftOutput = errors.New("invalid left output")
|
ErrInvalidLeftOutput = fmt.Errorf("invalid left output")
|
||||||
ErrInvalidRightOutput = errors.New("invalid right output")
|
ErrInvalidRightOutput = fmt.Errorf("invalid right output")
|
||||||
ErrMissingSweepTapscript = errors.New("missing sweep tapscript")
|
ErrMissingSweepTapscript = fmt.Errorf("missing sweep tapscript")
|
||||||
ErrMissingBranchTapscript = errors.New("missing branch tapscript")
|
ErrMissingBranchTapscript = errors.New("missing branch tapscript")
|
||||||
ErrInvalidLeaf = errors.New("leaf node shouldn't have children")
|
ErrInvalidLeaf = fmt.Errorf("leaf node shouldn't have children")
|
||||||
ErrWrongPoolTxID = errors.New("root input should be the pool tx outpoint")
|
ErrWrongRoundTxid = fmt.Errorf("the input of the tree root is not the round tx's shared output")
|
||||||
)
|
)
|
||||||
|
|
||||||
// 0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0
|
// 0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0
|
||||||
@@ -61,36 +61,36 @@ func UnspendableKey() *secp256k1.PublicKey {
|
|||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateCongestionTree checks if the given congestion tree is valid
|
// ValidateVtxoTree checks if the given vtxo tree is valid
|
||||||
// poolTxID & poolTxIndex & poolTxAmount are used to validate the root input outpoint
|
// roundTxid & roundTxIndex & roundTxAmount are used to validate the root input outpoint
|
||||||
// aspPublicKey & roundLifetime are used to validate the sweep tapscript leaves
|
// serverPubkey & roundLifetime are used to validate the sweep tapscript leaves
|
||||||
// besides that, the function validates:
|
// besides that, the function validates:
|
||||||
// - the number of nodes
|
// - the number of nodes
|
||||||
// - the number of leaves
|
// - the number of leaves
|
||||||
// - children coherence with parent
|
// - children coherence with parent
|
||||||
// - every control block and taproot output scripts
|
// - every control block and taproot output scripts
|
||||||
// - input and output amounts
|
// - input and output amounts
|
||||||
func ValidateCongestionTree(
|
func ValidateVtxoTree(
|
||||||
tree CongestionTree, poolTx string, aspPublicKey *secp256k1.PublicKey,
|
tree VtxoTree, roundTx string, serverPubkey *secp256k1.PublicKey,
|
||||||
roundLifetime int64,
|
roundLifetime int64,
|
||||||
) error {
|
) error {
|
||||||
poolTransaction, err := psetv2.NewPsetFromBase64(poolTx)
|
roundTransaction, err := psetv2.NewPsetFromBase64(roundTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrInvalidPoolTransaction
|
return ErrInvalidRoundTx
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(poolTransaction.Outputs) < sharedOutputIndex+1 {
|
if len(roundTransaction.Outputs) < sharedOutputIndex+1 {
|
||||||
return ErrInvalidPoolTransactionOutputs
|
return ErrInvalidRoundTxOutputs
|
||||||
}
|
}
|
||||||
|
|
||||||
poolTxAmount := poolTransaction.Outputs[sharedOutputIndex].Value
|
roundTxAmount := roundTransaction.Outputs[sharedOutputIndex].Value
|
||||||
|
|
||||||
utx, err := poolTransaction.UnsignedTx()
|
utx, err := roundTransaction.UnsignedTx()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrInvalidPoolTransaction
|
return ErrInvalidRoundTx
|
||||||
}
|
}
|
||||||
|
|
||||||
poolTxID := utx.TxHash().String()
|
roundTxid := utx.TxHash().String()
|
||||||
|
|
||||||
nbNodes := tree.NumberOfNodes()
|
nbNodes := tree.NumberOfNodes()
|
||||||
if nbNodes == 0 {
|
if nbNodes == 0 {
|
||||||
@@ -101,7 +101,7 @@ func ValidateCongestionTree(
|
|||||||
return ErrInvalidRootLevel
|
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
|
rootPsetB64 := tree[0][0].Tx
|
||||||
rootPset, err := psetv2.NewPsetFromBase64(rootPsetB64)
|
rootPset, err := psetv2.NewPsetFromBase64(rootPsetB64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -113,9 +113,9 @@ func ValidateCongestionTree(
|
|||||||
}
|
}
|
||||||
|
|
||||||
rootInput := rootPset.Inputs[0]
|
rootInput := rootPset.Inputs[0]
|
||||||
if chainhash.Hash(rootInput.PreviousTxid).String() != poolTxID ||
|
if chainhash.Hash(rootInput.PreviousTxid).String() != roundTxid ||
|
||||||
rootInput.PreviousTxIndex != sharedOutputIndex {
|
rootInput.PreviousTxIndex != sharedOutputIndex {
|
||||||
return ErrWrongPoolTxID
|
return ErrWrongRoundTxid
|
||||||
}
|
}
|
||||||
|
|
||||||
sumRootValue := uint64(0)
|
sumRootValue := uint64(0)
|
||||||
@@ -123,7 +123,7 @@ func ValidateCongestionTree(
|
|||||||
sumRootValue += output.Value
|
sumRootValue += output.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
if sumRootValue != poolTxAmount {
|
if sumRootValue != roundTxAmount {
|
||||||
return ErrInvalidAmount
|
return ErrInvalidAmount
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ func ValidateCongestionTree(
|
|||||||
for _, level := range tree {
|
for _, level := range tree {
|
||||||
for _, node := range level {
|
for _, node := range level {
|
||||||
if err := validateNodeTransaction(
|
if err := validateNodeTransaction(
|
||||||
node, tree, UnspendableKey(), aspPublicKey, roundLifetime,
|
node, tree, UnspendableKey(), serverPubkey, roundLifetime,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -146,12 +146,12 @@ func ValidateCongestionTree(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func validateNodeTransaction(
|
func validateNodeTransaction(
|
||||||
node Node, tree CongestionTree,
|
node Node, tree VtxoTree,
|
||||||
expectedInternalKey, expectedPublicKeyASP *secp256k1.PublicKey,
|
expectedInternalKey, expectedServerPubkey *secp256k1.PublicKey,
|
||||||
expectedSequence int64,
|
expectedSequence int64,
|
||||||
) error {
|
) error {
|
||||||
if node.Tx == "" {
|
if node.Tx == "" {
|
||||||
return ErrNodeTransactionEmpty
|
return ErrNodeTxEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.Txid == "" {
|
if node.Txid == "" {
|
||||||
@@ -238,21 +238,21 @@ func validateNodeTransaction(
|
|||||||
|
|
||||||
switch c := closure.(type) {
|
switch c := closure.(type) {
|
||||||
case *CSVSigClosure:
|
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(c.MultisigClosure.PubKeys[0]),
|
||||||
schnorr.SerializePubKey(expectedPublicKeyASP),
|
schnorr.SerializePubKey(expectedServerPubkey),
|
||||||
)
|
)
|
||||||
isSweepDelay := int64(c.Seconds) == expectedSequence
|
isSweepDelay := int64(c.Seconds) == expectedSequence
|
||||||
|
|
||||||
if isASP && !isSweepDelay {
|
if isServer && !isSweepDelay {
|
||||||
return ErrInvalidSweepSequence
|
return ErrInvalidSweepSequence
|
||||||
}
|
}
|
||||||
|
|
||||||
if isSweepDelay && !isASP {
|
if isSweepDelay && !isServer {
|
||||||
return ErrInvalidASP
|
return ErrInvalidServer
|
||||||
}
|
}
|
||||||
|
|
||||||
if isASP && isSweepDelay {
|
if isServer && isSweepDelay {
|
||||||
sweepLeafFound = true
|
sweepLeafFound = true
|
||||||
}
|
}
|
||||||
case *UnrollClosure:
|
case *UnrollClosure:
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ func ParseVtxoScript(scripts []string) (VtxoScript, error) {
|
|||||||
return v, err
|
return v, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDefaultVtxoScript(owner, asp *secp256k1.PublicKey, exitDelay uint) *TapscriptsVtxoScript {
|
func NewDefaultVtxoScript(owner, server *secp256k1.PublicKey, exitDelay uint) *TapscriptsVtxoScript {
|
||||||
return &TapscriptsVtxoScript{
|
return &TapscriptsVtxoScript{
|
||||||
[]Closure{
|
[]Closure{
|
||||||
&CSVSigClosure{
|
&CSVSigClosure{
|
||||||
MultisigClosure: MultisigClosure{PubKeys: []*secp256k1.PublicKey{owner}},
|
MultisigClosure: MultisigClosure{PubKeys: []*secp256k1.PublicKey{owner}},
|
||||||
Seconds: exitDelay,
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *TapscriptsVtxoScript) Validate(asp *secp256k1.PublicKey, minExitDelay uint) error {
|
func (v *TapscriptsVtxoScript) Validate(server *secp256k1.PublicKey, minExitDelay uint) error {
|
||||||
aspXonly := schnorr.SerializePubKey(asp)
|
serverXonly := schnorr.SerializePubKey(server)
|
||||||
for _, forfeit := range v.ForfeitClosures() {
|
for _, forfeit := range v.ForfeitClosures() {
|
||||||
// must contain asp pubkey
|
// must contain server pubkey
|
||||||
found := false
|
found := false
|
||||||
for _, pubkey := range forfeit.PubKeys {
|
for _, pubkey := range forfeit.PubKeys {
|
||||||
if bytes.Equal(schnorr.SerializePubKey(pubkey), aspXonly) {
|
if bytes.Equal(schnorr.SerializePubKey(pubkey), serverXonly) {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
return fmt.Errorf("invalid forfeit closure, ASP pubkey not found")
|
return fmt.Errorf("invalid forfeit closure, server pubkey not found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
It may also contain others closures implementing specific use cases.
|
||||||
|
|
||||||
VtxoScript abstracts the taproot complexity behind vtxo contracts.
|
VtxoScript abstracts the taproot complexity behind vtxo contracts.
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ type ArkClient interface {
|
|||||||
CollaborativeRedeem(
|
CollaborativeRedeem(
|
||||||
ctx context.Context, addr string, amount uint64, withExpiryCoinselect bool,
|
ctx context.Context, addr string, amount uint64, withExpiryCoinselect bool,
|
||||||
) (string, error)
|
) (string, error)
|
||||||
SendAsync(ctx context.Context, withExpiryCoinselect bool, receivers []Receiver) (string, error)
|
|
||||||
Settle(ctx context.Context) (string, error)
|
Settle(ctx context.Context) (string, error)
|
||||||
ListVtxos(ctx context.Context) (spendable, spent []client.Vtxo, err error)
|
ListVtxos(ctx context.Context) (spendable, spent []client.Vtxo, err error)
|
||||||
Dump(ctx context.Context) (seed string, err error)
|
Dump(ctx context.Context) (seed string, err error)
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ type arkClient struct {
|
|||||||
wallet wallet.WalletService
|
wallet wallet.WalletService
|
||||||
store types.Store
|
store types.Store
|
||||||
explorer explorer.Explorer
|
explorer explorer.Explorer
|
||||||
client client.ASPClient
|
client client.TransportClient
|
||||||
|
|
||||||
txStreamCtxCancel context.CancelFunc
|
txStreamCtxCancel context.CancelFunc
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ func (a *arkClient) initWithWallet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
clientSvc, err := getClient(
|
clientSvc, err := getClient(
|
||||||
supportedClients, args.ClientType, args.AspUrl,
|
supportedClients, args.ClientType, args.ServerUrl,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to setup client: %s", err)
|
return fmt.Errorf("failed to setup client: %s", err)
|
||||||
@@ -127,7 +127,7 @@ func (a *arkClient) initWithWallet(
|
|||||||
|
|
||||||
info, err := clientSvc.GetInfo(ctx)
|
info, err := clientSvc.GetInfo(ctx)
|
||||||
if err != nil {
|
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)
|
explorerSvc, err := getExplorer(args.ExplorerURL, info.Network)
|
||||||
@@ -137,18 +137,18 @@ func (a *arkClient) initWithWallet(
|
|||||||
|
|
||||||
network := utils.NetworkFromString(info.Network)
|
network := utils.NetworkFromString(info.Network)
|
||||||
|
|
||||||
buf, err := hex.DecodeString(info.Pubkey)
|
buf, err := hex.DecodeString(info.PubKey)
|
||||||
if err != nil {
|
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 {
|
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{
|
storeData := types.Config{
|
||||||
AspUrl: args.AspUrl,
|
ServerUrl: args.ServerUrl,
|
||||||
AspPubkey: aspPubkey,
|
ServerPubKey: serverPubkey,
|
||||||
WalletType: args.Wallet.GetType(),
|
WalletType: args.Wallet.GetType(),
|
||||||
ClientType: args.ClientType,
|
ClientType: args.ClientType,
|
||||||
Network: network,
|
Network: network,
|
||||||
@@ -186,7 +186,7 @@ func (a *arkClient) init(
|
|||||||
}
|
}
|
||||||
|
|
||||||
clientSvc, err := getClient(
|
clientSvc, err := getClient(
|
||||||
supportedClients, args.ClientType, args.AspUrl,
|
supportedClients, args.ClientType, args.ServerUrl,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to setup client: %s", err)
|
return fmt.Errorf("failed to setup client: %s", err)
|
||||||
@@ -194,7 +194,7 @@ func (a *arkClient) init(
|
|||||||
|
|
||||||
info, err := clientSvc.GetInfo(ctx)
|
info, err := clientSvc.GetInfo(ctx)
|
||||||
if err != nil {
|
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)
|
explorerSvc, err := getExplorer(args.ExplorerURL, info.Network)
|
||||||
@@ -204,18 +204,18 @@ func (a *arkClient) init(
|
|||||||
|
|
||||||
network := utils.NetworkFromString(info.Network)
|
network := utils.NetworkFromString(info.Network)
|
||||||
|
|
||||||
buf, err := hex.DecodeString(info.Pubkey)
|
buf, err := hex.DecodeString(info.PubKey)
|
||||||
if err != nil {
|
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 {
|
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{
|
cfgData := types.Config{
|
||||||
AspUrl: args.AspUrl,
|
ServerUrl: args.ServerUrl,
|
||||||
AspPubkey: aspPubkey,
|
ServerPubKey: serverPubkey,
|
||||||
WalletType: args.WalletType,
|
WalletType: args.WalletType,
|
||||||
ClientType: args.ClientType,
|
ClientType: args.ClientType,
|
||||||
Network: network,
|
Network: network,
|
||||||
@@ -252,17 +252,17 @@ func (a *arkClient) init(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *arkClient) ping(
|
func (a *arkClient) ping(
|
||||||
ctx context.Context, paymentID string,
|
ctx context.Context, requestID string,
|
||||||
) func() {
|
) func() {
|
||||||
ticker := time.NewTicker(5 * time.Second)
|
ticker := time.NewTicker(5 * time.Second)
|
||||||
|
|
||||||
go func(t *time.Ticker) {
|
go func(t *time.Ticker) {
|
||||||
if err := a.client.Ping(ctx, paymentID); err != nil {
|
if err := a.client.Ping(ctx, requestID); err != nil {
|
||||||
logrus.Warnf("failed to ping asp: %s", err)
|
logrus.Warnf("failed to ping server: %s", err)
|
||||||
}
|
}
|
||||||
for range t.C {
|
for range t.C {
|
||||||
if err := a.client.Ping(ctx, paymentID); err != nil {
|
if err := a.client.Ping(ctx, requestID); err != nil {
|
||||||
logrus.Warnf("failed to ping asp: %s", err)
|
logrus.Warnf("failed to ping server: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(ticker)
|
}(ticker)
|
||||||
@@ -292,10 +292,10 @@ func (a *arkClient) ListVtxos(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getClient(
|
func getClient(
|
||||||
supportedClients utils.SupportedType[utils.ClientFactory], clientType, aspUrl string,
|
supportedClients utils.SupportedType[utils.ClientFactory], clientType, serverUrl string,
|
||||||
) (client.ASPClient, error) {
|
) (client.TransportClient, error) {
|
||||||
factory := supportedClients[clientType]
|
factory := supportedClients[clientType]
|
||||||
return factory(aspUrl)
|
return factory(serverUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExplorer(explorerURL, network string) (explorer.Explorer, error) {
|
func getExplorer(explorerURL, network string) (explorer.Explorer, error) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ type RoundEvent interface {
|
|||||||
isRoundEvent()
|
isRoundEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
type ASPClient interface {
|
type TransportClient interface {
|
||||||
GetInfo(ctx context.Context) (*Info, error)
|
GetInfo(ctx context.Context) (*Info, error)
|
||||||
RegisterInputsForNextRound(
|
RegisterInputsForNextRound(
|
||||||
ctx context.Context, inputs []Input, ephemeralKey string,
|
ctx context.Context, inputs []Input, ephemeralKey string,
|
||||||
@@ -31,7 +31,7 @@ type ASPClient interface {
|
|||||||
ctx context.Context, notes []string, ephemeralKey string,
|
ctx context.Context, notes []string, ephemeralKey string,
|
||||||
) (string, error)
|
) (string, error)
|
||||||
RegisterOutputsForNextRound(
|
RegisterOutputsForNextRound(
|
||||||
ctx context.Context, paymentID string, outputs []Output,
|
ctx context.Context, requestID string, outputs []Output,
|
||||||
) error
|
) error
|
||||||
SubmitTreeNonces(
|
SubmitTreeNonces(
|
||||||
ctx context.Context, roundID, cosignerPubkey string, nonces bitcointree.TreeNonces,
|
ctx context.Context, roundID, cosignerPubkey string, nonces bitcointree.TreeNonces,
|
||||||
@@ -43,9 +43,9 @@ type ASPClient interface {
|
|||||||
ctx context.Context, signedForfeitTxs []string, signedRoundTx string,
|
ctx context.Context, signedForfeitTxs []string, signedRoundTx string,
|
||||||
) error
|
) error
|
||||||
GetEventStream(
|
GetEventStream(
|
||||||
ctx context.Context, paymentID string,
|
ctx context.Context, requestID string,
|
||||||
) (<-chan RoundEventChannel, func(), error)
|
) (<-chan RoundEventChannel, func(), error)
|
||||||
Ping(ctx context.Context, paymentID string) error
|
Ping(ctx context.Context, requestID string) error
|
||||||
SubmitRedeemTx(
|
SubmitRedeemTx(
|
||||||
ctx context.Context, signedRedeemTx string,
|
ctx context.Context, signedRedeemTx string,
|
||||||
) (string, error)
|
) (string, error)
|
||||||
@@ -59,7 +59,7 @@ type ASPClient interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Info struct {
|
type Info struct {
|
||||||
Pubkey string
|
PubKey string
|
||||||
RoundLifetime int64
|
RoundLifetime int64
|
||||||
UnilateralExitDelay int64
|
UnilateralExitDelay int64
|
||||||
RoundInterval int64
|
RoundInterval int64
|
||||||
@@ -90,7 +90,7 @@ type Input struct {
|
|||||||
|
|
||||||
type Vtxo struct {
|
type Vtxo struct {
|
||||||
Outpoint
|
Outpoint
|
||||||
Pubkey string
|
PubKey string
|
||||||
Amount uint64
|
Amount uint64
|
||||||
RoundTxid string
|
RoundTxid string
|
||||||
ExpiresAt time.Time
|
ExpiresAt time.Time
|
||||||
@@ -100,8 +100,8 @@ type Vtxo struct {
|
|||||||
SpentBy string
|
SpentBy string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Vtxo) Address(asp *secp256k1.PublicKey, net common.Network) (string, error) {
|
func (v Vtxo) Address(server *secp256k1.PublicKey, net common.Network) (string, error) {
|
||||||
pubkeyBytes, err := hex.DecodeString(v.Pubkey)
|
pubkeyBytes, err := hex.DecodeString(v.PubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -113,7 +113,7 @@ func (v Vtxo) Address(asp *secp256k1.PublicKey, net common.Network) (string, err
|
|||||||
|
|
||||||
a := &common.Address{
|
a := &common.Address{
|
||||||
HRP: net.Addr,
|
HRP: net.Addr,
|
||||||
Asp: asp,
|
Server: server,
|
||||||
VtxoTapKey: pubkey,
|
VtxoTapKey: pubkey,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ type Round struct {
|
|||||||
StartedAt *time.Time
|
StartedAt *time.Time
|
||||||
EndedAt *time.Time
|
EndedAt *time.Time
|
||||||
Tx string
|
Tx string
|
||||||
Tree tree.CongestionTree
|
Tree tree.VtxoTree
|
||||||
ForfeitTxs []string
|
ForfeitTxs []string
|
||||||
Connectors []string
|
Connectors []string
|
||||||
Stage RoundStage
|
Stage RoundStage
|
||||||
@@ -169,7 +169,7 @@ type Round struct {
|
|||||||
type RoundFinalizationEvent struct {
|
type RoundFinalizationEvent struct {
|
||||||
ID string
|
ID string
|
||||||
Tx string
|
Tx string
|
||||||
Tree tree.CongestionTree
|
Tree tree.VtxoTree
|
||||||
Connectors []string
|
Connectors []string
|
||||||
MinRelayFeeRate chainfee.SatPerKVByte
|
MinRelayFeeRate chainfee.SatPerKVByte
|
||||||
}
|
}
|
||||||
@@ -191,10 +191,10 @@ type RoundFailedEvent struct {
|
|||||||
func (e RoundFailedEvent) isRoundEvent() {}
|
func (e RoundFailedEvent) isRoundEvent() {}
|
||||||
|
|
||||||
type RoundSigningStartedEvent struct {
|
type RoundSigningStartedEvent struct {
|
||||||
ID string
|
ID string
|
||||||
UnsignedTree tree.CongestionTree
|
UnsignedTree tree.VtxoTree
|
||||||
CosignersPublicKeys []*secp256k1.PublicKey
|
CosignersPubKeys []*secp256k1.PublicKey
|
||||||
UnsignedRoundTx string
|
UnsignedRoundTx string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e RoundSigningStartedEvent) isRoundEvent() {}
|
func (e RoundSigningStartedEvent) isRoundEvent() {}
|
||||||
|
|||||||
@@ -23,31 +23,31 @@ import (
|
|||||||
type grpcClient struct {
|
type grpcClient struct {
|
||||||
conn *grpc.ClientConn
|
conn *grpc.ClientConn
|
||||||
svc arkv1.ArkServiceClient
|
svc arkv1.ArkServiceClient
|
||||||
treeCache *utils.Cache[tree.CongestionTree]
|
treeCache *utils.Cache[tree.VtxoTree]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(aspUrl string) (client.ASPClient, error) {
|
func NewClient(serverUrl string) (client.TransportClient, error) {
|
||||||
if len(aspUrl) <= 0 {
|
if len(serverUrl) <= 0 {
|
||||||
return nil, fmt.Errorf("missing asp url")
|
return nil, fmt.Errorf("missing server url")
|
||||||
}
|
}
|
||||||
|
|
||||||
creds := insecure.NewCredentials()
|
creds := insecure.NewCredentials()
|
||||||
port := 80
|
port := 80
|
||||||
if strings.HasPrefix(aspUrl, "https://") {
|
if strings.HasPrefix(serverUrl, "https://") {
|
||||||
aspUrl = strings.TrimPrefix(aspUrl, "https://")
|
serverUrl = strings.TrimPrefix(serverUrl, "https://")
|
||||||
creds = credentials.NewTLS(nil)
|
creds = credentials.NewTLS(nil)
|
||||||
port = 443
|
port = 443
|
||||||
}
|
}
|
||||||
if !strings.Contains(aspUrl, ":") {
|
if !strings.Contains(serverUrl, ":") {
|
||||||
aspUrl = fmt.Sprintf("%s:%d", aspUrl, port)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
svc := arkv1.NewArkServiceClient(conn)
|
svc := arkv1.NewArkServiceClient(conn)
|
||||||
treeCache := utils.NewCache[tree.CongestionTree]()
|
treeCache := utils.NewCache[tree.VtxoTree]()
|
||||||
|
|
||||||
return &grpcClient{conn, svc, treeCache}, nil
|
return &grpcClient{conn, svc, treeCache}, nil
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ func (a *grpcClient) GetInfo(ctx context.Context) (*client.Info, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &client.Info{
|
return &client.Info{
|
||||||
Pubkey: resp.GetPubkey(),
|
PubKey: resp.GetPubkey(),
|
||||||
RoundLifetime: resp.GetRoundLifetime(),
|
RoundLifetime: resp.GetRoundLifetime(),
|
||||||
UnilateralExitDelay: resp.GetUnilateralExitDelay(),
|
UnilateralExitDelay: resp.GetUnilateralExitDelay(),
|
||||||
RoundInterval: resp.GetRoundInterval(),
|
RoundInterval: resp.GetRoundInterval(),
|
||||||
@@ -84,20 +84,20 @@ func (a *grpcClient) GetBoardingAddress(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *grpcClient) RegisterInputsForNextRound(
|
func (a *grpcClient) RegisterInputsForNextRound(
|
||||||
ctx context.Context, inputs []client.Input, ephemeralPublicKey string,
|
ctx context.Context, inputs []client.Input, ephemeralPubkey string,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
req := &arkv1.RegisterInputsForNextRoundRequest{
|
req := &arkv1.RegisterInputsForNextRoundRequest{
|
||||||
Inputs: ins(inputs).toProto(),
|
Inputs: ins(inputs).toProto(),
|
||||||
}
|
}
|
||||||
if len(ephemeralPublicKey) > 0 {
|
if len(ephemeralPubkey) > 0 {
|
||||||
req.EphemeralPubkey = &ephemeralPublicKey
|
req.EphemeralPubkey = &ephemeralPubkey
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := a.svc.RegisterInputsForNextRound(ctx, req)
|
resp, err := a.svc.RegisterInputsForNextRound(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return resp.GetId(), nil
|
return resp.GetRequestId(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *grpcClient) RegisterNotesForNextRound(
|
func (a *grpcClient) RegisterNotesForNextRound(
|
||||||
@@ -113,15 +113,15 @@ func (a *grpcClient) RegisterNotesForNextRound(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return resp.GetId(), nil
|
return resp.GetRequestId(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *grpcClient) RegisterOutputsForNextRound(
|
func (a *grpcClient) RegisterOutputsForNextRound(
|
||||||
ctx context.Context, paymentID string, outputs []client.Output,
|
ctx context.Context, requestID string, outputs []client.Output,
|
||||||
) error {
|
) error {
|
||||||
req := &arkv1.RegisterOutputsForNextRoundRequest{
|
req := &arkv1.RegisterOutputsForNextRoundRequest{
|
||||||
Id: paymentID,
|
RequestId: requestID,
|
||||||
Outputs: outs(outputs).toProto(),
|
Outputs: outs(outputs).toProto(),
|
||||||
}
|
}
|
||||||
_, err := a.svc.RegisterOutputsForNextRound(ctx, req)
|
_, err := a.svc.RegisterOutputsForNextRound(ctx, req)
|
||||||
return err
|
return err
|
||||||
@@ -191,7 +191,7 @@ func (a *grpcClient) SubmitSignedForfeitTxs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *grpcClient) GetEventStream(
|
func (a *grpcClient) GetEventStream(
|
||||||
ctx context.Context, paymentID string,
|
ctx context.Context, requestID string,
|
||||||
) (<-chan client.RoundEventChannel, func(), error) {
|
) (<-chan client.RoundEventChannel, func(), error) {
|
||||||
req := &arkv1.GetEventStreamRequest{}
|
req := &arkv1.GetEventStreamRequest{}
|
||||||
stream, err := a.svc.GetEventStream(ctx, req)
|
stream, err := a.svc.GetEventStream(ctx, req)
|
||||||
@@ -236,10 +236,10 @@ func (a *grpcClient) GetEventStream(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *grpcClient) Ping(
|
func (a *grpcClient) Ping(
|
||||||
ctx context.Context, paymentID string,
|
ctx context.Context, requestID string,
|
||||||
) error {
|
) error {
|
||||||
req := &arkv1.PingRequest{
|
req := &arkv1.PingRequest{
|
||||||
PaymentId: paymentID,
|
RequestId: requestID,
|
||||||
}
|
}
|
||||||
_, err := a.svc.Ping(ctx, req)
|
_, err := a.svc.Ping(ctx, req)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -86,10 +86,10 @@ func (e event) toRoundEvent() (client.RoundEvent, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return client.RoundSigningStartedEvent{
|
return client.RoundSigningStartedEvent{
|
||||||
ID: ee.GetId(),
|
ID: ee.GetId(),
|
||||||
UnsignedTree: treeFromProto{ee.GetUnsignedVtxoTree()}.parse(),
|
UnsignedTree: treeFromProto{ee.GetUnsignedVtxoTree()}.parse(),
|
||||||
CosignersPublicKeys: pubkeys,
|
CosignersPubKeys: pubkeys,
|
||||||
UnsignedRoundTx: ee.GetUnsignedRoundTx(),
|
UnsignedRoundTx: ee.GetUnsignedRoundTx(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ func (v vtxo) toVtxo() client.Vtxo {
|
|||||||
IsPending: v.GetIsPending(),
|
IsPending: v.GetIsPending(),
|
||||||
RedeemTx: v.GetRedeemTx(),
|
RedeemTx: v.GetRedeemTx(),
|
||||||
SpentBy: v.GetSpentBy(),
|
SpentBy: v.GetSpentBy(),
|
||||||
Pubkey: v.GetPubkey(),
|
PubKey: v.GetPubkey(),
|
||||||
CreatedAt: time.Unix(v.GetCreatedAt(), 0),
|
CreatedAt: time.Unix(v.GetCreatedAt(), 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,8 +166,8 @@ type treeFromProto struct {
|
|||||||
*arkv1.Tree
|
*arkv1.Tree
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t treeFromProto) parse() tree.CongestionTree {
|
func (t treeFromProto) parse() tree.VtxoTree {
|
||||||
levels := make(tree.CongestionTree, 0, len(t.GetLevels()))
|
levels := make(tree.VtxoTree, 0, len(t.GetLevels()))
|
||||||
|
|
||||||
for _, level := range t.GetLevels() {
|
for _, level := range t.GetLevels() {
|
||||||
nodes := make([]tree.Node, 0, len(level.Nodes))
|
nodes := make([]tree.Node, 0, len(level.Nodes))
|
||||||
|
|||||||
@@ -32,12 +32,12 @@ type restClient struct {
|
|||||||
serverURL string
|
serverURL string
|
||||||
svc ark_service.ClientService
|
svc ark_service.ClientService
|
||||||
requestTimeout time.Duration
|
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 {
|
if len(serverURL) <= 0 {
|
||||||
return nil, fmt.Errorf("missing asp url")
|
return nil, fmt.Errorf("missing server url")
|
||||||
}
|
}
|
||||||
svc, err := newRestClient(serverURL)
|
svc, err := newRestClient(serverURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -45,7 +45,7 @@ func NewClient(serverURL string) (client.ASPClient, error) {
|
|||||||
}
|
}
|
||||||
// TODO: use twice the round interval.
|
// TODO: use twice the round interval.
|
||||||
reqTimeout := 15 * time.Second
|
reqTimeout := 15 * time.Second
|
||||||
treeCache := utils.NewCache[tree.CongestionTree]()
|
treeCache := utils.NewCache[tree.VtxoTree]()
|
||||||
|
|
||||||
return &restClient{serverURL, svc, reqTimeout, treeCache}, nil
|
return &restClient{serverURL, svc, reqTimeout, treeCache}, nil
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ func (a *restClient) GetInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &client.Info{
|
return &client.Info{
|
||||||
Pubkey: resp.Payload.Pubkey,
|
PubKey: resp.Payload.Pubkey,
|
||||||
RoundLifetime: int64(roundLifetime),
|
RoundLifetime: int64(roundLifetime),
|
||||||
UnilateralExitDelay: int64(unilateralExitDelay),
|
UnilateralExitDelay: int64(unilateralExitDelay),
|
||||||
RoundInterval: int64(roundInterval),
|
RoundInterval: int64(roundInterval),
|
||||||
@@ -108,7 +108,7 @@ func (a *restClient) GetBoardingAddress(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *restClient) RegisterInputsForNextRound(
|
func (a *restClient) RegisterInputsForNextRound(
|
||||||
ctx context.Context, inputs []client.Input, ephemeralPublicKey string,
|
ctx context.Context, inputs []client.Input, ephemeralPubkey string,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
ins := make([]*models.V1Input, 0, len(inputs))
|
ins := make([]*models.V1Input, 0, len(inputs))
|
||||||
for _, i := range inputs {
|
for _, i := range inputs {
|
||||||
@@ -125,8 +125,8 @@ func (a *restClient) RegisterInputsForNextRound(
|
|||||||
body := &models.V1RegisterInputsForNextRoundRequest{
|
body := &models.V1RegisterInputsForNextRoundRequest{
|
||||||
Inputs: ins,
|
Inputs: ins,
|
||||||
}
|
}
|
||||||
if len(ephemeralPublicKey) > 0 {
|
if len(ephemeralPubkey) > 0 {
|
||||||
body.EphemeralPubkey = ephemeralPublicKey
|
body.EphemeralPubkey = ephemeralPubkey
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := a.svc.ArkServiceRegisterInputsForNextRound(
|
resp, err := a.svc.ArkServiceRegisterInputsForNextRound(
|
||||||
@@ -136,7 +136,7 @@ func (a *restClient) RegisterInputsForNextRound(
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp.Payload.ID, nil
|
return resp.Payload.RequestID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *restClient) RegisterNotesForNextRound(
|
func (a *restClient) RegisterNotesForNextRound(
|
||||||
@@ -154,11 +154,11 @@ func (a *restClient) RegisterNotesForNextRound(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return resp.Payload.ID, nil
|
return resp.Payload.RequestID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *restClient) RegisterOutputsForNextRound(
|
func (a *restClient) RegisterOutputsForNextRound(
|
||||||
ctx context.Context, paymentID string, outputs []client.Output,
|
ctx context.Context, requestID string, outputs []client.Output,
|
||||||
) error {
|
) error {
|
||||||
outs := make([]*models.V1Output, 0, len(outputs))
|
outs := make([]*models.V1Output, 0, len(outputs))
|
||||||
for _, o := range outputs {
|
for _, o := range outputs {
|
||||||
@@ -168,8 +168,8 @@ func (a *restClient) RegisterOutputsForNextRound(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
body := models.V1RegisterOutputsForNextRoundRequest{
|
body := models.V1RegisterOutputsForNextRoundRequest{
|
||||||
ID: paymentID,
|
RequestID: requestID,
|
||||||
Outputs: outs,
|
Outputs: outs,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := a.svc.ArkServiceRegisterOutputsForNextRound(
|
_, err := a.svc.ArkServiceRegisterOutputsForNextRound(
|
||||||
@@ -246,7 +246,7 @@ func (a *restClient) SubmitSignedForfeitTxs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *restClient) GetEventStream(
|
func (c *restClient) GetEventStream(
|
||||||
ctx context.Context, paymentID string,
|
ctx context.Context, requestID string,
|
||||||
) (<-chan client.RoundEventChannel, func(), error) {
|
) (<-chan client.RoundEventChannel, func(), error) {
|
||||||
eventsCh := make(chan client.RoundEventChannel)
|
eventsCh := make(chan client.RoundEventChannel)
|
||||||
|
|
||||||
@@ -354,10 +354,10 @@ func (c *restClient) GetEventStream(
|
|||||||
}
|
}
|
||||||
|
|
||||||
event = client.RoundSigningStartedEvent{
|
event = client.RoundSigningStartedEvent{
|
||||||
ID: e.ID,
|
ID: e.ID,
|
||||||
UnsignedTree: treeFromProto{e.UnsignedVtxoTree}.parse(),
|
UnsignedTree: treeFromProto{e.UnsignedVtxoTree}.parse(),
|
||||||
CosignersPublicKeys: pubkeys,
|
CosignersPubKeys: pubkeys,
|
||||||
UnsignedRoundTx: e.UnsignedRoundTx,
|
UnsignedRoundTx: e.UnsignedRoundTx,
|
||||||
}
|
}
|
||||||
case resp.Result.RoundSigningNoncesGenerated != nil:
|
case resp.Result.RoundSigningNoncesGenerated != nil:
|
||||||
e := resp.Result.RoundSigningNoncesGenerated
|
e := resp.Result.RoundSigningNoncesGenerated
|
||||||
@@ -384,10 +384,10 @@ func (c *restClient) GetEventStream(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *restClient) Ping(
|
func (a *restClient) Ping(
|
||||||
ctx context.Context, paymentID string,
|
ctx context.Context, requestID string,
|
||||||
) error {
|
) error {
|
||||||
r := ark_service.NewArkServicePingParams()
|
r := ark_service.NewArkServicePingParams()
|
||||||
r.SetPaymentID(paymentID)
|
r.SetRequestID(requestID)
|
||||||
_, err := a.svc.ArkServicePing(r)
|
_, err := a.svc.ArkServicePing(r)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -573,8 +573,8 @@ type treeFromProto struct {
|
|||||||
*models.V1Tree
|
*models.V1Tree
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t treeFromProto) parse() tree.CongestionTree {
|
func (t treeFromProto) parse() tree.VtxoTree {
|
||||||
congestionTree := make(tree.CongestionTree, 0, len(t.Levels))
|
vtxoTree := make(tree.VtxoTree, 0, len(t.Levels))
|
||||||
for _, l := range t.Levels {
|
for _, l := range t.Levels {
|
||||||
level := make([]tree.Node, 0, len(l.Nodes))
|
level := make([]tree.Node, 0, len(l.Nodes))
|
||||||
for _, n := range l.Nodes {
|
for _, n := range l.Nodes {
|
||||||
@@ -584,13 +584,13 @@ func (t treeFromProto) parse() tree.CongestionTree {
|
|||||||
ParentTxid: n.ParentTxid,
|
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 {
|
for i, node := range treeLvl {
|
||||||
if len(congestionTree.Children(node.Txid)) == 0 {
|
if len(vtxoTree.Children(node.Txid)) == 0 {
|
||||||
congestionTree[j][i] = tree.Node{
|
vtxoTree[j][i] = tree.Node{
|
||||||
Txid: node.Txid,
|
Txid: node.Txid,
|
||||||
Tx: node.Tx,
|
Tx: node.Tx,
|
||||||
ParentTxid: node.ParentTxid,
|
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) {
|
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,
|
Txid: v.Outpoint.Txid,
|
||||||
VOut: uint32(v.Outpoint.Vout),
|
VOut: uint32(v.Outpoint.Vout),
|
||||||
},
|
},
|
||||||
Pubkey: v.Pubkey,
|
PubKey: v.Pubkey,
|
||||||
Amount: uint64(amount),
|
Amount: uint64(amount),
|
||||||
RoundTxid: v.RoundTxid,
|
RoundTxid: v.RoundTxid,
|
||||||
ExpiresAt: expiresAt,
|
ExpiresAt: expiresAt,
|
||||||
|
|||||||
@@ -396,7 +396,7 @@ func (a *Client) ArkServicePing(params *ArkServicePingParams, opts ...ClientOpti
|
|||||||
op := &runtime.ClientOperation{
|
op := &runtime.ClientOperation{
|
||||||
ID: "ArkService_Ping",
|
ID: "ArkService_Ping",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
PathPattern: "/v1/round/ping/{paymentId}",
|
PathPattern: "/v1/round/ping/{requestId}",
|
||||||
ProducesMediaTypes: []string{"application/json"},
|
ProducesMediaTypes: []string{"application/json"},
|
||||||
ConsumesMediaTypes: []string{"application/json"},
|
ConsumesMediaTypes: []string{"application/json"},
|
||||||
Schemes: []string{"http"},
|
Schemes: []string{"http"},
|
||||||
|
|||||||
@@ -61,8 +61,11 @@ ArkServicePingParams contains all the parameters to send to the API endpoint
|
|||||||
*/
|
*/
|
||||||
type ArkServicePingParams struct {
|
type ArkServicePingParams struct {
|
||||||
|
|
||||||
// PaymentID.
|
/* RequestID.
|
||||||
PaymentID string
|
|
||||||
|
The id used to register inputs and ouptuts.
|
||||||
|
*/
|
||||||
|
RequestID string
|
||||||
|
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
Context context.Context
|
Context context.Context
|
||||||
@@ -117,15 +120,15 @@ func (o *ArkServicePingParams) SetHTTPClient(client *http.Client) {
|
|||||||
o.HTTPClient = client
|
o.HTTPClient = client
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithPaymentID adds the paymentID to the ark service ping params
|
// WithRequestID adds the requestID to the ark service ping params
|
||||||
func (o *ArkServicePingParams) WithPaymentID(paymentID string) *ArkServicePingParams {
|
func (o *ArkServicePingParams) WithRequestID(requestID string) *ArkServicePingParams {
|
||||||
o.SetPaymentID(paymentID)
|
o.SetRequestID(requestID)
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPaymentID adds the paymentId to the ark service ping params
|
// SetRequestID adds the requestId to the ark service ping params
|
||||||
func (o *ArkServicePingParams) SetPaymentID(paymentID string) {
|
func (o *ArkServicePingParams) SetRequestID(requestID string) {
|
||||||
o.PaymentID = paymentID
|
o.RequestID = requestID
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteToRequest writes these params to a swagger request
|
// WriteToRequest writes these params to a swagger request
|
||||||
@@ -136,8 +139,8 @@ func (o *ArkServicePingParams) WriteToRequest(r runtime.ClientRequest, reg strfm
|
|||||||
}
|
}
|
||||||
var res []error
|
var res []error
|
||||||
|
|
||||||
// path param paymentId
|
// path param requestId
|
||||||
if err := r.SetPathParam("paymentId", o.PaymentID); err != nil {
|
if err := r.SetPathParam("requestId", o.RequestID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,12 +88,12 @@ func (o *ArkServicePingOK) Code() int {
|
|||||||
|
|
||||||
func (o *ArkServicePingOK) Error() string {
|
func (o *ArkServicePingOK) Error() string {
|
||||||
payload, _ := json.Marshal(o.Payload)
|
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 {
|
func (o *ArkServicePingOK) String() string {
|
||||||
payload, _ := json.Marshal(o.Payload)
|
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 {
|
func (o *ArkServicePingOK) GetPayload() models.V1PingResponse {
|
||||||
@@ -160,12 +160,12 @@ func (o *ArkServicePingDefault) Code() int {
|
|||||||
|
|
||||||
func (o *ArkServicePingDefault) Error() string {
|
func (o *ArkServicePingDefault) Error() string {
|
||||||
payload, _ := json.Marshal(o.Payload)
|
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 {
|
func (o *ArkServicePingDefault) String() string {
|
||||||
payload, _ := json.Marshal(o.Payload)
|
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 {
|
func (o *ArkServicePingDefault) GetPayload() *models.RPCStatus {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"github.com/go-openapi/swag"
|
"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
|
// swagger:model v1OwnershipProof
|
||||||
type V1OwnershipProof struct {
|
type V1OwnershipProof struct {
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ import (
|
|||||||
// swagger:model v1RegisterInputsForNextRoundResponse
|
// swagger:model v1RegisterInputsForNextRoundResponse
|
||||||
type V1RegisterInputsForNextRoundResponse struct {
|
type V1RegisterInputsForNextRoundResponse struct {
|
||||||
|
|
||||||
// Mocks wabisabi's blinded credentials.
|
// request Id
|
||||||
ID string `json:"id,omitempty"`
|
RequestID string `json:"requestId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates this v1 register inputs for next round response
|
// Validate validates this v1 register inputs for next round response
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ import (
|
|||||||
// swagger:model v1RegisterOutputsForNextRoundRequest
|
// swagger:model v1RegisterOutputsForNextRoundRequest
|
||||||
type V1RegisterOutputsForNextRoundRequest struct {
|
type V1RegisterOutputsForNextRoundRequest struct {
|
||||||
|
|
||||||
// Mocks wabisabi's blinded credentials.
|
// List of receivers for to convert to leaves in the next VTXO tree.
|
||||||
ID string `json:"id,omitempty"`
|
|
||||||
|
|
||||||
// List of receivers for a registered payment.
|
|
||||||
Outputs []*V1Output `json:"outputs"`
|
Outputs []*V1Output `json:"outputs"`
|
||||||
|
|
||||||
|
// request Id
|
||||||
|
RequestID string `json:"requestId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates this v1 register outputs for next round request
|
// Validate validates this v1 register outputs for next round request
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ type V1SubmitSignedForfeitTxsRequest struct {
|
|||||||
// Forfeit txs signed by the user.
|
// Forfeit txs signed by the user.
|
||||||
SignedForfeitTxs []string `json:"signedForfeitTxs"`
|
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"`
|
SignedRoundTx string `json:"signedRoundTx,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ func LoadCovenantClient(sdkStore types.Store) (ArkClient, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clientSvc, err := getClient(
|
clientSvc, err := getClient(
|
||||||
supportedClients, cfgData.ClientType, cfgData.AspUrl,
|
supportedClients, cfgData.ClientType, cfgData.ServerUrl,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to setup transport client: %s", err)
|
return nil, fmt.Errorf("failed to setup transport client: %s", err)
|
||||||
@@ -147,7 +147,7 @@ func LoadCovenantClientWithWallet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
clientSvc, err := getClient(
|
clientSvc, err := getClient(
|
||||||
supportedClients, cfgData.ClientType, cfgData.AspUrl,
|
supportedClients, cfgData.ClientType, cfgData.ServerUrl,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to setup transport client: %s", err)
|
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(
|
func (a *covenantArkClient) processTransactionEvent(
|
||||||
event client.TransactionEvent,
|
event client.TransactionEvent,
|
||||||
) {
|
) {
|
||||||
// TODO considering current covenant state where all payments happening in round
|
// TODO: considering current covenant state where all transactions happening in round
|
||||||
//and that this is going to change we leave this unimplemented until asnc payments are implemented
|
// 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
|
// 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
|
// are multiple boarding inputs + spent vtxo with change in spendable + received in the same round
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *covenantArkClient) listenForBoardingUtxos(
|
func (a *covenantArkClient) listenForBoardingUtxos(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
) {
|
) {
|
||||||
// TODO considering current covenant state where all payments happening in round
|
// TODO considering current covenant state where all transactions happening in round
|
||||||
//and that this is going to change we leave this unimplemented until asnc payments are implemented
|
// 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
|
// 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
|
// are multiple boarding inputs + spent vtxo with change in spendable + received in the same round
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *covenantArkClient) Balance(
|
func (a *covenantArkClient) Balance(
|
||||||
@@ -525,7 +525,7 @@ func (a *covenantArkClient) CollaborativeRedeem(
|
|||||||
|
|
||||||
for _, offchainAddr := range offchainAddrs {
|
for _, offchainAddr := range offchainAddrs {
|
||||||
for _, v := range spendableVtxos {
|
for _, v := range spendableVtxos {
|
||||||
vtxoAddr, err := v.Address(a.AspPubkey, a.Network)
|
vtxoAddr, err := v.Address(a.ServerPubKey, a.Network)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
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 {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.client.RegisterOutputsForNextRound(ctx, paymentID, receivers); err != nil {
|
if err := a.client.RegisterOutputsForNextRound(ctx, requestID, receivers); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
roundTxID, err := a.handleRoundStream(ctx, paymentID, selectedCoins, selectedBoardingUtxos, receivers)
|
roundTxID, err := a.handleRoundStream(ctx, requestID, selectedCoins, selectedBoardingUtxos, receivers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -601,13 +601,6 @@ func (a *covenantArkClient) CollaborativeRedeem(
|
|||||||
return roundTxID, nil
|
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(
|
func (a *covenantArkClient) Settle(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
@@ -889,7 +882,7 @@ func (a *covenantArkClient) sendOffchain(
|
|||||||
return "", fmt.Errorf("wallet is locked")
|
return "", fmt.Errorf("wallet is locked")
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedAspPubKey := schnorr.SerializePubKey(a.AspPubkey)
|
expectedServerPubkey := schnorr.SerializePubKey(a.ServerPubKey)
|
||||||
outputs := make([]client.Output, 0)
|
outputs := make([]client.Output, 0)
|
||||||
sumOfReceivers := uint64(0)
|
sumOfReceivers := uint64(0)
|
||||||
|
|
||||||
@@ -900,10 +893,10 @@ func (a *covenantArkClient) sendOffchain(
|
|||||||
return "", fmt.Errorf("invalid receiver address: %s", err)
|
return "", fmt.Errorf("invalid receiver address: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rcvAspPubKey := schnorr.SerializePubKey(rcvAddr.Asp)
|
rcvServerPubKkey := schnorr.SerializePubKey(rcvAddr.Server)
|
||||||
|
|
||||||
if !bytes.Equal(expectedAspPubKey, rcvAspPubKey) {
|
if !bytes.Equal(expectedServerPubkey, rcvServerPubKkey) {
|
||||||
return "", fmt.Errorf("invalid receiver address '%s': expected ASP %s, got %s", receiver.To(), hex.EncodeToString(expectedAspPubKey), hex.EncodeToString(rcvAspPubKey))
|
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 {
|
if receiver.Amount() < a.Dust {
|
||||||
@@ -934,7 +927,7 @@ func (a *covenantArkClient) sendOffchain(
|
|||||||
|
|
||||||
for _, offchainAddr := range offchainAddrs {
|
for _, offchainAddr := range offchainAddrs {
|
||||||
for _, v := range spendableVtxos {
|
for _, v := range spendableVtxos {
|
||||||
vtxoAddr, err := v.Address(a.AspPubkey, a.Network)
|
vtxoAddr, err := v.Address(a.ServerPubKey, a.Network)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
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 {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.client.RegisterOutputsForNextRound(
|
if err := a.client.RegisterOutputsForNextRound(
|
||||||
ctx, paymentID, outputs,
|
ctx, requestID, outputs,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("payment registered with id: %s", paymentID)
|
log.Infof("payout registered with id: %s", requestID)
|
||||||
|
|
||||||
roundTxID, err := a.handleRoundStream(
|
roundTxID, err := a.handleRoundStream(
|
||||||
ctx, paymentID, selectedCoins, boardingUtxos, outputs,
|
ctx, requestID, selectedCoins, boardingUtxos, outputs,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -1116,19 +1109,19 @@ func (a *covenantArkClient) addInputs(
|
|||||||
|
|
||||||
func (a *covenantArkClient) handleRoundStream(
|
func (a *covenantArkClient) handleRoundStream(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
paymentID string,
|
requestID string,
|
||||||
vtxosToSign []client.TapscriptsVtxo,
|
vtxosToSign []client.TapscriptsVtxo,
|
||||||
boardingUtxos []types.Utxo,
|
boardingUtxos []types.Utxo,
|
||||||
receivers []client.Output,
|
receivers []client.Output,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
eventsCh, close, err := a.client.GetEventStream(ctx, paymentID)
|
eventsCh, close, err := a.client.GetEventStream(ctx, requestID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
var pingStop func()
|
var pingStop func()
|
||||||
for pingStop == nil {
|
for pingStop == nil {
|
||||||
pingStop = a.ping(ctx, paymentID)
|
pingStop = a.ping(ctx, requestID)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -1166,7 +1159,7 @@ func (a *covenantArkClient) handleRoundStream(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("finalizing payment... ")
|
log.Info("submitting forfeit transactions... ")
|
||||||
if err := a.client.SubmitSignedForfeitTxs(ctx, signedForfeitTxs, signedRoundTx); err != nil {
|
if err := a.client.SubmitSignedForfeitTxs(ctx, signedForfeitTxs, signedRoundTx); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -1185,7 +1178,7 @@ func (a *covenantArkClient) handleRoundFinalization(
|
|||||||
boardingUtxos []types.Utxo,
|
boardingUtxos []types.Utxo,
|
||||||
receivers []client.Output,
|
receivers []client.Output,
|
||||||
) (signedForfeits []string, signedRoundTx string, err error) {
|
) (signedForfeits []string, signedRoundTx string, err error) {
|
||||||
if err = a.validateCongestionTree(event, receivers); err != nil {
|
if err = a.validateVtxoTree(event, receivers); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1270,11 +1263,11 @@ func (a *covenantArkClient) handleRoundFinalization(
|
|||||||
return signedForfeits, signedRoundTx, nil
|
return signedForfeits, signedRoundTx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *covenantArkClient) validateCongestionTree(
|
func (a *covenantArkClient) validateVtxoTree(
|
||||||
event client.RoundFinalizationEvent, receivers []client.Output,
|
event client.RoundFinalizationEvent, receivers []client.Output,
|
||||||
) error {
|
) error {
|
||||||
poolTx := event.Tx
|
roundTx := event.Tx
|
||||||
ptx, err := psetv2.NewPsetFromBase64(poolTx)
|
ptx, err := psetv2.NewPsetFromBase64(roundTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1282,14 +1275,14 @@ func (a *covenantArkClient) validateCongestionTree(
|
|||||||
connectors := event.Connectors
|
connectors := event.Connectors
|
||||||
|
|
||||||
if !utils.IsOnchainOnly(receivers) {
|
if !utils.IsOnchainOnly(receivers) {
|
||||||
if err := tree.ValidateCongestionTree(
|
if err := tree.ValidateVtxoTree(
|
||||||
event.Tree, poolTx, a.Config.AspPubkey, a.RoundLifetime,
|
event.Tree, roundTx, a.Config.ServerPubKey, a.RoundLifetime,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := common.ValidateConnectors(poolTx, connectors); err != nil {
|
if err := common.ValidateConnectors(roundTx, connectors); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1299,15 +1292,13 @@ func (a *covenantArkClient) validateCongestionTree(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infoln("congestion tree validated")
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *covenantArkClient) validateReceivers(
|
func (a *covenantArkClient) validateReceivers(
|
||||||
ptx *psetv2.Pset,
|
ptx *psetv2.Pset,
|
||||||
receivers []client.Output,
|
receivers []client.Output,
|
||||||
congestionTree tree.CongestionTree,
|
vtxoTree tree.VtxoTree,
|
||||||
) error {
|
) error {
|
||||||
for _, receiver := range receivers {
|
for _, receiver := range receivers {
|
||||||
isOnChain, onchainScript, err := utils.ParseLiquidAddress(
|
isOnChain, onchainScript, err := utils.ParseLiquidAddress(
|
||||||
@@ -1323,7 +1314,7 @@ func (a *covenantArkClient) validateReceivers(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := a.validateOffChainReceiver(
|
if err := a.validateOffChainReceiver(
|
||||||
congestionTree, receiver,
|
vtxoTree, receiver,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1357,7 +1348,7 @@ func (a *covenantArkClient) validateOnChainReceiver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *covenantArkClient) validateOffChainReceiver(
|
func (a *covenantArkClient) validateOffChainReceiver(
|
||||||
congestionTree tree.CongestionTree,
|
vtxoTree tree.VtxoTree,
|
||||||
receiver client.Output,
|
receiver client.Output,
|
||||||
) error {
|
) error {
|
||||||
found := false
|
found := false
|
||||||
@@ -1369,7 +1360,7 @@ func (a *covenantArkClient) validateOffChainReceiver(
|
|||||||
|
|
||||||
vtxoTapKey := schnorr.SerializePubKey(addr.VtxoTapKey)
|
vtxoTapKey := schnorr.SerializePubKey(addr.VtxoTapKey)
|
||||||
|
|
||||||
leaves := congestionTree.Leaves()
|
leaves := vtxoTree.Leaves()
|
||||||
for _, leaf := range leaves {
|
for _, leaf := range leaves {
|
||||||
tx, err := psetv2.NewPsetFromBase64(leaf.Tx)
|
tx, err := psetv2.NewPsetFromBase64(leaf.Tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1614,22 +1605,22 @@ func (a *covenantArkClient) coinSelectOnchain(
|
|||||||
func (a *covenantArkClient) getRedeemBranches(
|
func (a *covenantArkClient) getRedeemBranches(
|
||||||
ctx context.Context, vtxos []client.Vtxo,
|
ctx context.Context, vtxos []client.Vtxo,
|
||||||
) (map[string]*redemption.CovenantRedeemBranch, error) {
|
) (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)
|
redeemBranches := make(map[string]*redemption.CovenantRedeemBranch, 0)
|
||||||
|
|
||||||
for i := range vtxos {
|
for i := range vtxos {
|
||||||
vtxo := vtxos[i]
|
vtxo := vtxos[i]
|
||||||
if _, ok := congestionTrees[vtxo.RoundTxid]; !ok {
|
if _, ok := vtxoTrees[vtxo.RoundTxid]; !ok {
|
||||||
round, err := a.client.GetRound(ctx, vtxo.RoundTxid)
|
round, err := a.client.GetRound(ctx, vtxo.RoundTxid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
congestionTrees[vtxo.RoundTxid] = round.Tree
|
vtxoTrees[vtxo.RoundTxid] = round.Tree
|
||||||
}
|
}
|
||||||
|
|
||||||
redeemBranch, err := redemption.NewCovenantRedeemBranch(
|
redeemBranch, err := redemption.NewCovenantRedeemBranch(
|
||||||
a.explorer, congestionTrees[vtxo.RoundTxid], vtxo,
|
a.explorer, vtxoTrees[vtxo.RoundTxid], vtxo,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func LoadCovenantlessClient(sdkStore types.Store) (ArkClient, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clientSvc, err := getClient(
|
clientSvc, err := getClient(
|
||||||
supportedClients, cfgData.ClientType, cfgData.AspUrl,
|
supportedClients, cfgData.ClientType, cfgData.ServerUrl,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to setup transport client: %s", err)
|
return nil, fmt.Errorf("failed to setup transport client: %s", err)
|
||||||
@@ -151,7 +151,7 @@ func LoadCovenantlessClientWithWallet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
clientSvc, err := getClient(
|
clientSvc, err := getClient(
|
||||||
supportedClients, cfgData.ClientType, cfgData.AspUrl,
|
supportedClients, cfgData.ClientType, cfgData.ServerUrl,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to setup transport client: %s", err)
|
return nil, fmt.Errorf("failed to setup transport client: %s", err)
|
||||||
@@ -395,7 +395,7 @@ func (a *covenantlessArkClient) processTransactionEvent(
|
|||||||
vtxosToInsert := make([]types.Vtxo, 0)
|
vtxosToInsert := make([]types.Vtxo, 0)
|
||||||
txsToInsert := make([]types.Transaction, 0)
|
txsToInsert := make([]types.Transaction, 0)
|
||||||
for _, v := range event.Round.SpendableVtxos {
|
for _, v := range event.Round.SpendableVtxos {
|
||||||
if v.Pubkey == pubkey {
|
if v.PubKey == pubkey {
|
||||||
vtxosToInsert = append(vtxosToInsert, types.Vtxo{
|
vtxosToInsert = append(vtxosToInsert, types.Vtxo{
|
||||||
VtxoKey: types.VtxoKey{
|
VtxoKey: types.VtxoKey{
|
||||||
Txid: v.Txid,
|
Txid: v.Txid,
|
||||||
@@ -474,7 +474,7 @@ func (a *covenantlessArkClient) processTransactionEvent(
|
|||||||
|
|
||||||
outputAmount := uint64(0)
|
outputAmount := uint64(0)
|
||||||
for _, v := range event.Redeem.SpendableVtxos {
|
for _, v := range event.Redeem.SpendableVtxos {
|
||||||
if v.Pubkey == pubkey {
|
if v.PubKey == pubkey {
|
||||||
vtxosToInsert = append(vtxosToInsert, types.Vtxo{
|
vtxosToInsert = append(vtxosToInsert, types.Vtxo{
|
||||||
VtxoKey: types.VtxoKey{
|
VtxoKey: types.VtxoKey{
|
||||||
Txid: v.Txid,
|
Txid: v.Txid,
|
||||||
@@ -507,7 +507,7 @@ func (a *covenantlessArkClient) processTransactionEvent(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, v := range event.Redeem.SpendableVtxos {
|
for _, v := range event.Redeem.SpendableVtxos {
|
||||||
if v.Pubkey == pubkey {
|
if v.PubKey == pubkey {
|
||||||
vtxosToInsert = append(vtxosToInsert, types.Vtxo{
|
vtxosToInsert = append(vtxosToInsert, types.Vtxo{
|
||||||
VtxoKey: types.VtxoKey{
|
VtxoKey: types.VtxoKey{
|
||||||
Txid: v.Txid,
|
Txid: v.Txid,
|
||||||
@@ -708,13 +708,126 @@ func (a *covenantlessArkClient) SendOffChain(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
withExpiryCoinselect bool, receivers []Receiver,
|
withExpiryCoinselect bool, receivers []Receiver,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
|
if len(receivers) <= 0 {
|
||||||
|
return "", fmt.Errorf("missing receivers")
|
||||||
|
}
|
||||||
|
|
||||||
|
netParams := utils.ToBitcoinNetwork(a.Network)
|
||||||
for _, receiver := range receivers {
|
for _, receiver := range receivers {
|
||||||
if receiver.IsOnchain() {
|
isOnchain, _, err := utils.ParseBitcoinAddress(receiver.To(), netParams)
|
||||||
return "", fmt.Errorf("invalid receiver address '%s': must be offchain", receiver.To())
|
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) {
|
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
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
paymentID, err := a.client.RegisterNotesForNextRound(
|
requestID, err := a.client.RegisterNotesForNextRound(
|
||||||
ctx, notes, hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()),
|
ctx, notes, hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -756,15 +869,15 @@ func (a *covenantlessArkClient) RedeemNotes(ctx context.Context, notes []string)
|
|||||||
receiversOutput := []client.Output{output}
|
receiversOutput := []client.Output{output}
|
||||||
|
|
||||||
if err := a.client.RegisterOutputsForNextRound(
|
if err := a.client.RegisterOutputsForNextRound(
|
||||||
ctx, paymentID, receiversOutput,
|
ctx, requestID, receiversOutput,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("payment registered with id: %s", paymentID)
|
log.Infof("payout registered with id: %s", requestID)
|
||||||
|
|
||||||
roundTxID, err := a.handleRoundStream(
|
roundTxID, err := a.handleRoundStream(
|
||||||
ctx, paymentID, nil, nil, receiversOutput, roundEphemeralKey,
|
ctx, requestID, nil, nil, receiversOutput, roundEphemeralKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -865,7 +978,7 @@ func (a *covenantlessArkClient) CollaborativeRedeem(
|
|||||||
|
|
||||||
for _, offchainAddr := range offchainAddrs {
|
for _, offchainAddr := range offchainAddrs {
|
||||||
for _, v := range spendableVtxos {
|
for _, v := range spendableVtxos {
|
||||||
vtxoAddr, err := v.Address(a.AspPubkey, a.Network)
|
vtxoAddr, err := v.Address(a.ServerPubKey, a.Network)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -929,7 +1042,7 @@ func (a *covenantlessArkClient) CollaborativeRedeem(
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
paymentID, err := a.client.RegisterInputsForNextRound(
|
requestID, err := a.client.RegisterInputsForNextRound(
|
||||||
ctx,
|
ctx,
|
||||||
inputs,
|
inputs,
|
||||||
hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()),
|
hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()),
|
||||||
@@ -938,12 +1051,12 @@ func (a *covenantlessArkClient) CollaborativeRedeem(
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.client.RegisterOutputsForNextRound(ctx, paymentID, receivers); err != nil {
|
if err := a.client.RegisterOutputsForNextRound(ctx, requestID, receivers); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
roundTxID, err := a.handleRoundStream(
|
roundTxID, err := a.handleRoundStream(
|
||||||
ctx, paymentID, selectedCoins, selectedBoardingCoins, receivers, roundEphemeralKey,
|
ctx, requestID, selectedCoins, selectedBoardingCoins, receivers, roundEphemeralKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -952,132 +1065,6 @@ func (a *covenantlessArkClient) CollaborativeRedeem(
|
|||||||
return roundTxID, nil
|
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) {
|
func (a *covenantlessArkClient) Settle(ctx context.Context) (string, error) {
|
||||||
return a.sendOffchain(ctx, false, nil)
|
return a.sendOffchain(ctx, false, nil)
|
||||||
}
|
}
|
||||||
@@ -1136,7 +1123,7 @@ func (a *covenantlessArkClient) SetNostrNotificationRecipient(ctx context.Contex
|
|||||||
descriptorVtxos := make([]client.TapscriptsVtxo, 0)
|
descriptorVtxos := make([]client.TapscriptsVtxo, 0)
|
||||||
for _, offchainAddr := range offchainAddrs {
|
for _, offchainAddr := range offchainAddrs {
|
||||||
for _, vtxo := range spendableVtxos {
|
for _, vtxo := range spendableVtxos {
|
||||||
vtxoAddr, err := vtxo.Address(a.AspPubkey, a.Network)
|
vtxoAddr, err := vtxo.Address(a.ServerPubKey, a.Network)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1362,7 +1349,7 @@ func (a *covenantlessArkClient) sendOffchain(
|
|||||||
return "", fmt.Errorf("wallet is locked")
|
return "", fmt.Errorf("wallet is locked")
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedAspPubKey := schnorr.SerializePubKey(a.AspPubkey)
|
expectedServerPubkey := schnorr.SerializePubKey(a.ServerPubKey)
|
||||||
outputs := make([]client.Output, 0)
|
outputs := make([]client.Output, 0)
|
||||||
sumOfReceivers := uint64(0)
|
sumOfReceivers := uint64(0)
|
||||||
|
|
||||||
@@ -1373,10 +1360,10 @@ func (a *covenantlessArkClient) sendOffchain(
|
|||||||
return "", fmt.Errorf("invalid receiver address: %s", err)
|
return "", fmt.Errorf("invalid receiver address: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rcvAspPubKey := schnorr.SerializePubKey(rcvAddr.Asp)
|
rcvServerPubkey := schnorr.SerializePubKey(rcvAddr.Server)
|
||||||
|
|
||||||
if !bytes.Equal(expectedAspPubKey, rcvAspPubKey) {
|
if !bytes.Equal(expectedServerPubkey, rcvServerPubkey) {
|
||||||
return "", fmt.Errorf("invalid receiver address '%s': expected ASP %s, got %s", receiver.To(), hex.EncodeToString(expectedAspPubKey), hex.EncodeToString(rcvAspPubKey))
|
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 {
|
if receiver.Amount() < a.Dust {
|
||||||
@@ -1408,7 +1395,7 @@ func (a *covenantlessArkClient) sendOffchain(
|
|||||||
|
|
||||||
for _, offchainAddr := range offchainAddrs {
|
for _, offchainAddr := range offchainAddrs {
|
||||||
for _, v := range spendableVtxos {
|
for _, v := range spendableVtxos {
|
||||||
vtxoAddr, err := v.Address(a.AspPubkey, a.Network)
|
vtxoAddr, err := v.Address(a.ServerPubKey, a.Network)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -1495,7 +1482,7 @@ func (a *covenantlessArkClient) sendOffchain(
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
paymentID, err := a.client.RegisterInputsForNextRound(
|
requestID, err := a.client.RegisterInputsForNextRound(
|
||||||
ctx, inputs, hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()),
|
ctx, inputs, hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1503,15 +1490,15 @@ func (a *covenantlessArkClient) sendOffchain(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := a.client.RegisterOutputsForNextRound(
|
if err := a.client.RegisterOutputsForNextRound(
|
||||||
ctx, paymentID, outputs,
|
ctx, requestID, outputs,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return "", err
|
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(
|
roundTxID, err := a.handleRoundStream(
|
||||||
ctx, paymentID, selectedCoins, selectedBoardingCoins, outputs, roundEphemeralKey,
|
ctx, requestID, selectedCoins, selectedBoardingCoins, outputs, roundEphemeralKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -1594,7 +1581,7 @@ func (a *covenantlessArkClient) addInputs(
|
|||||||
|
|
||||||
func (a *covenantlessArkClient) handleRoundStream(
|
func (a *covenantlessArkClient) handleRoundStream(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
paymentID string,
|
requestID string,
|
||||||
vtxosToSign []client.TapscriptsVtxo,
|
vtxosToSign []client.TapscriptsVtxo,
|
||||||
boardingUtxos []types.Utxo,
|
boardingUtxos []types.Utxo,
|
||||||
receivers []client.Output,
|
receivers []client.Output,
|
||||||
@@ -1605,14 +1592,14 @@ func (a *covenantlessArkClient) handleRoundStream(
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
eventsCh, close, err := a.client.GetEventStream(ctx, paymentID)
|
eventsCh, close, err := a.client.GetEventStream(ctx, requestID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
var pingStop func()
|
var pingStop func()
|
||||||
for pingStop == nil {
|
for pingStop == nil {
|
||||||
pingStop = a.ping(ctx, paymentID)
|
pingStop = a.ping(ctx, requestID)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -1697,7 +1684,7 @@ func (a *covenantlessArkClient) handleRoundStream(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("finalizing payment... ")
|
log.Info("submitting forfeit transactions... ")
|
||||||
if err := a.client.SubmitSignedForfeitTxs(ctx, signedForfeitTxs, signedRoundTx); err != nil {
|
if err := a.client.SubmitSignedForfeitTxs(ctx, signedForfeitTxs, signedRoundTx); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -1715,7 +1702,7 @@ func (a *covenantlessArkClient) handleRoundSigningStarted(
|
|||||||
ctx context.Context, ephemeralKey *secp256k1.PrivateKey, event client.RoundSigningStartedEvent,
|
ctx context.Context, ephemeralKey *secp256k1.PrivateKey, event client.RoundSigningStartedEvent,
|
||||||
) (signerSession bitcointree.SignerSession, err error) {
|
) (signerSession bitcointree.SignerSession, err error) {
|
||||||
sweepClosure := tree.CSVSigClosure{
|
sweepClosure := tree.CSVSigClosure{
|
||||||
MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{a.AspPubkey}},
|
MultisigClosure: tree.MultisigClosure{PubKeys: []*secp256k1.PublicKey{a.ServerPubKey}},
|
||||||
Seconds: uint(a.RoundLifetime),
|
Seconds: uint(a.RoundLifetime),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1740,7 +1727,7 @@ func (a *covenantlessArkClient) handleRoundSigningStarted(
|
|||||||
ephemeralKey, sharedOutputValue, event.UnsignedTree, root.CloneBytes(),
|
ephemeralKey, sharedOutputValue, event.UnsignedTree, root.CloneBytes(),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err = signerSession.SetKeys(event.CosignersPublicKeys); err != nil {
|
if err = signerSession.SetKeys(event.CosignersPubKeys); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1749,9 +1736,9 @@ func (a *covenantlessArkClient) handleRoundSigningStarted(
|
|||||||
return
|
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
|
return
|
||||||
}
|
}
|
||||||
@@ -1794,8 +1781,8 @@ func (a *covenantlessArkClient) handleRoundFinalization(
|
|||||||
boardingUtxos []types.Utxo,
|
boardingUtxos []types.Utxo,
|
||||||
receivers []client.Output,
|
receivers []client.Output,
|
||||||
) ([]string, string, error) {
|
) ([]string, string, error) {
|
||||||
if err := a.validateCongestionTree(event, receivers); err != nil {
|
if err := a.validateVtxoTree(event, receivers); err != nil {
|
||||||
return nil, "", fmt.Errorf("failed to verify congestion tree: %s", err)
|
return nil, "", fmt.Errorf("failed to verify vtxo tree: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var forfeits []string
|
var forfeits []string
|
||||||
@@ -1880,24 +1867,25 @@ func (a *covenantlessArkClient) handleRoundFinalization(
|
|||||||
return forfeits, signedRoundTx, nil
|
return forfeits, signedRoundTx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *covenantlessArkClient) validateCongestionTree(
|
func (a *covenantlessArkClient) validateVtxoTree(
|
||||||
event client.RoundFinalizationEvent, receivers []client.Output,
|
event client.RoundFinalizationEvent, receivers []client.Output,
|
||||||
) error {
|
) error {
|
||||||
poolTx := event.Tx
|
roundTx := event.Tx
|
||||||
ptx, err := psbt.NewFromRawBytes(strings.NewReader(poolTx), true)
|
ptx, err := psbt.NewFromRawBytes(strings.NewReader(roundTx), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !utils.IsOnchainOnly(receivers) {
|
if !utils.IsOnchainOnly(receivers) {
|
||||||
if err := bitcointree.ValidateCongestionTree(
|
if err := bitcointree.ValidateVtxoTree(
|
||||||
event.Tree, poolTx, a.Config.AspPubkey, a.RoundLifetime,
|
event.Tree, roundTx, a.Config.ServerPubKey, a.RoundLifetime,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
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
|
// return err
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@@ -1907,15 +1895,13 @@ func (a *covenantlessArkClient) validateCongestionTree(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("congestion tree validated")
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *covenantlessArkClient) validateReceivers(
|
func (a *covenantlessArkClient) validateReceivers(
|
||||||
ptx *psbt.Packet,
|
ptx *psbt.Packet,
|
||||||
receivers []client.Output,
|
receivers []client.Output,
|
||||||
congestionTree tree.CongestionTree,
|
vtxoTree tree.VtxoTree,
|
||||||
) error {
|
) error {
|
||||||
netParams := utils.ToBitcoinNetwork(a.Network)
|
netParams := utils.ToBitcoinNetwork(a.Network)
|
||||||
for _, receiver := range receivers {
|
for _, receiver := range receivers {
|
||||||
@@ -1932,7 +1918,7 @@ func (a *covenantlessArkClient) validateReceivers(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := a.validateOffChainReceiver(
|
if err := a.validateOffChainReceiver(
|
||||||
congestionTree, receiver,
|
vtxoTree, receiver,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1966,7 +1952,7 @@ func (a *covenantlessArkClient) validateOnChainReceiver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *covenantlessArkClient) validateOffChainReceiver(
|
func (a *covenantlessArkClient) validateOffChainReceiver(
|
||||||
congestionTree tree.CongestionTree,
|
vtxoTree tree.VtxoTree,
|
||||||
receiver client.Output,
|
receiver client.Output,
|
||||||
) error {
|
) error {
|
||||||
found := false
|
found := false
|
||||||
@@ -1978,7 +1964,7 @@ func (a *covenantlessArkClient) validateOffChainReceiver(
|
|||||||
|
|
||||||
vtxoTapKey := schnorr.SerializePubKey(rcvAddr.VtxoTapKey)
|
vtxoTapKey := schnorr.SerializePubKey(rcvAddr.VtxoTapKey)
|
||||||
|
|
||||||
leaves := congestionTree.Leaves()
|
leaves := vtxoTree.Leaves()
|
||||||
for _, leaf := range leaves {
|
for _, leaf := range leaves {
|
||||||
tx, err := psbt.NewFromRawBytes(strings.NewReader(leaf.Tx), true)
|
tx, err := psbt.NewFromRawBytes(strings.NewReader(leaf.Tx), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -2247,7 +2233,7 @@ func (a *covenantlessArkClient) coinSelectOnchain(
|
|||||||
func (a *covenantlessArkClient) getRedeemBranches(
|
func (a *covenantlessArkClient) getRedeemBranches(
|
||||||
ctx context.Context, vtxos []client.Vtxo,
|
ctx context.Context, vtxos []client.Vtxo,
|
||||||
) (map[string]*redemption.CovenantlessRedeemBranch, error) {
|
) (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)
|
redeemBranches := make(map[string]*redemption.CovenantlessRedeemBranch, 0)
|
||||||
|
|
||||||
for i := range vtxos {
|
for i := range vtxos {
|
||||||
@@ -2258,17 +2244,17 @@ func (a *covenantlessArkClient) getRedeemBranches(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := congestionTrees[vtxo.RoundTxid]; !ok {
|
if _, ok := vtxoTrees[vtxo.RoundTxid]; !ok {
|
||||||
round, err := a.client.GetRound(ctx, vtxo.RoundTxid)
|
round, err := a.client.GetRound(ctx, vtxo.RoundTxid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
congestionTrees[vtxo.RoundTxid] = round.Tree
|
vtxoTrees[vtxo.RoundTxid] = round.Tree
|
||||||
}
|
}
|
||||||
|
|
||||||
redeemBranch, err := redemption.NewCovenantlessRedeemBranch(
|
redeemBranch, err := redemption.NewCovenantlessRedeemBranch(
|
||||||
a.explorer, congestionTrees[vtxo.RoundTxid], vtxo,
|
a.explorer, vtxoTrees[vtxo.RoundTxid], vtxo,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
aspUrl = "localhost:6060"
|
serverUrl = "localhost:6060"
|
||||||
clientType = arksdk.GrpcClient
|
clientType = arksdk.GrpcClient
|
||||||
password = "password"
|
password = "password"
|
||||||
walletType = arksdk.SingleKeyWallet
|
walletType = arksdk.SingleKeyWallet
|
||||||
@@ -110,7 +110,7 @@ func main() {
|
|||||||
log.Fatal(err)
|
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 {
|
if err := generateBlock(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@@ -155,7 +155,7 @@ func setupArkClient(wallet string) (arksdk.ArkClient, error) {
|
|||||||
if err := client.Init(context.Background(), arksdk.InitArgs{
|
if err := client.Init(context.Background(), arksdk.InitArgs{
|
||||||
WalletType: walletType,
|
WalletType: walletType,
|
||||||
ClientType: clientType,
|
ClientType: clientType,
|
||||||
AspUrl: aspUrl,
|
ServerUrl: serverUrl,
|
||||||
Password: password,
|
Password: password,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, fmt.Errorf("failed to initialize wallet: %s", err)
|
return nil, fmt.Errorf("failed to initialize wallet: %s", err)
|
||||||
|
|||||||
@@ -28,13 +28,13 @@
|
|||||||
logMessage("Init error: password is required");
|
logMessage("Init error: password is required");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const aspUrl = document.getElementById("aspUrl").value;
|
const serverUrl = document.getElementById("serverUrl").value;
|
||||||
if (!aspUrl) {
|
if (!serverUrl) {
|
||||||
logMessage("Init error: asp url is required");
|
logMessage("Init error: server url is required");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await init(walletType, clientType, aspUrl, privateKey, password, chain, explorerUrl);
|
await init(walletType, clientType, serverUrl, privateKey, password, chain, explorerUrl);
|
||||||
logMessage("wallet initialized and connected to ASP");
|
logMessage("wallet initialized and connected to server");
|
||||||
await config();
|
await config();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logMessage("Init error: " + err.message);
|
logMessage("Init error: " + err.message);
|
||||||
@@ -91,11 +91,11 @@
|
|||||||
|
|
||||||
async function config() {
|
async function config() {
|
||||||
try {
|
try {
|
||||||
const aspUrl = await getAspUrl();
|
const serverUrl = await getServerUrl();
|
||||||
logMessage("ASP URL: " + aspUrl);
|
logMessage("Server URL: " + serverUrl);
|
||||||
|
|
||||||
const aspPubKeyHex = await getAspPubKeyHex();
|
const serverPubkeyHex = await getServerPubkeyHex();
|
||||||
logMessage("ASP PubKey: " + aspPubKeyHex);
|
logMessage("Server PubKey: " + serverPubkeyHex);
|
||||||
|
|
||||||
const walletType = await getWalletType();
|
const walletType = await getWalletType();
|
||||||
logMessage("Wallet Type: " + walletType);
|
logMessage("Wallet Type: " + walletType);
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
<h2>Wallet</h2>
|
<h2>Wallet</h2>
|
||||||
<div>
|
<div>
|
||||||
<button onclick="initWallet()">Init</button>
|
<button onclick="initWallet()">Init</button>
|
||||||
<input type="text" id="aspUrl" placeholder="http://localhost:6060">
|
<input type="text" id="serverUrl" placeholder="http://localhost:6060">
|
||||||
<input type="password" id="i_password" placeholder="password">
|
<input type="password" id="i_password" placeholder="password">
|
||||||
<input type="text" id="prvkey" placeholder="Optional: privkey (hex)">
|
<input type="text" id="prvkey" placeholder="Optional: privkey (hex)">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
aspUrl = "localhost:7070"
|
serverUrl = "localhost:7070"
|
||||||
clientType = arksdk.GrpcClient
|
clientType = arksdk.GrpcClient
|
||||||
password = "password"
|
password = "password"
|
||||||
walletType = arksdk.SingleKeyWallet
|
walletType = arksdk.SingleKeyWallet
|
||||||
@@ -128,11 +128,11 @@ func main() {
|
|||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
log.Infof("alice is sending %d sats to bob offchain...", amount)
|
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.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("payment completed out of round")
|
log.Info("transaction completed out of round")
|
||||||
|
|
||||||
if err := generateBlock(); err != nil {
|
if err := generateBlock(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@@ -188,7 +188,7 @@ func setupArkClient(wallet string) (arksdk.ArkClient, error) {
|
|||||||
if err := client.Init(context.Background(), arksdk.InitArgs{
|
if err := client.Init(context.Background(), arksdk.InitArgs{
|
||||||
WalletType: walletType,
|
WalletType: walletType,
|
||||||
ClientType: clientType,
|
ClientType: clientType,
|
||||||
AspUrl: aspUrl,
|
ServerUrl: serverUrl,
|
||||||
Password: password,
|
Password: password,
|
||||||
WithTransactionFeed: true,
|
WithTransactionFeed: true,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|||||||
@@ -28,13 +28,13 @@
|
|||||||
logMessage("Init error: password is required");
|
logMessage("Init error: password is required");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const aspUrl = document.getElementById("aspUrl").value;
|
const serverUrl = document.getElementById("serverUrl").value;
|
||||||
if (!aspUrl) {
|
if (!serverUrl) {
|
||||||
logMessage("Init error: asp url is required");
|
logMessage("Init error: server url is required");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await init(walletType, clientType, aspUrl, privateKey, password, chain, explorerUrl);
|
await init(walletType, clientType, serverUrl, privateKey, password, chain, explorerUrl);
|
||||||
logMessage("wallet initialized and connected to ASP");
|
logMessage("wallet initialized and connected to server");
|
||||||
await config();
|
await config();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logMessage("Init error: " + err.message);
|
logMessage("Init error: " + err.message);
|
||||||
@@ -119,11 +119,11 @@
|
|||||||
|
|
||||||
async function config() {
|
async function config() {
|
||||||
try {
|
try {
|
||||||
const aspUrl = await getAspUrl();
|
const serverUrl = await getServerUrl();
|
||||||
logMessage("ASP URL: " + aspUrl);
|
logMessage("Server URL: " + serverUrl);
|
||||||
|
|
||||||
const aspPubKeyHex = await getAspPubKeyHex();
|
const serverPubkeyHex = await getServerPubkeyHex();
|
||||||
logMessage("ASP PubKey: " + aspPubKeyHex);
|
logMessage("Server Pubkey: " + serverPubkeyHex);
|
||||||
|
|
||||||
const walletType = await getWalletType();
|
const walletType = await getWalletType();
|
||||||
logMessage("Wallet Type: " + walletType);
|
logMessage("Wallet Type: " + walletType);
|
||||||
@@ -149,7 +149,7 @@
|
|||||||
<h2>Wallet</h2>
|
<h2>Wallet</h2>
|
||||||
<div>
|
<div>
|
||||||
<button onclick="initWallet()">Init</button>
|
<button onclick="initWallet()">Init</button>
|
||||||
<input type="text" id="aspUrl" placeholder="http://localhost:7070">
|
<input type="text" id="serverUrl" placeholder="http://localhost:7070">
|
||||||
<input type="password" id="i_password" placeholder="password">
|
<input type="password" id="i_password" placeholder="password">
|
||||||
<input type="text" id="prvkey" placeholder="Optional: privkey (hex)">
|
<input type="text" id="prvkey" placeholder="Optional: privkey (hex)">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func (t SupportedType[V]) Supports(typeStr string) bool {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClientFactory func(string) (client.ASPClient, error)
|
type ClientFactory func(string) (client.TransportClient, error)
|
||||||
|
|
||||||
type Cache[V any] struct {
|
type Cache[V any] struct {
|
||||||
mapping map[string]V
|
mapping map[string]V
|
||||||
|
|||||||
@@ -173,11 +173,11 @@ func ToBitcoinNetwork(net common.Network) chaincfg.Params {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GenerateRandomPrivateKey() (*secp256k1.PrivateKey, error) {
|
func GenerateRandomPrivateKey() (*secp256k1.PrivateKey, error) {
|
||||||
privKey, err := btcec.NewPrivateKey()
|
prvkey, err := btcec.NewPrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return privKey, nil
|
return prvkey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func HashPassword(password []byte) []byte {
|
func HashPassword(password []byte) []byte {
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ type CovenantRedeemBranch struct {
|
|||||||
|
|
||||||
func NewCovenantRedeemBranch(
|
func NewCovenantRedeemBranch(
|
||||||
explorer explorer.Explorer,
|
explorer explorer.Explorer,
|
||||||
congestionTree tree.CongestionTree, vtxo client.Vtxo,
|
vtxoTree tree.VtxoTree, vtxo client.Vtxo,
|
||||||
) (*CovenantRedeemBranch, error) {
|
) (*CovenantRedeemBranch, error) {
|
||||||
sweepClosure, seconds, err := findCovenantSweepClosure(congestionTree)
|
sweepClosure, seconds, err := findCovenantSweepClosure(vtxoTree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ func NewCovenantRedeemBranch(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes, err := congestionTree.Branch(vtxo.Txid)
|
nodes, err := vtxoTree.Branch(vtxo.Txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -182,9 +182,9 @@ func (r *CovenantRedeemBranch) offchainPath() ([]*psetv2.Pset, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func findCovenantSweepClosure(
|
func findCovenantSweepClosure(
|
||||||
congestionTree tree.CongestionTree,
|
vtxoTree tree.VtxoTree,
|
||||||
) (*taproot.TapElementsLeaf, uint, error) {
|
) (*taproot.TapElementsLeaf, uint, error) {
|
||||||
root, err := congestionTree.Root()
|
root, err := vtxoTree.Root()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ type CovenantlessRedeemBranch struct {
|
|||||||
|
|
||||||
func NewCovenantlessRedeemBranch(
|
func NewCovenantlessRedeemBranch(
|
||||||
explorer explorer.Explorer,
|
explorer explorer.Explorer,
|
||||||
congestionTree tree.CongestionTree, vtxo client.Vtxo,
|
vtxoTree tree.VtxoTree, vtxo client.Vtxo,
|
||||||
) (*CovenantlessRedeemBranch, error) {
|
) (*CovenantlessRedeemBranch, error) {
|
||||||
_, seconds, err := findCovenantlessSweepClosure(congestionTree)
|
_, seconds, err := findCovenantlessSweepClosure(vtxoTree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ func NewCovenantlessRedeemBranch(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes, err := congestionTree.Branch(vtxo.Txid)
|
nodes, err := vtxoTree.Branch(vtxo.Txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -155,9 +155,9 @@ func (r *CovenantlessRedeemBranch) OffchainPath() ([]*psbt.Packet, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func findCovenantlessSweepClosure(
|
func findCovenantlessSweepClosure(
|
||||||
congestionTree tree.CongestionTree,
|
vtxoTree tree.VtxoTree,
|
||||||
) (*txscript.TapLeaf, uint, error) {
|
) (*txscript.TapLeaf, uint, error) {
|
||||||
root, err := congestionTree.Root()
|
root, err := vtxoTree.Root()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ func (s *configStore) GetDatadir() string {
|
|||||||
|
|
||||||
func (s *configStore) AddData(ctx context.Context, data types.Config) error {
|
func (s *configStore) AddData(ctx context.Context, data types.Config) error {
|
||||||
sd := &storeData{
|
sd := &storeData{
|
||||||
AspUrl: data.AspUrl,
|
ServerUrl: data.ServerUrl,
|
||||||
AspPubkey: hex.EncodeToString(data.AspPubkey.SerializeCompressed()),
|
ServerPubKey: hex.EncodeToString(data.ServerPubKey.SerializeCompressed()),
|
||||||
WalletType: data.WalletType,
|
WalletType: data.WalletType,
|
||||||
ClientType: data.ClientType,
|
ClientType: data.ClientType,
|
||||||
Network: data.Network.Name,
|
Network: data.Network.Name,
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type storeData struct {
|
type storeData struct {
|
||||||
AspUrl string `json:"asp_url"`
|
ServerUrl string `json:"server_url"`
|
||||||
AspPubkey string `json:"asp_pubkey"`
|
ServerPubKey string `json:"server_pubkey"`
|
||||||
WalletType string `json:"wallet_type"`
|
WalletType string `json:"wallet_type"`
|
||||||
ClientType string `json:"client_type"`
|
ClientType string `json:"client_type"`
|
||||||
Network string `json:"network"`
|
Network string `json:"network"`
|
||||||
@@ -26,8 +26,8 @@ type storeData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d storeData) isEmpty() bool {
|
func (d storeData) isEmpty() bool {
|
||||||
if d.AspUrl == "" &&
|
if d.ServerUrl == "" &&
|
||||||
d.AspPubkey == "" {
|
d.ServerPubKey == "" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,12 +41,12 @@ func (d storeData) decode() types.Config {
|
|||||||
unilateralExitDelay, _ := strconv.Atoi(d.UnilateralExitDelay)
|
unilateralExitDelay, _ := strconv.Atoi(d.UnilateralExitDelay)
|
||||||
withTransactionFeed, _ := strconv.ParseBool(d.WithTransactionFeed)
|
withTransactionFeed, _ := strconv.ParseBool(d.WithTransactionFeed)
|
||||||
dust, _ := strconv.Atoi(d.Dust)
|
dust, _ := strconv.Atoi(d.Dust)
|
||||||
buf, _ := hex.DecodeString(d.AspPubkey)
|
buf, _ := hex.DecodeString(d.ServerPubKey)
|
||||||
aspPubkey, _ := secp256k1.ParsePubKey(buf)
|
serverPubkey, _ := secp256k1.ParsePubKey(buf)
|
||||||
explorerURL := d.ExplorerURL
|
explorerURL := d.ExplorerURL
|
||||||
return types.Config{
|
return types.Config{
|
||||||
AspUrl: d.AspUrl,
|
ServerUrl: d.ServerUrl,
|
||||||
AspPubkey: aspPubkey,
|
ServerPubKey: serverPubkey,
|
||||||
WalletType: d.WalletType,
|
WalletType: d.WalletType,
|
||||||
ClientType: d.ClientType,
|
ClientType: d.ClientType,
|
||||||
Network: network,
|
Network: network,
|
||||||
@@ -63,8 +63,8 @@ func (d storeData) decode() types.Config {
|
|||||||
|
|
||||||
func (d storeData) asMap() map[string]string {
|
func (d storeData) asMap() map[string]string {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
"asp_url": d.AspUrl,
|
"server_url": d.ServerUrl,
|
||||||
"asp_pubkey": d.AspPubkey,
|
"server_pubkey": d.ServerPubKey,
|
||||||
"wallet_type": d.WalletType,
|
"wallet_type": d.WalletType,
|
||||||
"client_type": d.ClientType,
|
"client_type": d.ClientType,
|
||||||
"network": d.Network,
|
"network": d.Network,
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ func TestStore(t *testing.T) {
|
|||||||
key, _ := btcec.NewPrivateKey()
|
key, _ := btcec.NewPrivateKey()
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
testStoreData := sdktypes.Config{
|
testStoreData := sdktypes.Config{
|
||||||
AspUrl: "localhost:7070",
|
ServerUrl: "localhost:7070",
|
||||||
AspPubkey: key.PubKey(),
|
ServerPubKey: key.PubKey(),
|
||||||
WalletType: wallet.SingleKeyWallet,
|
WalletType: wallet.SingleKeyWallet,
|
||||||
ClientType: client.GrpcClient,
|
ClientType: client.GrpcClient,
|
||||||
Network: common.LiquidRegTest,
|
Network: common.LiquidRegTest,
|
||||||
|
|||||||
@@ -4,10 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"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"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -18,6 +14,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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"
|
"github.com/shirou/gopsutil/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ func TestMain(m *testing.M) {
|
|||||||
os.Exit(1)
|
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 {
|
if err != nil {
|
||||||
fmt.Printf("error initializing ark config: %s", err)
|
fmt.Printf("error initializing ark config: %s", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
@@ -139,9 +140,9 @@ func TestWasm(t *testing.T) {
|
|||||||
|
|
||||||
amount := 1000
|
amount := 1000
|
||||||
t.Logf("Alice is sending %d sats to Bob offchain...", amount)
|
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...")
|
t.Logf("Bob settling the received funds...")
|
||||||
txID, err = settle(bobPage)
|
txID, err = settle(bobPage)
|
||||||
@@ -231,8 +232,8 @@ func initWallet(page playwright.Page) error {
|
|||||||
const privateKey = "";
|
const privateKey = "";
|
||||||
const password = "pass";
|
const password = "pass";
|
||||||
const explorerUrl = "";
|
const explorerUrl = "";
|
||||||
const aspUrl = "http://localhost:7070";
|
const serverUrl = "http://localhost:7070";
|
||||||
return await init(walletType, clientType, aspUrl, privateKey, password, chain, explorerUrl);
|
return await init(walletType, clientType, serverUrl, privateKey, password, chain, explorerUrl);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Init error:", err);
|
console.error("Init error:", err);
|
||||||
throw err;
|
throw err;
|
||||||
@@ -336,10 +337,10 @@ func settle(page playwright.Page) (string, error) {
|
|||||||
return fmt.Sprint(result), nil
|
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 () => {
|
_, err := page.Evaluate(fmt.Sprintf(`async () => {
|
||||||
try {
|
try {
|
||||||
return await sendAsync(false, [{To:"%s", Amount:%d}]);
|
return await sendOffChain(false, [{To:"%s", Amount:%d}]);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error:", err);
|
console.error("Error:", err);
|
||||||
throw err;
|
throw err;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ var (
|
|||||||
type InitArgs struct {
|
type InitArgs struct {
|
||||||
ClientType string
|
ClientType string
|
||||||
WalletType string
|
WalletType string
|
||||||
AspUrl string
|
ServerUrl string
|
||||||
Seed string
|
Seed string
|
||||||
Password string
|
Password string
|
||||||
ExplorerURL string
|
ExplorerURL string
|
||||||
@@ -51,8 +51,8 @@ func (a InitArgs) validate() error {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(a.AspUrl) <= 0 {
|
if len(a.ServerUrl) <= 0 {
|
||||||
return fmt.Errorf("missing asp url")
|
return fmt.Errorf("missing server url")
|
||||||
}
|
}
|
||||||
if len(a.Password) <= 0 {
|
if len(a.Password) <= 0 {
|
||||||
return fmt.Errorf("missing password")
|
return fmt.Errorf("missing password")
|
||||||
@@ -63,7 +63,7 @@ func (a InitArgs) validate() error {
|
|||||||
type InitWithWalletArgs struct {
|
type InitWithWalletArgs struct {
|
||||||
ClientType string
|
ClientType string
|
||||||
Wallet wallet.WalletService
|
Wallet wallet.WalletService
|
||||||
AspUrl string
|
ServerUrl string
|
||||||
Seed string
|
Seed string
|
||||||
Password string
|
Password string
|
||||||
ExplorerURL 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)
|
return fmt.Errorf("client type not supported, please select one of: %s", supportedClients)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(a.AspUrl) <= 0 {
|
if len(a.ServerUrl) <= 0 {
|
||||||
return fmt.Errorf("missing asp url")
|
return fmt.Errorf("missing server url")
|
||||||
}
|
}
|
||||||
if len(a.Password) <= 0 {
|
if len(a.Password) <= 0 {
|
||||||
return fmt.Errorf("missing password")
|
return fmt.Errorf("missing password")
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
AspUrl string
|
ServerUrl string
|
||||||
AspPubkey *secp256k1.PublicKey
|
ServerPubKey *secp256k1.PublicKey
|
||||||
WalletType string
|
WalletType string
|
||||||
ClientType string
|
ClientType string
|
||||||
Network common.Network
|
Network common.Network
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ func (s *bitcoinWallet) SignTransaction(
|
|||||||
)
|
)
|
||||||
|
|
||||||
txsighashes := txscript.NewTxSigHashes(updater.Upsbt.UnsignedTx, prevoutFetcher)
|
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 {
|
for i, input := range ptx.Inputs {
|
||||||
if len(input.TaprootLeafScript) > 0 {
|
if len(input.TaprootLeafScript) > 0 {
|
||||||
@@ -246,7 +246,7 @@ func (s *bitcoinWallet) SignTransaction(
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !sig.Verify(preimage, s.walletData.Pubkey) {
|
if !sig.Verify(preimage, s.walletData.PubKey) {
|
||||||
return "", fmt.Errorf("signature verification failed")
|
return "", fmt.Errorf("signature verification failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,8 +308,8 @@ func (w *bitcoinWallet) getAddress(
|
|||||||
netParams := utils.ToBitcoinNetwork(data.Network)
|
netParams := utils.ToBitcoinNetwork(data.Network)
|
||||||
|
|
||||||
defaultVtxoScript := bitcointree.NewDefaultVtxoScript(
|
defaultVtxoScript := bitcointree.NewDefaultVtxoScript(
|
||||||
w.walletData.Pubkey,
|
w.walletData.PubKey,
|
||||||
data.AspPubkey,
|
data.ServerPubKey,
|
||||||
uint(data.UnilateralExitDelay),
|
uint(data.UnilateralExitDelay),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -320,13 +320,13 @@ func (w *bitcoinWallet) getAddress(
|
|||||||
|
|
||||||
offchainAddress := &common.Address{
|
offchainAddress := &common.Address{
|
||||||
HRP: data.Network.Addr,
|
HRP: data.Network.Addr,
|
||||||
Asp: data.AspPubkey,
|
Server: data.ServerPubKey,
|
||||||
VtxoTapKey: vtxoTapKey,
|
VtxoTapKey: vtxoTapKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
boardingVtxoScript := bitcointree.NewDefaultVtxoScript(
|
boardingVtxoScript := bitcointree.NewDefaultVtxoScript(
|
||||||
w.walletData.Pubkey,
|
w.walletData.PubKey,
|
||||||
data.AspPubkey,
|
data.ServerPubKey,
|
||||||
uint(data.UnilateralExitDelay*2),
|
uint(data.UnilateralExitDelay*2),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ func (s *liquidWallet) SignTransaction(
|
|||||||
prevoutsAssets = append(prevoutsAssets, input.WitnessUtxo.Asset)
|
prevoutsAssets = append(prevoutsAssets, input.WitnessUtxo.Asset)
|
||||||
}
|
}
|
||||||
|
|
||||||
myPubkey := schnorr.SerializePubKey(s.walletData.Pubkey)
|
myPubkey := schnorr.SerializePubKey(s.walletData.PubKey)
|
||||||
|
|
||||||
for i, input := range pset.Inputs {
|
for i, input := range pset.Inputs {
|
||||||
if len(input.TapLeafScript) > 0 {
|
if len(input.TapLeafScript) > 0 {
|
||||||
@@ -265,7 +265,7 @@ func (s *liquidWallet) SignTransaction(
|
|||||||
|
|
||||||
tapScriptSig := psetv2.TapScriptSig{
|
tapScriptSig := psetv2.TapScriptSig{
|
||||||
PartialSig: psetv2.PartialSig{
|
PartialSig: psetv2.PartialSig{
|
||||||
PubKey: schnorr.SerializePubKey(s.walletData.Pubkey),
|
PubKey: schnorr.SerializePubKey(s.walletData.PubKey),
|
||||||
Signature: sig.Serialize(),
|
Signature: sig.Serialize(),
|
||||||
},
|
},
|
||||||
LeafHash: hash.CloneBytes(),
|
LeafHash: hash.CloneBytes(),
|
||||||
@@ -330,8 +330,8 @@ func (w *liquidWallet) getAddress(
|
|||||||
liquidNet := utils.ToElementsNetwork(data.Network)
|
liquidNet := utils.ToElementsNetwork(data.Network)
|
||||||
|
|
||||||
vtxoScript := tree.NewDefaultVtxoScript(
|
vtxoScript := tree.NewDefaultVtxoScript(
|
||||||
w.walletData.Pubkey,
|
w.walletData.PubKey,
|
||||||
data.AspPubkey,
|
data.ServerPubKey,
|
||||||
uint(data.UnilateralExitDelay),
|
uint(data.UnilateralExitDelay),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -342,13 +342,13 @@ func (w *liquidWallet) getAddress(
|
|||||||
|
|
||||||
offchainAddr := &common.Address{
|
offchainAddr := &common.Address{
|
||||||
HRP: data.Network.Addr,
|
HRP: data.Network.Addr,
|
||||||
Asp: data.AspPubkey,
|
Server: data.ServerPubKey,
|
||||||
VtxoTapKey: vtxoTapKey,
|
VtxoTapKey: vtxoTapKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
boardingVtxoScript := tree.NewDefaultVtxoScript(
|
boardingVtxoScript := tree.NewDefaultVtxoScript(
|
||||||
w.walletData.Pubkey,
|
w.walletData.PubKey,
|
||||||
data.AspPubkey,
|
data.ServerPubKey,
|
||||||
uint(data.UnilateralExitDelay*2),
|
uint(data.UnilateralExitDelay*2),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const (
|
|||||||
type walletData struct {
|
type walletData struct {
|
||||||
EncryptedPrvkey string `json:"encrypted_private_key"`
|
EncryptedPrvkey string `json:"encrypted_private_key"`
|
||||||
PasswordHash string `json:"password_hash"`
|
PasswordHash string `json:"password_hash"`
|
||||||
Pubkey string `json:"pubkey"`
|
PubKey string `json:"pubkey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d walletData) isEmpty() bool {
|
func (d walletData) isEmpty() bool {
|
||||||
@@ -30,12 +30,12 @@ func (d walletData) isEmpty() bool {
|
|||||||
func (d walletData) decode() walletstore.WalletData {
|
func (d walletData) decode() walletstore.WalletData {
|
||||||
encryptedPrvkey, _ := hex.DecodeString(d.EncryptedPrvkey)
|
encryptedPrvkey, _ := hex.DecodeString(d.EncryptedPrvkey)
|
||||||
passwordHash, _ := hex.DecodeString(d.PasswordHash)
|
passwordHash, _ := hex.DecodeString(d.PasswordHash)
|
||||||
buf, _ := hex.DecodeString(d.Pubkey)
|
buf, _ := hex.DecodeString(d.PubKey)
|
||||||
pubkey, _ := secp256k1.ParsePubKey(buf)
|
pubkey, _ := secp256k1.ParsePubKey(buf)
|
||||||
return walletstore.WalletData{
|
return walletstore.WalletData{
|
||||||
EncryptedPrvkey: encryptedPrvkey,
|
EncryptedPrvkey: encryptedPrvkey,
|
||||||
PasswordHash: passwordHash,
|
PasswordHash: passwordHash,
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ func (d walletData) asMap() map[string]string {
|
|||||||
return map[string]string{
|
return map[string]string{
|
||||||
"encrypted_private_key": d.EncryptedPrvkey,
|
"encrypted_private_key": d.EncryptedPrvkey,
|
||||||
"password_hash": d.PasswordHash,
|
"password_hash": d.PasswordHash,
|
||||||
"pubkey": d.Pubkey,
|
"pubkey": d.PubKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ func (s *fileStore) AddWallet(data walletstore.WalletData) error {
|
|||||||
wd := &walletData{
|
wd := &walletData{
|
||||||
EncryptedPrvkey: hex.EncodeToString(data.EncryptedPrvkey),
|
EncryptedPrvkey: hex.EncodeToString(data.EncryptedPrvkey),
|
||||||
PasswordHash: hex.EncodeToString(data.PasswordHash),
|
PasswordHash: hex.EncodeToString(data.PasswordHash),
|
||||||
Pubkey: hex.EncodeToString(data.Pubkey.SerializeCompressed()),
|
PubKey: hex.EncodeToString(data.PubKey.SerializeCompressed()),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.write(wd); err != nil {
|
if err := s.write(wd); err != nil {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
type WalletData struct {
|
type WalletData struct {
|
||||||
EncryptedPrvkey []byte
|
EncryptedPrvkey []byte
|
||||||
PasswordHash []byte
|
PasswordHash []byte
|
||||||
Pubkey *secp256k1.PublicKey
|
PubKey *secp256k1.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
type WalletStore interface {
|
type WalletStore interface {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func TestWalletStore(t *testing.T) {
|
|||||||
testWalletData := walletstore.WalletData{
|
testWalletData := walletstore.WalletData{
|
||||||
EncryptedPrvkey: make([]byte, 32),
|
EncryptedPrvkey: make([]byte, 32),
|
||||||
PasswordHash: make([]byte, 32),
|
PasswordHash: make([]byte, 32),
|
||||||
Pubkey: key.PubKey(),
|
PubKey: key.PubKey(),
|
||||||
}
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
|||||||
@@ -29,18 +29,18 @@ func (w *singlekeyWallet) Create(
|
|||||||
) (string, error) {
|
) (string, error) {
|
||||||
var privateKey *secp256k1.PrivateKey
|
var privateKey *secp256k1.PrivateKey
|
||||||
if len(seed) <= 0 {
|
if len(seed) <= 0 {
|
||||||
privKey, err := utils.GenerateRandomPrivateKey()
|
prvkey, err := utils.GenerateRandomPrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
privateKey = privKey
|
privateKey = prvkey
|
||||||
} else {
|
} else {
|
||||||
privKeyBytes, err := hex.DecodeString(seed)
|
prvkeyBytes, err := hex.DecodeString(seed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
privateKey = secp256k1.PrivKeyFromBytes(privKeyBytes)
|
privateKey = secp256k1.PrivKeyFromBytes(prvkeyBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
pwd := []byte(password)
|
pwd := []byte(password)
|
||||||
@@ -55,7 +55,7 @@ func (w *singlekeyWallet) Create(
|
|||||||
walletData := walletstore.WalletData{
|
walletData := walletstore.WalletData{
|
||||||
EncryptedPrvkey: encryptedPrivateKey,
|
EncryptedPrvkey: encryptedPrivateKey,
|
||||||
PasswordHash: passwordHash,
|
PasswordHash: passwordHash,
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
}
|
}
|
||||||
if err := w.walletStore.AddWallet(walletData); err != nil {
|
if err := w.walletStore.AddWallet(walletData); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ func TestWallet(t *testing.T) {
|
|||||||
key, _ := btcec.NewPrivateKey()
|
key, _ := btcec.NewPrivateKey()
|
||||||
password := "password"
|
password := "password"
|
||||||
testStoreData := sdktypes.Config{
|
testStoreData := sdktypes.Config{
|
||||||
AspUrl: "localhost:7070",
|
ServerUrl: "localhost:7070",
|
||||||
AspPubkey: key.PubKey(),
|
ServerPubKey: key.PubKey(),
|
||||||
WalletType: wallet.SingleKeyWallet,
|
WalletType: wallet.SingleKeyWallet,
|
||||||
ClientType: client.GrpcClient,
|
ClientType: client.GrpcClient,
|
||||||
Network: common.LiquidRegTest,
|
Network: common.LiquidRegTest,
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type storeData struct {
|
type storeData struct {
|
||||||
AspUrl string `json:"asp_url"`
|
ServerUrl string `json:"server_url"`
|
||||||
AspPubkey string `json:"asp_pubkey"`
|
ServerPubKey string `json:"server_pubkey"`
|
||||||
WalletType string `json:"wallet_type"`
|
WalletType string `json:"wallet_type"`
|
||||||
ClientType string `json:"client_type"`
|
ClientType string `json:"client_type"`
|
||||||
ExplorerURL string `json:"explorer_url"`
|
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 {
|
func (s *configStore) AddData(ctx context.Context, data types.Config) error {
|
||||||
sd := &storeData{
|
sd := &storeData{
|
||||||
AspUrl: data.AspUrl,
|
ServerUrl: data.ServerUrl,
|
||||||
AspPubkey: hex.EncodeToString(data.AspPubkey.SerializeCompressed()),
|
ServerPubKey: hex.EncodeToString(data.ServerPubKey.SerializeCompressed()),
|
||||||
WalletType: data.WalletType,
|
WalletType: data.WalletType,
|
||||||
ClientType: data.ClientType,
|
ClientType: data.ClientType,
|
||||||
Network: data.Network.Name,
|
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) {
|
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() {
|
if key.IsNull() || key.IsUndefined() {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ func (s *configStore) GetData(ctx context.Context) (*types.Config, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
aspPubkey, err := secp256k1.ParsePubKey(buf)
|
serverPubkey, err := secp256k1.ParsePubKey(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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())
|
withTxFeed, _ := strconv.ParseBool(s.store.Call("getItem", "with_transaction_feed").String())
|
||||||
|
|
||||||
return &types.Config{
|
return &types.Config{
|
||||||
AspUrl: s.store.Call("getItem", "asp_url").String(),
|
ServerUrl: s.store.Call("getItem", "server_url").String(),
|
||||||
AspPubkey: aspPubkey,
|
ServerPubKey: serverPubkey,
|
||||||
WalletType: s.store.Call("getItem", "wallet_type").String(),
|
WalletType: s.store.Call("getItem", "wallet_type").String(),
|
||||||
ClientType: s.store.Call("getItem", "client_type").String(),
|
ClientType: s.store.Call("getItem", "client_type").String(),
|
||||||
Network: network,
|
Network: network,
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ func init() {
|
|||||||
js.Global().Set("receive", ReceiveWrapper())
|
js.Global().Set("receive", ReceiveWrapper())
|
||||||
js.Global().Set("sendOnChain", SendOnChainWrapper())
|
js.Global().Set("sendOnChain", SendOnChainWrapper())
|
||||||
js.Global().Set("sendOffChain", SendOffChainWrapper())
|
js.Global().Set("sendOffChain", SendOffChainWrapper())
|
||||||
js.Global().Set("sendAsync", SendAsyncWrapper())
|
|
||||||
js.Global().Set("settle", SettleWrapper())
|
js.Global().Set("settle", SettleWrapper())
|
||||||
js.Global().Set("unilateralRedeem", UnilateralRedeemWrapper())
|
js.Global().Set("unilateralRedeem", UnilateralRedeemWrapper())
|
||||||
js.Global().Set("collaborativeRedeem", CollaborativeRedeemWrapper())
|
js.Global().Set("collaborativeRedeem", CollaborativeRedeemWrapper())
|
||||||
@@ -41,8 +40,8 @@ func init() {
|
|||||||
js.Global().Set("setNostrNotificationRecipient", SetNostrNotificationRecipientWrapper())
|
js.Global().Set("setNostrNotificationRecipient", SetNostrNotificationRecipientWrapper())
|
||||||
js.Global().Set("listVtxos", ListVtxosWrapper())
|
js.Global().Set("listVtxos", ListVtxosWrapper())
|
||||||
|
|
||||||
js.Global().Set("getAspUrl", GetAspUrlWrapper())
|
js.Global().Set("getServerUrl", GetServerUrlWrapper())
|
||||||
js.Global().Set("getAspPubKeyHex", GetAspPubkeyWrapper())
|
js.Global().Set("getServerPubkeyHex", GetServerPubkeyWrapper())
|
||||||
js.Global().Set("getWalletType", GetWalletTypeWrapper())
|
js.Global().Set("getWalletType", GetWalletTypeWrapper())
|
||||||
js.Global().Set("getClientType", GetClientTypeWrapper())
|
js.Global().Set("getClientType", GetClientTypeWrapper())
|
||||||
js.Global().Set("getNetwork", GetNetworkWrapper())
|
js.Global().Set("getNetwork", GetNetworkWrapper())
|
||||||
|
|||||||
@@ -16,18 +16,18 @@ import (
|
|||||||
type walletData struct {
|
type walletData struct {
|
||||||
EncryptedPrvkey string `json:"encrypted_private_key"`
|
EncryptedPrvkey string `json:"encrypted_private_key"`
|
||||||
PasswordHash string `json:"password_hash"`
|
PasswordHash string `json:"password_hash"`
|
||||||
Pubkey string `json:"pubkey"`
|
PubKey string `json:"pubkey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d walletData) decode() *walletstore.WalletData {
|
func (d walletData) decode() *walletstore.WalletData {
|
||||||
encryptedPrvkey, _ := hex.DecodeString(d.EncryptedPrvkey)
|
encryptedPrvkey, _ := hex.DecodeString(d.EncryptedPrvkey)
|
||||||
passwordHash, _ := hex.DecodeString(d.PasswordHash)
|
passwordHash, _ := hex.DecodeString(d.PasswordHash)
|
||||||
buf, _ := hex.DecodeString(d.Pubkey)
|
buf, _ := hex.DecodeString(d.PubKey)
|
||||||
pubkey, _ := secp256k1.ParsePubKey(buf)
|
pubkey, _ := secp256k1.ParsePubKey(buf)
|
||||||
return &walletstore.WalletData{
|
return &walletstore.WalletData{
|
||||||
EncryptedPrvkey: encryptedPrvkey,
|
EncryptedPrvkey: encryptedPrvkey,
|
||||||
PasswordHash: passwordHash,
|
PasswordHash: passwordHash,
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ func (s *walletStore) AddWallet(data walletstore.WalletData) error {
|
|||||||
wd := &walletData{
|
wd := &walletData{
|
||||||
EncryptedPrvkey: hex.EncodeToString(data.EncryptedPrvkey),
|
EncryptedPrvkey: hex.EncodeToString(data.EncryptedPrvkey),
|
||||||
PasswordHash: hex.EncodeToString(data.PasswordHash),
|
PasswordHash: hex.EncodeToString(data.PasswordHash),
|
||||||
Pubkey: hex.EncodeToString(data.Pubkey.SerializeCompressed()),
|
PubKey: hex.EncodeToString(data.PubKey.SerializeCompressed()),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.writeData(wd); err != nil {
|
if err := s.writeData(wd); err != nil {
|
||||||
@@ -57,7 +57,7 @@ func (s *walletStore) GetWallet() (*walletstore.WalletData, error) {
|
|||||||
data := walletData{
|
data := walletData{
|
||||||
EncryptedPrvkey: s.store.Call("getItem", "encrypted_private_key").String(),
|
EncryptedPrvkey: s.store.Call("getItem", "encrypted_private_key").String(),
|
||||||
PasswordHash: s.store.Call("getItem", "password_hash").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
|
return data.decode(), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func InitWrapper() js.Func {
|
|||||||
err := arkSdkClient.InitWithWallet(context.Background(), arksdk.InitWithWalletArgs{
|
err := arkSdkClient.InitWithWallet(context.Background(), arksdk.InitWithWalletArgs{
|
||||||
ClientType: args[1].String(),
|
ClientType: args[1].String(),
|
||||||
Wallet: walletSvc,
|
Wallet: walletSvc,
|
||||||
AspUrl: args[2].String(),
|
ServerUrl: args[2].String(),
|
||||||
Seed: args[3].String(),
|
Seed: args[3].String(),
|
||||||
Password: args[4].String(),
|
Password: args[4].String(),
|
||||||
ExplorerURL: args[6].String(),
|
ExplorerURL: args[6].String(),
|
||||||
@@ -227,28 +227,6 @@ func SendOnChainWrapper() js.Func {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SendOffChainWrapper() 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) {
|
return JSPromise(func(args []js.Value) (interface{}, error) {
|
||||||
if len(args) != 2 {
|
if len(args) != 2 {
|
||||||
return nil, errors.New("invalid number of args")
|
return nil, errors.New("invalid number of args")
|
||||||
@@ -260,11 +238,7 @@ func SendAsyncWrapper() js.Func {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if receivers == nil || len(receivers) == 0 {
|
txID, err := arkSdkClient.SendOffChain(
|
||||||
return nil, errors.New("no receivers specified")
|
|
||||||
}
|
|
||||||
|
|
||||||
txID, err := arkSdkClient.SendAsync(
|
|
||||||
context.Background(), withExpiryCoinselect, receivers,
|
context.Background(), withExpiryCoinselect, receivers,
|
||||||
)
|
)
|
||||||
if err != nil {
|
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{} {
|
return js.FuncOf(func(this js.Value, p []js.Value) interface{} {
|
||||||
data, _ := arkSdkClient.GetConfigData(context.Background())
|
data, _ := arkSdkClient.GetConfigData(context.Background())
|
||||||
var url string
|
var url string
|
||||||
if data != nil {
|
if data != nil {
|
||||||
url = data.AspUrl
|
url = data.ServerUrl
|
||||||
}
|
}
|
||||||
return js.ValueOf(url)
|
return js.ValueOf(url)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAspPubkeyWrapper() js.Func {
|
func GetServerPubkeyWrapper() js.Func {
|
||||||
return js.FuncOf(func(this js.Value, p []js.Value) interface{} {
|
return js.FuncOf(func(this js.Value, p []js.Value) interface{} {
|
||||||
data, _ := arkSdkClient.GetConfigData(context.Background())
|
data, _ := arkSdkClient.GetConfigData(context.Background())
|
||||||
var aspPubkey string
|
var serverPubkey string
|
||||||
if data != nil {
|
if data != nil {
|
||||||
aspPubkey = hex.EncodeToString(data.AspPubkey.SerializeCompressed())
|
serverPubkey = hex.EncodeToString(data.ServerPubKey.SerializeCompressed())
|
||||||
}
|
}
|
||||||
return js.ValueOf(aspPubkey)
|
return js.ValueOf(serverPubkey)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Ark Server
|
# 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!**
|
**ALPHA STAGE SOFTWARE: USE AT YOUR OWN RISK!**
|
||||||
|
|
||||||
|
|||||||
@@ -89,11 +89,11 @@ func (a *adminService) GetRoundDetails(ctx context.Context, roundId string) (*Ro
|
|||||||
OutputsVtxos: []string{},
|
OutputsVtxos: []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, payment := range round.Payments {
|
for _, request := range round.TxRequests {
|
||||||
// TODO: Add fees amount
|
// 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() {
|
if receiver.IsOnchain() {
|
||||||
roundDetails.TotalExitAmount += receiver.Amount
|
roundDetails.TotalExitAmount += receiver.Amount
|
||||||
roundDetails.ExitAddresses = append(roundDetails.ExitAddresses, receiver.OnchainAddress)
|
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
|
roundDetails.TotalVtxosAmount += receiver.Amount
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, input := range payment.Inputs {
|
for _, input := range request.Inputs {
|
||||||
roundDetails.InputsVtxos = append(roundDetails.InputsVtxos, input.Txid)
|
roundDetails.InputsVtxos = append(roundDetails.InputsVtxos, input.Txid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ func (a *adminService) GetScheduledSweeps(ctx context.Context) ([]ScheduledSweep
|
|||||||
|
|
||||||
for _, round := range sweepableRounds {
|
for _, round := range sweepableRounds {
|
||||||
sweepable, err := findSweepableOutputs(
|
sweepable, err := findSweepableOutputs(
|
||||||
ctx, a.walletSvc, a.txBuilder, a.sweeperTimeUnit, round.CongestionTree,
|
ctx, a.walletSvc, a.txBuilder, a.sweeperTimeUnit, round.VtxoTree,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ type covenantService struct {
|
|||||||
scanner ports.BlockchainScanner
|
scanner ports.BlockchainScanner
|
||||||
sweeper *sweeper
|
sweeper *sweeper
|
||||||
|
|
||||||
paymentRequests *paymentsMap
|
txRequests *txRequestsQueue
|
||||||
forfeitTxs *forfeitTxsMap
|
forfeitTxs *forfeitTxsMap
|
||||||
|
|
||||||
eventsCh chan domain.RoundEvent
|
eventsCh chan domain.RoundEvent
|
||||||
transactionEventsCh chan TransactionEvent
|
transactionEventsCh chan TransactionEvent
|
||||||
@@ -94,7 +94,7 @@ func NewCovenantService(
|
|||||||
builder: builder,
|
builder: builder,
|
||||||
scanner: scanner,
|
scanner: scanner,
|
||||||
sweeper: newSweeper(walletSvc, repoManager, builder, scheduler, notificationPrefix),
|
sweeper: newSweeper(walletSvc, repoManager, builder, scheduler, notificationPrefix),
|
||||||
paymentRequests: newPaymentsMap(),
|
txRequests: newTxRequestsQueue(),
|
||||||
forfeitTxs: newForfeitTxsMap(builder),
|
forfeitTxs: newForfeitTxsMap(builder),
|
||||||
eventsCh: make(chan domain.RoundEvent),
|
eventsCh: make(chan domain.RoundEvent),
|
||||||
transactionEventsCh: make(chan TransactionEvent),
|
transactionEventsCh: make(chan TransactionEvent),
|
||||||
@@ -287,14 +287,14 @@ func (s *covenantService) SpendVtxos(ctx context.Context, inputs []ports.Input)
|
|||||||
vtxosInputs = append(vtxosInputs, vtxo)
|
vtxosInputs = append(vtxosInputs, vtxo)
|
||||||
}
|
}
|
||||||
|
|
||||||
payment, err := domain.NewPayment(vtxosInputs)
|
request, err := domain.NewTxRequest(vtxosInputs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if err := s.paymentRequests.push(*payment, boardingInputs); err != nil {
|
if err := s.txRequests.push(*request, boardingInputs); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return payment.Id, nil
|
return request.Id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantService) newBoardingInput(tx *transaction.Transaction, input ports.Input) (*ports.BoardingInput, error) {
|
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 {
|
func (s *covenantService) ClaimVtxos(ctx context.Context, creds string, receivers []domain.Receiver) error {
|
||||||
// Check credentials
|
// Check credentials
|
||||||
payment, ok := s.paymentRequests.view(creds)
|
request, ok := s.txRequests.view(creds)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("invalid credentials")
|
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 err
|
||||||
}
|
}
|
||||||
return s.paymentRequests.update(*payment)
|
return s.txRequests.update(*request)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantService) UpdatePaymentStatus(_ context.Context, id string) error {
|
func (s *covenantService) UpdateTxRequestStatus(_ context.Context, id string) error {
|
||||||
return s.paymentRequests.updatePingTimestamp(id)
|
return s.txRequests.updatePingTimestamp(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantService) SubmitRedeemTx(context.Context, string) (string, error) {
|
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)
|
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")
|
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
|
return s.transactionEventsCh
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantService) GetRoundByTxid(ctx context.Context, poolTxid string) (*domain.Round, error) {
|
func (s *covenantService) GetRoundByTxid(ctx context.Context, roundTxid string) (*domain.Round, error) {
|
||||||
return s.repoManager.Rounds().GetRoundWithTxid(ctx, poolTxid)
|
return s.repoManager.Rounds().GetRoundWithTxid(ctx, roundTxid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantService) GetCurrentRound(ctx context.Context) (*domain.Round, error) {
|
func (s *covenantService) GetCurrentRound(ctx context.Context) (*domain.Round, error) {
|
||||||
@@ -472,11 +472,11 @@ func (s *covenantService) GetInfo(ctx context.Context) (*ServiceInfo, error) {
|
|||||||
}, nil
|
}, 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
|
// if the user sends an ephemeral pubkey, something is going wrong client-side
|
||||||
// we should delete the associated payment
|
// we should delete the associated tx request
|
||||||
if err := s.paymentRequests.delete(paymentId); err != nil {
|
if err := s.txRequests.delete(requestID); err != nil {
|
||||||
log.WithError(err).Warn("failed to delete payment")
|
log.WithError(err).Warnf("failed to delete tx request %s", requestID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ErrTreeSigningNotRequired
|
return ErrTreeSigningNotRequired
|
||||||
@@ -554,22 +554,22 @@ func (s *covenantService) startFinalization() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: understand how many payments must be popped from the queue and actually registered for the round
|
// TODO: understand how many tx requests must be popped from the queue and actually registered for the round
|
||||||
num := s.paymentRequests.len()
|
num := s.txRequests.len()
|
||||||
if num == 0 {
|
if num == 0 {
|
||||||
roundAborted = true
|
roundAborted = true
|
||||||
err := fmt.Errorf("no payments registered")
|
err := fmt.Errorf("no tx requests registered")
|
||||||
round.Fail(fmt.Errorf("round aborted: %s", err))
|
round.Fail(fmt.Errorf("round aborted: %s", err))
|
||||||
log.WithError(err).Debugf("round %s aborted", round.Id)
|
log.WithError(err).Debugf("round %s aborted", round.Id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if num > paymentsThreshold {
|
if num > txRequestsThreshold {
|
||||||
num = paymentsThreshold
|
num = txRequestsThreshold
|
||||||
}
|
}
|
||||||
payments, boardingInputs, _, _ := s.paymentRequests.pop(num)
|
requests, boardingInputs, _, _ := s.txRequests.pop(num)
|
||||||
if _, err := round.RegisterPayments(payments); err != nil {
|
if _, err := round.RegisterTxRequests(requests); err != nil {
|
||||||
round.Fail(fmt.Errorf("failed to register payments: %s", err))
|
round.Fail(fmt.Errorf("failed to register tx requests: %s", err))
|
||||||
log.WithError(err).Warn("failed to register payments")
|
log.WithError(err).Warn("failed to register tx requests")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,18 +580,18 @@ func (s *covenantService) startFinalization() {
|
|||||||
return
|
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 {
|
if err != nil {
|
||||||
round.Fail(fmt.Errorf("failed to create pool tx: %s", err))
|
round.Fail(fmt.Errorf("failed to create round tx: %s", err))
|
||||||
log.WithError(err).Warn("failed to create pool tx")
|
log.WithError(err).Warn("failed to create round tx")
|
||||||
return
|
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(
|
if _, err := round.StartFinalization(
|
||||||
connectorAddress, connectors, tree, unsignedPoolTx,
|
connectorAddress, connectors, tree, unsignedRoundTx,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
round.Fail(fmt.Errorf("failed to start finalization: %s", err))
|
round.Fail(fmt.Errorf("failed to start finalization: %s", err))
|
||||||
log.WithError(err).Warn("failed to start finalization")
|
log.WithError(err).Warn("failed to start finalization")
|
||||||
@@ -670,8 +670,8 @@ func (s *covenantService) finalizeRound() {
|
|||||||
txid, err := s.wallet.BroadcastTransaction(ctx, signedRoundTx)
|
txid, err := s.wallet.BroadcastTransaction(ctx, signedRoundTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("failed to broadcast round tx: %s", signedRoundTx)
|
log.Debugf("failed to broadcast round tx: %s", signedRoundTx)
|
||||||
changes = round.Fail(fmt.Errorf("failed to broadcast pool tx: %s", err))
|
changes = round.Fail(fmt.Errorf("failed to broadcast round tx: %s", err))
|
||||||
log.WithError(err).Warn("failed to broadcast pool tx")
|
log.WithError(err).Warn("failed to broadcast round tx")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,7 +682,7 @@ func (s *covenantService) finalizeRound() {
|
|||||||
return
|
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() {
|
func (s *covenantService) listenToScannerNotifications() {
|
||||||
@@ -906,7 +906,7 @@ func (s *covenantService) updateVtxoSet(round *domain.Round) {
|
|||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
repo := s.repoManager.Vtxos()
|
repo := s.repoManager.Vtxos()
|
||||||
spentVtxos := getSpentVtxos(round.Payments)
|
spentVtxos := getSpentVtxos(round.TxRequests)
|
||||||
if len(spentVtxos) > 0 {
|
if len(spentVtxos) > 0 {
|
||||||
for {
|
for {
|
||||||
if err := repo.SpendVtxos(ctx, spentVtxos, round.Txid); err != nil {
|
if err := repo.SpendVtxos(ctx, spentVtxos, round.Txid); err != nil {
|
||||||
@@ -970,8 +970,8 @@ func (s *covenantService) updateVtxoSet(round *domain.Round) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.transactionEventsCh <- RoundTransactionEvent{
|
s.transactionEventsCh <- RoundTransactionEvent{
|
||||||
RoundTxID: round.Txid,
|
RoundTxid: round.Txid,
|
||||||
SpentVtxos: getSpentVtxos(round.Payments),
|
SpentVtxos: getSpentVtxos(round.TxRequests),
|
||||||
SpendableVtxos: s.getNewVtxos(round),
|
SpendableVtxos: s.getNewVtxos(round),
|
||||||
ClaimedBoardingInputs: boardingInputs,
|
ClaimedBoardingInputs: boardingInputs,
|
||||||
}
|
}
|
||||||
@@ -984,7 +984,7 @@ func (s *covenantService) propagateEvents(round *domain.Round) {
|
|||||||
case domain.RoundFinalizationStarted:
|
case domain.RoundFinalizationStarted:
|
||||||
ev := domain.RoundFinalizationStarted{
|
ev := domain.RoundFinalizationStarted{
|
||||||
Id: e.Id,
|
Id: e.Id,
|
||||||
CongestionTree: e.CongestionTree,
|
VtxoTree: e.VtxoTree,
|
||||||
Connectors: e.Connectors,
|
Connectors: e.Connectors,
|
||||||
RoundTx: e.RoundTx,
|
RoundTx: e.RoundTx,
|
||||||
MinRelayFeeRate: int64(s.wallet.MinRelayFeeRate(context.Background())),
|
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)
|
expirationTime := s.sweeper.scheduler.AddNow(s.roundLifetime)
|
||||||
|
|
||||||
if err := s.sweeper.schedule(
|
if err := s.sweeper.schedule(
|
||||||
expirationTime, round.Txid, round.CongestionTree,
|
expirationTime, round.Txid, round.VtxoTree,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
log.WithError(err).Warn("failed to schedule sweep tx")
|
log.WithError(err).Warn("failed to schedule sweep tx")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantService) getNewVtxos(round *domain.Round) []domain.Vtxo {
|
func (s *covenantService) getNewVtxos(round *domain.Round) []domain.Vtxo {
|
||||||
if len(round.CongestionTree) <= 0 {
|
if len(round.VtxoTree) <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
createdAt := time.Now().Unix()
|
createdAt := time.Now().Unix()
|
||||||
|
|
||||||
leaves := round.CongestionTree.Leaves()
|
leaves := round.VtxoTree.Leaves()
|
||||||
vtxos := make([]domain.Vtxo, 0)
|
vtxos := make([]domain.Vtxo, 0)
|
||||||
for _, node := range leaves {
|
for _, node := range leaves {
|
||||||
tx, _ := psetv2.NewPsetFromBase64(node.Tx)
|
tx, _ := psetv2.NewPsetFromBase64(node.Tx)
|
||||||
@@ -1038,7 +1038,7 @@ func (s *covenantService) getNewVtxos(round *domain.Round) []domain.Vtxo {
|
|||||||
|
|
||||||
vtxos = append(vtxos, domain.Vtxo{
|
vtxos = append(vtxos, domain.Vtxo{
|
||||||
VtxoKey: domain.VtxoKey{Txid: node.Txid, VOut: uint32(i)},
|
VtxoKey: domain.VtxoKey{Txid: node.Txid, VOut: uint32(i)},
|
||||||
Pubkey: vtxoPubkey,
|
PubKey: vtxoPubkey,
|
||||||
Amount: uint64(out.Value),
|
Amount: uint64(out.Value),
|
||||||
RoundTxid: round.Txid,
|
RoundTxid: round.Txid,
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
@@ -1113,7 +1113,7 @@ func (s *covenantService) restoreWatchingVtxos() error {
|
|||||||
func (s *covenantService) extractVtxosScripts(vtxos []domain.Vtxo) ([]string, error) {
|
func (s *covenantService) extractVtxosScripts(vtxos []domain.Vtxo) ([]string, error) {
|
||||||
indexedScripts := make(map[string]struct{})
|
indexedScripts := make(map[string]struct{})
|
||||||
for _, vtxo := range vtxos {
|
for _, vtxo := range vtxos {
|
||||||
vtxoTapKeyBytes, err := hex.DecodeString(vtxo.Pubkey)
|
vtxoTapKeyBytes, err := hex.DecodeString(vtxo.PubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ type covenantlessService struct {
|
|||||||
scanner ports.BlockchainScanner
|
scanner ports.BlockchainScanner
|
||||||
sweeper *sweeper
|
sweeper *sweeper
|
||||||
|
|
||||||
paymentRequests *paymentsMap
|
txRequests *txRequestsQueue
|
||||||
forfeitTxs *forfeitTxsMap
|
forfeitTxs *forfeitTxsMap
|
||||||
|
|
||||||
eventsCh chan domain.RoundEvent
|
eventsCh chan domain.RoundEvent
|
||||||
transactionEventsCh chan TransactionEvent
|
transactionEventsCh chan TransactionEvent
|
||||||
@@ -99,7 +99,7 @@ func NewCovenantlessService(
|
|||||||
builder: builder,
|
builder: builder,
|
||||||
scanner: scanner,
|
scanner: scanner,
|
||||||
sweeper: newSweeper(walletSvc, repoManager, builder, scheduler, noteUriPrefix),
|
sweeper: newSweeper(walletSvc, repoManager, builder, scheduler, noteUriPrefix),
|
||||||
paymentRequests: newPaymentsMap(),
|
txRequests: newTxRequestsQueue(),
|
||||||
forfeitTxs: newForfeitTxsMap(builder),
|
forfeitTxs: newForfeitTxsMap(builder),
|
||||||
eventsCh: make(chan domain.RoundEvent),
|
eventsCh: make(chan domain.RoundEvent),
|
||||||
transactionEventsCh: make(chan TransactionEvent),
|
transactionEventsCh: make(chan TransactionEvent),
|
||||||
@@ -260,37 +260,37 @@ func (s *covenantlessService) SubmitRedeemTx(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// verify that the user signs a forfeit closure
|
// 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 {
|
for _, sig := range input.TaprootScriptSpendSig {
|
||||||
if !bytes.Equal(sig.XOnlyPubKey, aspXOnlyPubKey) {
|
if !bytes.Equal(sig.XOnlyPubKey, serverXOnlyPubkey) {
|
||||||
parsed, err := schnorr.ParsePubKey(sig.XOnlyPubKey)
|
parsed, err := schnorr.ParsePubKey(sig.XOnlyPubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to parse pubkey: %s", err)
|
return "", fmt.Errorf("failed to parse pubkey: %s", err)
|
||||||
}
|
}
|
||||||
userPubKey = parsed
|
userPubkey = parsed
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if userPubKey == nil {
|
if userPubkey == nil {
|
||||||
return "", fmt.Errorf("redeem transaction is not signed")
|
return "", fmt.Errorf("redeem transaction is not signed")
|
||||||
}
|
}
|
||||||
|
|
||||||
vtxoPublicKeyBytes, err := hex.DecodeString(vtxo.Pubkey)
|
vtxoPubkeyBuf, err := hex.DecodeString(vtxo.PubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to decode vtxo pubkey: %s", err)
|
return "", fmt.Errorf("failed to decode vtxo pubkey: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
vtxoTapKey, err := schnorr.ParsePubKey(vtxoPublicKeyBytes)
|
vtxoPubkey, err := schnorr.ParsePubKey(vtxoPubkeyBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to parse vtxo pubkey: %s", err)
|
return "", fmt.Errorf("failed to parse vtxo pubkey: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify witness utxo
|
// verify witness utxo
|
||||||
pkscript, err := common.P2TRScript(vtxoTapKey)
|
pkscript, err := common.P2TRScript(vtxoPubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to get pkscript: %s", err)
|
return "", fmt.Errorf("failed to get pkscript: %s", err)
|
||||||
}
|
}
|
||||||
@@ -378,8 +378,15 @@ func (s *covenantlessService) SubmitRedeemTx(
|
|||||||
return "", fmt.Errorf("no valid vtxo found")
|
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 {
|
for outIndex, out := range outputs {
|
||||||
vtxoTapKey, err := schnorr.ParsePubKey(out.PkScript[2:])
|
vtxoTapKey, err := schnorr.ParsePubKey(out.PkScript[2:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -393,24 +400,15 @@ func (s *covenantlessService) SubmitRedeemTx(
|
|||||||
Txid: redeemTxid,
|
Txid: redeemTxid,
|
||||||
VOut: uint32(outIndex),
|
VOut: uint32(outIndex),
|
||||||
},
|
},
|
||||||
Pubkey: vtxoPubkey,
|
PubKey: vtxoPubkey,
|
||||||
Amount: uint64(out.Value),
|
Amount: uint64(out.Value),
|
||||||
ExpireAt: expiration,
|
ExpireAt: expiration,
|
||||||
RoundTxid: roundTxid,
|
RoundTxid: roundTxid,
|
||||||
RedeemTx: redeemTx,
|
RedeemTx: signedRedeemTx,
|
||||||
CreatedAt: time.Now().Unix(),
|
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 {
|
if err := s.repoManager.Vtxos().AddVtxos(ctx, newVtxos); err != nil {
|
||||||
return "", fmt.Errorf("failed to add vtxos: %s", err)
|
return "", fmt.Errorf("failed to add vtxos: %s", err)
|
||||||
}
|
}
|
||||||
@@ -429,7 +427,7 @@ func (s *covenantlessService) SubmitRedeemTx(
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
s.transactionEventsCh <- RedeemTransactionEvent{
|
s.transactionEventsCh <- RedeemTransactionEvent{
|
||||||
AsyncTxID: redeemTxid,
|
RedeemTxid: redeemTxid,
|
||||||
SpentVtxos: spentVtxoKeys,
|
SpentVtxos: spentVtxoKeys,
|
||||||
SpendableVtxos: newVtxos,
|
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 {
|
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 {
|
if err := s.txRequests.pushWithNotes(*request, notes); err != nil {
|
||||||
return "", fmt.Errorf("failed to push payment: %s", err)
|
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) {
|
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)
|
vtxosInputs = append(vtxosInputs, vtxo)
|
||||||
}
|
}
|
||||||
|
|
||||||
payment, err := domain.NewPayment(vtxosInputs)
|
request, err := domain.NewTxRequest(vtxosInputs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if err := s.paymentRequests.push(*payment, boardingInputs); err != nil {
|
if err := s.txRequests.push(*request, boardingInputs); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return payment.Id, nil
|
return request.Id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantlessService) newBoardingInput(tx wire.MsgTx, input ports.Input) (*ports.BoardingInput, error) {
|
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)
|
return nil, fmt.Errorf("failed to get taproot key: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedScriptPubKey, err := common.P2TRScript(tapKey)
|
expectedScriptPubkey, err := common.P2TRScript(tapKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get script pubkey: %s", err)
|
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")
|
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 {
|
func (s *covenantlessService) ClaimVtxos(ctx context.Context, creds string, receivers []domain.Receiver) error {
|
||||||
// Check credentials
|
// Check credentials
|
||||||
payment, ok := s.paymentRequests.view(creds)
|
request, ok := s.txRequests.view(creds)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("invalid credentials")
|
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 err
|
||||||
}
|
}
|
||||||
return s.paymentRequests.update(*payment)
|
return s.txRequests.update(*request)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantlessService) UpdatePaymentStatus(_ context.Context, id string) error {
|
func (s *covenantlessService) UpdateTxRequestStatus(_ context.Context, id string) error {
|
||||||
return s.paymentRequests.updatePingTimestamp(id)
|
return s.txRequests.updatePingTimestamp(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantlessService) SignVtxos(ctx context.Context, forfeitTxs []string) error {
|
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)
|
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")
|
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)
|
pubkeyBytes, err := hex.DecodeString(pubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to decode hex pubkey: %s", err)
|
return fmt.Errorf("failed to decode hex pubkey: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ephemeralPublicKey, err := secp256k1.ParsePubKey(pubkeyBytes)
|
ephemeralPubkey, err := secp256k1.ParsePubKey(pubkeyBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse pubkey: %s", err)
|
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(
|
func (s *covenantlessService) RegisterCosignerNonces(
|
||||||
@@ -853,7 +851,7 @@ func (s *covenantlessService) RegisterCosignerNonces(
|
|||||||
|
|
||||||
session.nonces[pubkey] = nonces
|
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() {
|
go func() {
|
||||||
session.nonceDoneC <- struct{}{}
|
session.nonceDoneC <- struct{}{}
|
||||||
}()
|
}()
|
||||||
@@ -884,7 +882,7 @@ func (s *covenantlessService) RegisterCosignerSignatures(
|
|||||||
|
|
||||||
session.signatures[pubkey] = signatures
|
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() {
|
go func() {
|
||||||
session.sigDoneC <- struct{}{}
|
session.sigDoneC <- struct{}{}
|
||||||
}()
|
}()
|
||||||
@@ -992,31 +990,31 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: understand how many payments must be popped from the queue and actually registered for the round
|
// TODO: understand how many tx requests must be popped from the queue and actually registered for the round
|
||||||
num := s.paymentRequests.len()
|
num := s.txRequests.len()
|
||||||
if num == 0 {
|
if num == 0 {
|
||||||
roundAborted = true
|
roundAborted = true
|
||||||
err := fmt.Errorf("no payments registered")
|
err := fmt.Errorf("no tx requests registered")
|
||||||
round.Fail(fmt.Errorf("round aborted: %s", err))
|
round.Fail(fmt.Errorf("round aborted: %s", err))
|
||||||
log.WithError(err).Debugf("round %s aborted", round.Id)
|
log.WithError(err).Debugf("round %s aborted", round.Id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if num > paymentsThreshold {
|
if num > txRequestsThreshold {
|
||||||
num = paymentsThreshold
|
num = txRequestsThreshold
|
||||||
}
|
}
|
||||||
payments, boardingInputs, cosigners, paymentsNotes := s.paymentRequests.pop(num)
|
requests, boardingInputs, cosigners, redeeemedNotes := s.txRequests.pop(num)
|
||||||
if len(payments) > len(cosigners) {
|
if len(requests) > len(cosigners) {
|
||||||
err := fmt.Errorf("missing ephemeral key for payments")
|
err := fmt.Errorf("missing ephemeral key for tx requests")
|
||||||
round.Fail(fmt.Errorf("round aborted: %s", err))
|
round.Fail(fmt.Errorf("round aborted: %s", err))
|
||||||
log.WithError(err).Debugf("round %s aborted", round.Id)
|
log.WithError(err).Debugf("round %s aborted", round.Id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
notes = paymentsNotes
|
notes = redeeemedNotes
|
||||||
|
|
||||||
if _, err := round.RegisterPayments(payments); err != nil {
|
if _, err := round.RegisterTxRequests(requests); err != nil {
|
||||||
round.Fail(fmt.Errorf("failed to register payments: %s", err))
|
round.Fail(fmt.Errorf("failed to register tx requests: %s", err))
|
||||||
log.WithError(err).Warn("failed to register payments")
|
log.WithError(err).Warn("failed to register tx requests")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1038,7 +1036,7 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
|
|
||||||
unsignedRoundTx, vtxoTree, connectorAddress, connectors, err := s.builder.BuildRoundTx(
|
unsignedRoundTx, vtxoTree, connectorAddress, connectors, err := s.builder.BuildRoundTx(
|
||||||
s.pubkey,
|
s.pubkey,
|
||||||
payments,
|
requests,
|
||||||
boardingInputs,
|
boardingInputs,
|
||||||
sweptRounds,
|
sweptRounds,
|
||||||
cosigners...,
|
cosigners...,
|
||||||
@@ -1050,10 +1048,10 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
}
|
}
|
||||||
log.Debugf("round 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 len(vtxoTree) > 0 {
|
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))
|
signingSession := newMusigSigningSession(len(cosigners))
|
||||||
s.treeSigningSessions[round.Id] = signingSession
|
s.treeSigningSessions[round.Id] = signingSession
|
||||||
@@ -1094,11 +1092,11 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
aspSignerSession := bitcointree.NewTreeSignerSession(
|
serverSignerSession := bitcointree.NewTreeSignerSession(
|
||||||
ephemeralKey, sharedOutputAmount, vtxoTree, root.CloneBytes(),
|
ephemeralKey, sharedOutputAmount, vtxoTree, root.CloneBytes(),
|
||||||
)
|
)
|
||||||
|
|
||||||
nonces, err := aspSignerSession.GetNonces()
|
nonces, err := serverSignerSession.GetNonces()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
round.Fail(fmt.Errorf("failed to get nonces: %s", err))
|
round.Fail(fmt.Errorf("failed to get nonces: %s", err))
|
||||||
log.WithError(err).Warn("failed to get nonces")
|
log.WithError(err).Warn("failed to get nonces")
|
||||||
@@ -1142,33 +1140,33 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
|
|
||||||
s.propagateRoundSigningNoncesGeneratedEvent(aggragatedNonces)
|
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))
|
round.Fail(fmt.Errorf("failed to set keys: %s", err))
|
||||||
log.WithError(err).Warn("failed to set keys")
|
log.WithError(err).Warn("failed to set keys")
|
||||||
return
|
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))
|
round.Fail(fmt.Errorf("failed to set aggregated nonces: %s", err))
|
||||||
log.WithError(err).Warn("failed to set aggregated nonces")
|
log.WithError(err).Warn("failed to set aggregated nonces")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// sign the tree as ASP
|
// sign the tree as server
|
||||||
aspTreeSigs, err := aspSignerSession.Sign()
|
serverTreeSigs, err := serverSignerSession.Sign()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
round.Fail(fmt.Errorf("failed to sign tree: %s", err))
|
round.Fail(fmt.Errorf("failed to sign tree: %s", err))
|
||||||
log.WithError(err).Warn("failed to sign tree")
|
log.WithError(err).Warn("failed to sign tree")
|
||||||
return
|
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))
|
round.Fail(fmt.Errorf("failed to add signature: %s", err))
|
||||||
log.WithError(err).Warn("failed to add signature")
|
log.WithError(err).Warn("failed to add signature")
|
||||||
return
|
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)
|
signaturesTimer := time.NewTimer(thirdOfRemainingDuration)
|
||||||
|
|
||||||
@@ -1199,7 +1197,7 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("congestion tree signed for round %s", round.Id)
|
log.Debugf("vtxo tree signed for round %s", round.Id)
|
||||||
|
|
||||||
vtxoTree = signedTree
|
vtxoTree = signedTree
|
||||||
}
|
}
|
||||||
@@ -1216,11 +1214,11 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantlessService) propagateRoundSigningStartedEvent(
|
func (s *covenantlessService) propagateRoundSigningStartedEvent(
|
||||||
unsignedCongestionTree tree.CongestionTree, cosigners []*secp256k1.PublicKey,
|
unsignedVtxoTree tree.VtxoTree, cosigners []*secp256k1.PublicKey,
|
||||||
) {
|
) {
|
||||||
ev := RoundSigningStarted{
|
ev := RoundSigningStarted{
|
||||||
Id: s.currentRound.Id,
|
Id: s.currentRound.Id,
|
||||||
UnsignedVtxoTree: unsignedCongestionTree,
|
UnsignedVtxoTree: unsignedVtxoTree,
|
||||||
Cosigners: cosigners,
|
Cosigners: cosigners,
|
||||||
UnsignedRoundTx: s.currentRound.UnsignedTx,
|
UnsignedRoundTx: s.currentRound.UnsignedTx,
|
||||||
}
|
}
|
||||||
@@ -1311,7 +1309,7 @@ func (s *covenantlessService) finalizeRound(notes []note.Note) {
|
|||||||
|
|
||||||
txid, err := s.wallet.BroadcastTransaction(ctx, signedRoundTx)
|
txid, err := s.wallet.BroadcastTransaction(ctx, signedRoundTx)
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1331,14 +1329,14 @@ func (s *covenantlessService) finalizeRound(notes []note.Note) {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
s.transactionEventsCh <- RoundTransactionEvent{
|
s.transactionEventsCh <- RoundTransactionEvent{
|
||||||
RoundTxID: round.Txid,
|
RoundTxid: round.Txid,
|
||||||
SpentVtxos: getSpentVtxos(round.Payments),
|
SpentVtxos: getSpentVtxos(round.TxRequests),
|
||||||
SpendableVtxos: s.getNewVtxos(round),
|
SpendableVtxos: s.getNewVtxos(round),
|
||||||
ClaimedBoardingInputs: boardingInputs,
|
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() {
|
func (s *covenantlessService) listenToScannerNotifications() {
|
||||||
@@ -1491,7 +1489,7 @@ func (s *covenantlessService) updateVtxoSet(round *domain.Round) {
|
|||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
repo := s.repoManager.Vtxos()
|
repo := s.repoManager.Vtxos()
|
||||||
spentVtxos := getSpentVtxos(round.Payments)
|
spentVtxos := getSpentVtxos(round.TxRequests)
|
||||||
if len(spentVtxos) > 0 {
|
if len(spentVtxos) > 0 {
|
||||||
for {
|
for {
|
||||||
if err := repo.SpendVtxos(ctx, spentVtxos, round.Txid); err != nil {
|
if err := repo.SpendVtxos(ctx, spentVtxos, round.Txid); err != nil {
|
||||||
@@ -1544,7 +1542,7 @@ func (s *covenantlessService) propagateEvents(round *domain.Round) {
|
|||||||
case domain.RoundFinalizationStarted:
|
case domain.RoundFinalizationStarted:
|
||||||
ev := domain.RoundFinalizationStarted{
|
ev := domain.RoundFinalizationStarted{
|
||||||
Id: e.Id,
|
Id: e.Id,
|
||||||
CongestionTree: e.CongestionTree,
|
VtxoTree: e.VtxoTree,
|
||||||
Connectors: e.Connectors,
|
Connectors: e.Connectors,
|
||||||
RoundTx: e.RoundTx,
|
RoundTx: e.RoundTx,
|
||||||
MinRelayFeeRate: int64(s.wallet.MinRelayFeeRate(context.Background())),
|
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)
|
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")
|
log.WithError(err).Warn("failed to schedule sweep tx")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantlessService) getNewVtxos(round *domain.Round) []domain.Vtxo {
|
func (s *covenantlessService) getNewVtxos(round *domain.Round) []domain.Vtxo {
|
||||||
if len(round.CongestionTree) <= 0 {
|
if len(round.VtxoTree) <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
createdAt := time.Now().Unix()
|
createdAt := time.Now().Unix()
|
||||||
|
|
||||||
leaves := round.CongestionTree.Leaves()
|
leaves := round.VtxoTree.Leaves()
|
||||||
vtxos := make([]domain.Vtxo, 0)
|
vtxos := make([]domain.Vtxo, 0)
|
||||||
for _, node := range leaves {
|
for _, node := range leaves {
|
||||||
tx, err := psbt.NewFromRawBytes(strings.NewReader(node.Tx), true)
|
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))
|
vtxoPubkey := hex.EncodeToString(schnorr.SerializePubKey(vtxoTapKey))
|
||||||
|
|
||||||
vtxos = append(vtxos, domain.Vtxo{
|
vtxos = append(vtxos, domain.Vtxo{
|
||||||
VtxoKey: domain.VtxoKey{Txid: node.Txid, VOut: uint32(i)},
|
VtxoKey: domain.VtxoKey{Txid: node.Txid, VOut: uint32(i)},
|
||||||
Pubkey: vtxoPubkey,
|
PubKey: vtxoPubkey,
|
||||||
Amount: uint64(out.Value),
|
Amount: uint64(out.Value),
|
||||||
RoundTxid: round.Txid,
|
RoundTxid: round.Txid,
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
@@ -1672,7 +1669,7 @@ func (s *covenantlessService) extractVtxosScripts(vtxos []domain.Vtxo) ([]string
|
|||||||
indexedScripts := make(map[string]struct{})
|
indexedScripts := make(map[string]struct{})
|
||||||
|
|
||||||
for _, vtxo := range vtxos {
|
for _, vtxo := range vtxos {
|
||||||
vtxoTapKeyBytes, err := hex.DecodeString(vtxo.Pubkey)
|
vtxoTapKeyBytes, err := hex.DecodeString(vtxo.PubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1731,7 +1728,7 @@ func (s *covenantlessService) reactToFraud(ctx context.Context, vtxo domain.Vtxo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
vtxosRepo := s.repoManager.Vtxos()
|
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{
|
vtxos, err := vtxosRepo.GetVtxos(ctx, []domain.VtxoKey{
|
||||||
{Txid: vtxo.SpentBy, VOut: 0},
|
{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)
|
return fmt.Errorf("failed to retrieve round: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
asyncPayVtxo := vtxos[0]
|
storedVtxo := vtxos[0]
|
||||||
if asyncPayVtxo.Redeemed { // redeem tx is already onchain
|
if storedVtxo.Redeemed { // redeem tx is already onchain
|
||||||
return nil
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to finalize redeem tx: %s", err)
|
return fmt.Errorf("failed to finalize redeem tx: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* This package contains intermediary events that are used only by the covenantless version
|
* 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
|
* they are not included in domain because they don't mutate the Round state and should not be persisted
|
||||||
*/
|
*/
|
||||||
package application
|
package application
|
||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
// signer should react to this event by generating a musig2 nonce for each transaction in the tree
|
// signer should react to this event by generating a musig2 nonce for each transaction in the tree
|
||||||
type RoundSigningStarted struct {
|
type RoundSigningStarted struct {
|
||||||
Id string
|
Id string
|
||||||
UnsignedVtxoTree tree.CongestionTree
|
UnsignedVtxoTree tree.VtxoTree
|
||||||
Cosigners []*secp256k1.PublicKey
|
Cosigners []*secp256k1.PublicKey
|
||||||
UnsignedRoundTx string
|
UnsignedRoundTx string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package application
|
|||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
type errPaymentNotFound struct {
|
type errTxRequestNotFound struct {
|
||||||
id string
|
id string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e errPaymentNotFound) Error() string {
|
func (e errTxRequestNotFound) Error() string {
|
||||||
return fmt.Sprintf("payment %s not found", e.id)
|
return fmt.Sprintf("tx request %s not found", e.id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func (p OwnershipProof) validate(vtxo domain.Vtxo) error {
|
|||||||
rootHash := p.ControlBlock.RootHash(p.Script)
|
rootHash := p.ControlBlock.RootHash(p.Script)
|
||||||
vtxoTapKey := txscript.ComputeTaprootOutputKey(bitcointree.UnspendableKey(), rootHash)
|
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")
|
return fmt.Errorf("invalid control block")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
// sweeper is an unexported service running while the main application service is started
|
// sweeper is an unexported service running while the main application service is started
|
||||||
// it is responsible for sweeping onchain shared outputs that expired
|
// 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
|
// 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 {
|
type sweeper struct {
|
||||||
wallet ports.WalletService
|
wallet ports.WalletService
|
||||||
repoManager ports.RepoManager
|
repoManager ports.RepoManager
|
||||||
@@ -58,7 +58,7 @@ func (s *sweeper) start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, round := range allRounds {
|
for _, round := range allRounds {
|
||||||
task := s.createTask(round.Txid, round.CongestionTree)
|
task := s.createTask(round.Txid, round.VtxoTree)
|
||||||
task()
|
task()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,14 +78,14 @@ func (s *sweeper) removeTask(treeRootTxid string) {
|
|||||||
|
|
||||||
// schedule set up a task to be executed once at the given timestamp
|
// schedule set up a task to be executed once at the given timestamp
|
||||||
func (s *sweeper) schedule(
|
func (s *sweeper) schedule(
|
||||||
expirationTimestamp int64, roundTxid string, congestionTree tree.CongestionTree,
|
expirationTimestamp int64, roundTxid string, vtxoTree tree.VtxoTree,
|
||||||
) error {
|
) error {
|
||||||
if len(congestionTree) <= 0 { // skip
|
if len(vtxoTree) <= 0 { // skip
|
||||||
log.Debugf("skipping sweep scheduling (round tx %s), empty congestion tree", roundTxid)
|
log.Debugf("skipping sweep scheduling (round tx %s), empty vtxo tree", roundTxid)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
root, err := congestionTree.Root()
|
root, err := vtxoTree.Root()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ func (s *sweeper) schedule(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
task := s.createTask(roundTxid, congestionTree)
|
task := s.createTask(roundTxid, vtxoTree)
|
||||||
|
|
||||||
var fancyTime string
|
var fancyTime string
|
||||||
if s.scheduler.Unit() == ports.UnixTime {
|
if s.scheduler.Unit() == ports.UnixTime {
|
||||||
@@ -112,7 +112,7 @@ func (s *sweeper) schedule(
|
|||||||
s.scheduledTasks[root.Txid] = struct{}{}
|
s.scheduledTasks[root.Txid] = struct{}{}
|
||||||
s.locker.Unlock()
|
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")
|
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
|
// 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
|
// 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(
|
func (s *sweeper) createTask(
|
||||||
roundTxid string, congestionTree tree.CongestionTree,
|
roundTxid string, vtxoTree tree.VtxoTree,
|
||||||
) func() {
|
) func() {
|
||||||
return func() {
|
return func() {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
root, err := congestionTree.Root()
|
root, err := vtxoTree.Root()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("error while getting root node")
|
log.WithError(err).Error("error while getting root node")
|
||||||
return
|
return
|
||||||
@@ -139,17 +139,17 @@ func (s *sweeper) createTask(
|
|||||||
sweepInputs := make([]ports.SweepInput, 0)
|
sweepInputs := make([]ports.SweepInput, 0)
|
||||||
vtxoKeys := make([]domain.VtxoKey, 0) // vtxos associated to the sweep inputs
|
vtxoKeys := make([]domain.VtxoKey, 0) // vtxos associated to the sweep inputs
|
||||||
|
|
||||||
// inspect the congestion tree to find onchain shared outputs
|
// inspect the vtxo tree to find onchain shared outputs
|
||||||
sharedOutputs, err := findSweepableOutputs(ctx, s.wallet, s.builder, s.scheduler.Unit(), congestionTree)
|
sharedOutputs, err := findSweepableOutputs(ctx, s.wallet, s.builder, s.scheduler.Unit(), vtxoTree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("error while inspecting congestion tree")
|
log.WithError(err).Error("error while inspecting vtxo tree")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for expiredAt, inputs := range sharedOutputs {
|
for expiredAt, inputs := range sharedOutputs {
|
||||||
// if the shared outputs are not expired, schedule a sweep task for it
|
// if the shared outputs are not expired, schedule a sweep task for it
|
||||||
if s.scheduler.AfterNow(expiredAt) {
|
if s.scheduler.AfterNow(expiredAt) {
|
||||||
subtrees, err := computeSubTrees(congestionTree, inputs)
|
subtrees, err := computeSubTrees(vtxoTree, inputs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("error while computing subtrees")
|
log.WithError(err).Error("error while computing subtrees")
|
||||||
continue
|
continue
|
||||||
@@ -185,7 +185,7 @@ func (s *sweeper) createTask(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if it's not a vtxo, find all the vtxos leaves reachable from that input
|
// 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 {
|
if err != nil {
|
||||||
log.WithError(err).Error("error while finding vtxos leaves")
|
log.WithError(err).Error("error while finding vtxos leaves")
|
||||||
continue
|
continue
|
||||||
@@ -301,7 +301,7 @@ func (s *sweeper) createTask(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *sweeper) updateVtxoExpirationTime(
|
func (s *sweeper) updateVtxoExpirationTime(
|
||||||
tree tree.CongestionTree,
|
tree tree.VtxoTree,
|
||||||
expirationTime int64,
|
expirationTime int64,
|
||||||
) error {
|
) error {
|
||||||
leaves := tree.Leaves()
|
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) {
|
func computeSubTrees(vtxoTree tree.VtxoTree, inputs []ports.SweepInput) ([]tree.VtxoTree, error) {
|
||||||
subTrees := make(map[string]tree.CongestionTree, 0)
|
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
|
// it allows to skip the part of the tree that has been broadcasted in the next task
|
||||||
for _, input := range inputs {
|
for _, input := range inputs {
|
||||||
subTree, err := computeSubTree(congestionTree, input.GetHash().String())
|
subTree, err := computeSubTree(vtxoTree, input.GetHash().String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("error while finding sub tree")
|
log.WithError(err).Error("error while finding sub tree")
|
||||||
continue
|
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
|
// 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 {
|
for i, subTree := range subTrees {
|
||||||
notIncludedInOtherTrees := true
|
notIncludedInOtherTrees := true
|
||||||
|
|
||||||
@@ -426,19 +426,19 @@ func computeSubTrees(congestionTree tree.CongestionTree, inputs []ports.SweepInp
|
|||||||
return filteredSubTrees, nil
|
return filteredSubTrees, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func computeSubTree(congestionTree tree.CongestionTree, newRoot string) (tree.CongestionTree, error) {
|
func computeSubTree(vtxoTree tree.VtxoTree, newRoot string) (tree.VtxoTree, error) {
|
||||||
for _, level := range congestionTree {
|
for _, level := range vtxoTree {
|
||||||
for _, node := range level {
|
for _, node := range level {
|
||||||
if node.Txid == newRoot || node.ParentTxid == newRoot {
|
if node.Txid == newRoot || node.ParentTxid == newRoot {
|
||||||
newTree := make(tree.CongestionTree, 0)
|
newTree := make(tree.VtxoTree, 0)
|
||||||
newTree = append(newTree, []tree.Node{node})
|
newTree = append(newTree, []tree.Node{node})
|
||||||
|
|
||||||
children := congestionTree.Children(node.Txid)
|
children := vtxoTree.Children(node.Txid)
|
||||||
for len(children) > 0 {
|
for len(children) > 0 {
|
||||||
newTree = append(newTree, children)
|
newTree = append(newTree, children)
|
||||||
newChildren := make([]tree.Node, 0)
|
newChildren := make([]tree.Node, 0)
|
||||||
for _, child := range children {
|
for _, child := range children {
|
||||||
newChildren = append(newChildren, congestionTree.Children(child.Txid)...)
|
newChildren = append(newChildren, vtxoTree.Children(child.Txid)...)
|
||||||
}
|
}
|
||||||
children = newChildren
|
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")
|
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()
|
tr1Root, err := tr1.Root()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@@ -468,7 +468,7 @@ func containsTree(tr0 tree.CongestionTree, tr1 tree.CongestionTree) (bool, error
|
|||||||
return false, nil
|
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) {
|
func extractVtxoOutpoint(leaf tree.Node) (*domain.VtxoKey, error) {
|
||||||
if !leaf.Leaf {
|
if !leaf.Leaf {
|
||||||
return nil, fmt.Errorf("node is not a leaf")
|
return nil, fmt.Errorf("node is not a leaf")
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
paymentsThreshold = int64(128)
|
txRequestsThreshold = int64(128)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
@@ -22,11 +22,11 @@ type Service interface {
|
|||||||
ClaimVtxos(ctx context.Context, creds string, receivers []domain.Receiver) error
|
ClaimVtxos(ctx context.Context, creds string, receivers []domain.Receiver) error
|
||||||
SignVtxos(ctx context.Context, forfeitTxs []string) error
|
SignVtxos(ctx context.Context, forfeitTxs []string) error
|
||||||
SignRoundTx(ctx context.Context, roundTx 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)
|
GetRoundById(ctx context.Context, id string) (*domain.Round, error)
|
||||||
GetCurrentRound(ctx context.Context) (*domain.Round, error)
|
GetCurrentRound(ctx context.Context) (*domain.Round, error)
|
||||||
GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent
|
GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent
|
||||||
UpdatePaymentStatus(ctx context.Context, paymentId string) error
|
UpdateTxRequestStatus(ctx context.Context, requestID string) error
|
||||||
ListVtxos(
|
ListVtxos(
|
||||||
ctx context.Context, address string,
|
ctx context.Context, address string,
|
||||||
) (spendableVtxos, spentVtxos []domain.Vtxo, err error)
|
) (spendableVtxos, spentVtxos []domain.Vtxo, err error)
|
||||||
@@ -36,7 +36,7 @@ type Service interface {
|
|||||||
ctx context.Context, userPubkey *secp256k1.PublicKey,
|
ctx context.Context, userPubkey *secp256k1.PublicKey,
|
||||||
) (address string, scripts []string, err error)
|
) (address string, scripts []string, err error)
|
||||||
// Tree signing methods
|
// Tree signing methods
|
||||||
RegisterCosignerPubkey(ctx context.Context, paymentId string, ephemeralPublicKey string) error
|
RegisterCosignerPubkey(ctx context.Context, requestID string, ephemeralPubkey string) error
|
||||||
RegisterCosignerNonces(
|
RegisterCosignerNonces(
|
||||||
ctx context.Context, roundID string,
|
ctx context.Context, roundID string,
|
||||||
pubkey *secp256k1.PublicKey, nonces string,
|
pubkey *secp256k1.PublicKey, nonces string,
|
||||||
@@ -106,7 +106,7 @@ type TransactionEvent interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RoundTransactionEvent struct {
|
type RoundTransactionEvent struct {
|
||||||
RoundTxID string
|
RoundTxid string
|
||||||
SpentVtxos []domain.VtxoKey
|
SpentVtxos []domain.VtxoKey
|
||||||
SpendableVtxos []domain.Vtxo
|
SpendableVtxos []domain.Vtxo
|
||||||
ClaimedBoardingInputs []domain.VtxoKey
|
ClaimedBoardingInputs []domain.VtxoKey
|
||||||
@@ -117,7 +117,7 @@ func (r RoundTransactionEvent) Type() TransactionEventType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RedeemTransactionEvent struct {
|
type RedeemTransactionEvent struct {
|
||||||
AsyncTxID string
|
RedeemTxid string
|
||||||
SpentVtxos []domain.VtxoKey
|
SpentVtxos []domain.VtxoKey
|
||||||
SpendableVtxos []domain.Vtxo
|
SpendableVtxos []domain.Vtxo
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,32 +16,32 @@ import (
|
|||||||
"github.com/nbd-wtf/go-nostr/nip19"
|
"github.com/nbd-wtf/go-nostr/nip19"
|
||||||
)
|
)
|
||||||
|
|
||||||
type timedPayment struct {
|
type timedTxRequest struct {
|
||||||
domain.Payment
|
domain.TxRequest
|
||||||
boardingInputs []ports.BoardingInput
|
boardingInputs []ports.BoardingInput
|
||||||
notes []note.Note
|
notes []note.Note
|
||||||
timestamp time.Time
|
timestamp time.Time
|
||||||
pingTimestamp time.Time
|
pingTimestamp time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type paymentsMap struct {
|
type txRequestsQueue struct {
|
||||||
lock *sync.RWMutex
|
lock *sync.RWMutex
|
||||||
payments map[string]*timedPayment
|
requests map[string]*timedTxRequest
|
||||||
ephemeralKeys map[string]*secp256k1.PublicKey
|
ephemeralKeys map[string]*secp256k1.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPaymentsMap() *paymentsMap {
|
func newTxRequestsQueue() *txRequestsQueue {
|
||||||
paymentsById := make(map[string]*timedPayment)
|
requestsById := make(map[string]*timedTxRequest)
|
||||||
lock := &sync.RWMutex{}
|
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()
|
m.lock.RLock()
|
||||||
defer m.lock.RUnlock()
|
defer m.lock.RUnlock()
|
||||||
|
|
||||||
count := int64(0)
|
count := int64(0)
|
||||||
for _, p := range m.payments {
|
for _, p := range m.requests {
|
||||||
if len(p.Receivers) > 0 {
|
if len(p.Receivers) > 0 {
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
@@ -49,154 +49,154 @@ func (m *paymentsMap) len() int64 {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *paymentsMap) delete(id string) error {
|
func (m *txRequestsQueue) delete(id string) error {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
|
|
||||||
if _, ok := m.payments[id]; !ok {
|
if _, ok := m.requests[id]; !ok {
|
||||||
return errPaymentNotFound{id}
|
return errTxRequestNotFound{id}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(m.payments, id)
|
delete(m.requests, id)
|
||||||
return nil
|
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()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
|
|
||||||
if _, ok := m.payments[payment.Id]; ok {
|
if _, ok := m.requests[request.Id]; ok {
|
||||||
return fmt.Errorf("duplicated payment %s", payment.Id)
|
return fmt.Errorf("duplicated tx request %s", request.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, note := range notes {
|
for _, note := range notes {
|
||||||
for _, payment := range m.payments {
|
for _, txRequest := range m.requests {
|
||||||
for _, pNote := range payment.notes {
|
for _, rNote := range txRequest.notes {
|
||||||
if note.ID == pNote.ID {
|
if note.ID == rNote.ID {
|
||||||
return fmt.Errorf("duplicated note %s", note)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *paymentsMap) push(
|
func (m *txRequestsQueue) push(
|
||||||
payment domain.Payment,
|
request domain.TxRequest,
|
||||||
boardingInputs []ports.BoardingInput,
|
boardingInputs []ports.BoardingInput,
|
||||||
) error {
|
) error {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
|
|
||||||
if _, ok := m.payments[payment.Id]; ok {
|
if _, ok := m.requests[request.Id]; ok {
|
||||||
return fmt.Errorf("duplicated payment %s", payment.Id)
|
return fmt.Errorf("duplicated tx request %s", request.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, input := range payment.Inputs {
|
for _, input := range request.Inputs {
|
||||||
for _, pay := range m.payments {
|
for _, pay := range m.requests {
|
||||||
for _, pInput := range pay.Inputs {
|
for _, pInput := range pay.Inputs {
|
||||||
if input.VtxoKey.Txid == pInput.VtxoKey.Txid && input.VtxoKey.VOut == pInput.VtxoKey.VOut {
|
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 _, input := range boardingInputs {
|
||||||
for _, pay := range m.payments {
|
for _, request := range m.requests {
|
||||||
for _, pBoardingInput := range pay.boardingInputs {
|
for _, pBoardingInput := range request.boardingInputs {
|
||||||
if input.Txid == pBoardingInput.Txid && input.VOut == pBoardingInput.VOut {
|
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
|
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()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
|
|
||||||
if _, ok := m.payments[paymentId]; !ok {
|
if _, ok := m.requests[requestID]; !ok {
|
||||||
return fmt.Errorf("payment %s not found, cannot register signing ephemeral public key", paymentId)
|
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
|
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()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
|
|
||||||
paymentsByTime := make([]timedPayment, 0, len(m.payments))
|
requestsByTime := make([]timedTxRequest, 0, len(m.requests))
|
||||||
for _, p := range m.payments {
|
for _, p := range m.requests {
|
||||||
// Skip payments without registered receivers.
|
// Skip tx requests without registered receivers.
|
||||||
if len(p.Receivers) <= 0 {
|
if len(p.Receivers) <= 0 {
|
||||||
continue
|
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 {
|
if p.pingTimestamp.IsZero() || time.Since(p.pingTimestamp).Minutes() > 1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
paymentsByTime = append(paymentsByTime, *p)
|
requestsByTime = append(requestsByTime, *p)
|
||||||
}
|
}
|
||||||
sort.SliceStable(paymentsByTime, func(i, j int) bool {
|
sort.SliceStable(requestsByTime, func(i, j int) bool {
|
||||||
return paymentsByTime[i].timestamp.Before(paymentsByTime[j].timestamp)
|
return requestsByTime[i].timestamp.Before(requestsByTime[j].timestamp)
|
||||||
})
|
})
|
||||||
|
|
||||||
if num < 0 || num > int64(len(paymentsByTime)) {
|
if num < 0 || num > int64(len(requestsByTime)) {
|
||||||
num = int64(len(paymentsByTime))
|
num = int64(len(requestsByTime))
|
||||||
}
|
}
|
||||||
|
|
||||||
payments := make([]domain.Payment, 0, num)
|
requests := make([]domain.TxRequest, 0, num)
|
||||||
boardingInputs := make([]ports.BoardingInput, 0)
|
boardingInputs := make([]ports.BoardingInput, 0)
|
||||||
cosigners := make([]*secp256k1.PublicKey, 0, num)
|
cosigners := make([]*secp256k1.PublicKey, 0, num)
|
||||||
notes := make([]note.Note, 0)
|
notes := make([]note.Note, 0)
|
||||||
for _, p := range paymentsByTime[:num] {
|
for _, p := range requestsByTime[:num] {
|
||||||
boardingInputs = append(boardingInputs, p.boardingInputs...)
|
boardingInputs = append(boardingInputs, p.boardingInputs...)
|
||||||
payments = append(payments, p.Payment)
|
requests = append(requests, p.TxRequest)
|
||||||
if pubkey, ok := m.ephemeralKeys[p.Payment.Id]; ok {
|
if pubkey, ok := m.ephemeralKeys[p.TxRequest.Id]; ok {
|
||||||
cosigners = append(cosigners, pubkey)
|
cosigners = append(cosigners, pubkey)
|
||||||
delete(m.ephemeralKeys, p.Payment.Id)
|
delete(m.ephemeralKeys, p.TxRequest.Id)
|
||||||
}
|
}
|
||||||
notes = append(notes, p.notes...)
|
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()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
|
|
||||||
p, ok := m.payments[payment.Id]
|
r, ok := m.requests[request.Id]
|
||||||
if !ok {
|
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
|
// sum inputs = vtxos + boarding utxos + notes
|
||||||
sumOfInputs := uint64(0)
|
sumOfInputs := uint64(0)
|
||||||
for _, input := range payment.Inputs {
|
for _, input := range request.Inputs {
|
||||||
sumOfInputs += input.Amount
|
sumOfInputs += input.Amount
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, boardingInput := range p.boardingInputs {
|
for _, boardingInput := range r.boardingInputs {
|
||||||
sumOfInputs += boardingInput.Amount
|
sumOfInputs += boardingInput.Amount
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, note := range p.notes {
|
for _, note := range r.notes {
|
||||||
sumOfInputs += uint64(note.Value)
|
sumOfInputs += uint64(note.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sum outputs = receivers VTXOs
|
// sum outputs = receivers VTXOs
|
||||||
sumOfOutputs := uint64(0)
|
sumOfOutputs := uint64(0)
|
||||||
for _, receiver := range payment.Receivers {
|
for _, receiver := range request.Receivers {
|
||||||
sumOfOutputs += receiver.Amount
|
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)
|
return fmt.Errorf("sum of inputs %d does not match sum of outputs %d", sumOfInputs, sumOfOutputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Payment = payment
|
r.TxRequest = request
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *paymentsMap) updatePingTimestamp(id string) error {
|
func (m *txRequestsQueue) updatePingTimestamp(id string) error {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
|
|
||||||
payment, ok := m.payments[id]
|
request, ok := m.requests[id]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errPaymentNotFound{id}
|
return errTxRequestNotFound{id}
|
||||||
}
|
}
|
||||||
|
|
||||||
payment.pingTimestamp = time.Now()
|
request.pingTimestamp = time.Now()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *paymentsMap) view(id string) (*domain.Payment, bool) {
|
func (m *txRequestsQueue) view(id string) (*domain.TxRequest, bool) {
|
||||||
m.lock.RLock()
|
m.lock.RLock()
|
||||||
defer m.lock.RUnlock()
|
defer m.lock.RUnlock()
|
||||||
|
|
||||||
payment, ok := m.payments[id]
|
request, ok := m.requests[id]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return &domain.Payment{
|
return &domain.TxRequest{
|
||||||
Id: payment.Id,
|
Id: request.Id,
|
||||||
Inputs: payment.Inputs,
|
Inputs: request.Inputs,
|
||||||
Receivers: payment.Receivers,
|
Receivers: request.Receivers,
|
||||||
}, true
|
}, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,10 +251,10 @@ func newForfeitTxsMap(txBuilder ports.TxBuilder) *forfeitTxsMap {
|
|||||||
return &forfeitTxsMap{&sync.RWMutex{}, txBuilder, make(map[domain.VtxoKey][]string), nil, nil}
|
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)
|
vtxosToSign := make([]domain.Vtxo, 0)
|
||||||
for _, payment := range payments {
|
for _, request := range requests {
|
||||||
vtxosToSign = append(vtxosToSign, payment.Inputs...)
|
vtxosToSign = append(vtxosToSign, request.Inputs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
@@ -318,18 +318,18 @@ func (m *forfeitTxsMap) pop() ([]string, error) {
|
|||||||
return txs, nil
|
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
|
// returns the sweepable outputs as ports.SweepInput mapped by their expiration time
|
||||||
func findSweepableOutputs(
|
func findSweepableOutputs(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
walletSvc ports.WalletService,
|
walletSvc ports.WalletService,
|
||||||
txbuilder ports.TxBuilder,
|
txbuilder ports.TxBuilder,
|
||||||
schedulerUnit ports.TimeUnit,
|
schedulerUnit ports.TimeUnit,
|
||||||
congestionTree tree.CongestionTree,
|
vtxoTree tree.VtxoTree,
|
||||||
) (map[int64][]ports.SweepInput, error) {
|
) (map[int64][]ports.SweepInput, error) {
|
||||||
sweepableOutputs := make(map[int64][]ports.SweepInput)
|
sweepableOutputs := make(map[int64][]ports.SweepInput)
|
||||||
blocktimeCache := make(map[string]int64) // txid -> blocktime / blockheight
|
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 {
|
for len(nodesToCheck) > 0 {
|
||||||
newNodesToCheck := make([]tree.Node, 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
|
// 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"?
|
// We will return the error below, but are we going to schedule the tasks for the "children roots"?
|
||||||
if !node.Leaf {
|
if !node.Leaf {
|
||||||
children := congestionTree.Children(node.Txid)
|
children := vtxoTree.Children(node.Txid)
|
||||||
newNodesToCheck = append(newNodesToCheck, children...)
|
newNodesToCheck = append(newNodesToCheck, children...)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
@@ -393,10 +393,10 @@ func findSweepableOutputs(
|
|||||||
return sweepableOutputs, nil
|
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)
|
vtxos := make([]domain.VtxoKey, 0)
|
||||||
for _, p := range payments {
|
for _, request := range requests {
|
||||||
for _, vtxo := range p.Inputs {
|
for _, vtxo := range request.Inputs {
|
||||||
vtxos = append(vtxos, vtxo.VtxoKey)
|
vtxos = append(vtxos, vtxo.VtxoKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -460,12 +460,12 @@ func nip19toNostrProfile(nostrRecipient string, defaultRelays []string) (string,
|
|||||||
|
|
||||||
nprofileRecipient = nostrRecipient
|
nprofileRecipient = nostrRecipient
|
||||||
case "npub":
|
case "npub":
|
||||||
recipientPublicKey, ok := result.(string)
|
recipientPubkey, ok := result.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", fmt.Errorf("invalid NIP-19 result: %v", result)
|
return "", fmt.Errorf("invalid NIP-19 result: %v", result)
|
||||||
}
|
}
|
||||||
|
|
||||||
nprofileRecipient, err = nip19.EncodeProfile(recipientPublicKey, defaultRelays)
|
nprofileRecipient, err = nip19.EncodeProfile(recipientPubkey, defaultRelays)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to encode nostr profile: %s", err)
|
return "", fmt.Errorf("failed to encode nostr profile: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ func (r RoundStarted) IsEvent() {}
|
|||||||
func (r RoundFinalizationStarted) IsEvent() {}
|
func (r RoundFinalizationStarted) IsEvent() {}
|
||||||
func (r RoundFinalized) IsEvent() {}
|
func (r RoundFinalized) IsEvent() {}
|
||||||
func (r RoundFailed) IsEvent() {}
|
func (r RoundFailed) IsEvent() {}
|
||||||
func (r PaymentsRegistered) IsEvent() {}
|
func (r TxRequestsRegistered) IsEvent() {}
|
||||||
|
|
||||||
type RoundStarted struct {
|
type RoundStarted struct {
|
||||||
Id string
|
Id string
|
||||||
@@ -19,7 +19,7 @@ type RoundStarted struct {
|
|||||||
|
|
||||||
type RoundFinalizationStarted struct {
|
type RoundFinalizationStarted struct {
|
||||||
Id string
|
Id string
|
||||||
CongestionTree tree.CongestionTree // BTC: signed
|
VtxoTree tree.VtxoTree
|
||||||
Connectors []string
|
Connectors []string
|
||||||
ConnectorAddress string
|
ConnectorAddress string
|
||||||
RoundTx string
|
RoundTx string
|
||||||
@@ -39,7 +39,7 @@ type RoundFailed struct {
|
|||||||
Timestamp int64
|
Timestamp int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type PaymentsRegistered struct {
|
type TxRequestsRegistered struct {
|
||||||
Id string
|
Id string
|
||||||
Payments []Payment
|
TxRequests []TxRequest
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,66 +11,66 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Payment struct {
|
type TxRequest struct {
|
||||||
Id string
|
Id string
|
||||||
Inputs []Vtxo
|
Inputs []Vtxo
|
||||||
Receivers []Receiver
|
Receivers []Receiver
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPayment(inputs []Vtxo) (*Payment, error) {
|
func NewTxRequest(inputs []Vtxo) (*TxRequest, error) {
|
||||||
p := &Payment{
|
request := &TxRequest{
|
||||||
Id: uuid.New().String(),
|
Id: uuid.New().String(),
|
||||||
Inputs: inputs,
|
Inputs: inputs,
|
||||||
}
|
}
|
||||||
if err := p.validate(true); err != nil {
|
if err := request.validate(true); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return p, nil
|
return request, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Payment) AddReceivers(receivers []Receiver) (err error) {
|
func (r *TxRequest) AddReceivers(receivers []Receiver) (err error) {
|
||||||
if p.Receivers == nil {
|
if r.Receivers == nil {
|
||||||
p.Receivers = make([]Receiver, 0)
|
r.Receivers = make([]Receiver, 0)
|
||||||
}
|
}
|
||||||
p.Receivers = append(p.Receivers, receivers...)
|
r.Receivers = append(r.Receivers, receivers...)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Payment) TotalInputAmount() uint64 {
|
func (r TxRequest) TotalInputAmount() uint64 {
|
||||||
tot := uint64(0)
|
tot := uint64(0)
|
||||||
for _, in := range p.Inputs {
|
for _, in := range r.Inputs {
|
||||||
tot += in.Amount
|
tot += in.Amount
|
||||||
}
|
}
|
||||||
return tot
|
return tot
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Payment) TotalOutputAmount() uint64 {
|
func (r TxRequest) TotalOutputAmount() uint64 {
|
||||||
tot := uint64(0)
|
tot := uint64(0)
|
||||||
for _, r := range p.Receivers {
|
for _, r := range r.Receivers {
|
||||||
tot += r.Amount
|
tot += r.Amount
|
||||||
}
|
}
|
||||||
return tot
|
return tot
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Payment) validate(ignoreOuts bool) error {
|
func (r TxRequest) validate(ignoreOuts bool) error {
|
||||||
if len(p.Id) <= 0 {
|
if len(r.Id) <= 0 {
|
||||||
return fmt.Errorf("missing id")
|
return fmt.Errorf("missing id")
|
||||||
}
|
}
|
||||||
if ignoreOuts {
|
if ignoreOuts {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(p.Receivers) <= 0 {
|
if len(r.Receivers) <= 0 {
|
||||||
return fmt.Errorf("missing outputs")
|
return fmt.Errorf("missing outputs")
|
||||||
}
|
}
|
||||||
for _, r := range p.Receivers {
|
for _, r := range r.Receivers {
|
||||||
if len(r.OnchainAddress) <= 0 && len(r.Pubkey) <= 0 {
|
if len(r.OnchainAddress) <= 0 && len(r.PubKey) <= 0 {
|
||||||
return fmt.Errorf("missing receiver destination")
|
return fmt.Errorf("missing receiver destination")
|
||||||
}
|
}
|
||||||
if r.Amount == 0 {
|
if r.Amount == 0 {
|
||||||
@@ -107,7 +107,7 @@ func (k VtxoKey) Hash() string {
|
|||||||
type Receiver struct {
|
type Receiver struct {
|
||||||
Amount uint64
|
Amount uint64
|
||||||
OnchainAddress string // onchain
|
OnchainAddress string // onchain
|
||||||
Pubkey string // offchain
|
PubKey string // offchain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Receiver) IsOnchain() bool {
|
func (r Receiver) IsOnchain() bool {
|
||||||
@@ -117,9 +117,9 @@ func (r Receiver) IsOnchain() bool {
|
|||||||
type Vtxo struct {
|
type Vtxo struct {
|
||||||
VtxoKey
|
VtxoKey
|
||||||
Amount uint64
|
Amount uint64
|
||||||
Pubkey string
|
PubKey string
|
||||||
RoundTxid string
|
RoundTxid string
|
||||||
SpentBy string // round txid or async redeem txid
|
SpentBy string // round txid or redeem txid
|
||||||
Spent bool
|
Spent bool
|
||||||
Redeemed bool
|
Redeemed bool
|
||||||
Swept bool
|
Swept bool
|
||||||
@@ -129,7 +129,7 @@ type Vtxo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v Vtxo) TapKey() (*secp256k1.PublicKey, error) {
|
func (v Vtxo) TapKey() (*secp256k1.PublicKey, error) {
|
||||||
pubkeyBytes, err := hex.DecodeString(v.Pubkey)
|
pubkeyBytes, err := hex.DecodeString(v.PubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,36 +16,36 @@ var inputs = []domain.Vtxo{
|
|||||||
Txid: "0000000000000000000000000000000000000000000000000000000000000000",
|
Txid: "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
VOut: 0,
|
VOut: 0,
|
||||||
},
|
},
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
Amount: 1000,
|
Amount: 1000,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPayment(t *testing.T) {
|
func TestTxRequest(t *testing.T) {
|
||||||
t.Run("new_payment", func(t *testing.T) {
|
t.Run("new_tx_request", func(t *testing.T) {
|
||||||
t.Run("valid", 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.NoError(t, err)
|
||||||
require.NotNil(t, payment)
|
require.NotNil(t, request)
|
||||||
require.NotEmpty(t, payment.Id)
|
require.NotEmpty(t, request.Id)
|
||||||
require.Exactly(t, inputs, payment.Inputs)
|
require.Exactly(t, inputs, request.Inputs)
|
||||||
require.Empty(t, payment.Receivers)
|
require.Empty(t, request.Receivers)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("add_receivers", func(t *testing.T) {
|
t.Run("add_receivers", func(t *testing.T) {
|
||||||
t.Run("valid", 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.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,
|
Amount: 450,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
Amount: 550,
|
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.NoError(t, err)
|
||||||
require.NotNil(t, payment)
|
require.NotNil(t, request)
|
||||||
|
|
||||||
for _, f := range fixtures {
|
for _, f := range fixtures {
|
||||||
err := payment.AddReceivers(f.receivers)
|
err := request.AddReceivers(f.receivers)
|
||||||
require.EqualError(t, err, f.expectedErr)
|
require.EqualError(t, err, f.expectedErr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -38,11 +38,11 @@ type Round struct {
|
|||||||
StartingTimestamp int64
|
StartingTimestamp int64
|
||||||
EndingTimestamp int64
|
EndingTimestamp int64
|
||||||
Stage Stage
|
Stage Stage
|
||||||
Payments map[string]Payment
|
TxRequests map[string]TxRequest
|
||||||
Txid string
|
Txid string
|
||||||
UnsignedTx string
|
UnsignedTx string
|
||||||
ForfeitTxs []string
|
ForfeitTxs []string
|
||||||
CongestionTree tree.CongestionTree
|
VtxoTree tree.VtxoTree
|
||||||
Connectors []string
|
Connectors []string
|
||||||
ConnectorAddress string
|
ConnectorAddress string
|
||||||
DustAmount uint64
|
DustAmount uint64
|
||||||
@@ -55,7 +55,7 @@ func NewRound(dustAmount uint64) *Round {
|
|||||||
return &Round{
|
return &Round{
|
||||||
Id: uuid.New().String(),
|
Id: uuid.New().String(),
|
||||||
DustAmount: dustAmount,
|
DustAmount: dustAmount,
|
||||||
Payments: make(map[string]Payment),
|
TxRequests: make(map[string]TxRequest),
|
||||||
changes: make([]RoundEvent, 0),
|
changes: make([]RoundEvent, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ func (r *Round) On(event RoundEvent, replayed bool) {
|
|||||||
r.StartingTimestamp = e.Timestamp
|
r.StartingTimestamp = e.Timestamp
|
||||||
case RoundFinalizationStarted:
|
case RoundFinalizationStarted:
|
||||||
r.Stage.Code = FinalizationStage
|
r.Stage.Code = FinalizationStage
|
||||||
r.CongestionTree = e.CongestionTree
|
r.VtxoTree = e.VtxoTree
|
||||||
r.Connectors = append([]string{}, e.Connectors...)
|
r.Connectors = append([]string{}, e.Connectors...)
|
||||||
r.ConnectorAddress = e.ConnectorAddress
|
r.ConnectorAddress = e.ConnectorAddress
|
||||||
r.UnsignedTx = e.RoundTx
|
r.UnsignedTx = e.RoundTx
|
||||||
@@ -96,12 +96,12 @@ func (r *Round) On(event RoundEvent, replayed bool) {
|
|||||||
case RoundFailed:
|
case RoundFailed:
|
||||||
r.Stage.Failed = true
|
r.Stage.Failed = true
|
||||||
r.EndingTimestamp = e.Timestamp
|
r.EndingTimestamp = e.Timestamp
|
||||||
case PaymentsRegistered:
|
case TxRequestsRegistered:
|
||||||
if r.Payments == nil {
|
if r.TxRequests == nil {
|
||||||
r.Payments = make(map[string]Payment)
|
r.TxRequests = make(map[string]TxRequest)
|
||||||
}
|
}
|
||||||
for _, p := range e.Payments {
|
for _, p := range e.TxRequests {
|
||||||
r.Payments[p.Id] = p
|
r.TxRequests[p.Id] = p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ func (r *Round) On(event RoundEvent, replayed bool) {
|
|||||||
func (r *Round) StartRegistration() ([]RoundEvent, error) {
|
func (r *Round) StartRegistration() ([]RoundEvent, error) {
|
||||||
empty := Stage{}
|
empty := Stage{}
|
||||||
if r.Stage != empty {
|
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{
|
event := RoundStarted{
|
||||||
@@ -125,45 +125,45 @@ func (r *Round) StartRegistration() ([]RoundEvent, error) {
|
|||||||
return []RoundEvent{event}, nil
|
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() {
|
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 {
|
if len(txRequests) <= 0 {
|
||||||
return nil, fmt.Errorf("missing payments to register")
|
return nil, fmt.Errorf("missing tx requests to register")
|
||||||
}
|
}
|
||||||
for _, p := range payments {
|
for _, request := range txRequests {
|
||||||
if err := p.validate(false); err != nil {
|
if err := request.validate(false); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event := PaymentsRegistered{
|
event := TxRequestsRegistered{
|
||||||
Id: r.Id,
|
Id: r.Id,
|
||||||
Payments: payments,
|
TxRequests: txRequests,
|
||||||
}
|
}
|
||||||
r.raise(event)
|
r.raise(event)
|
||||||
|
|
||||||
return []RoundEvent{event}, nil
|
return []RoundEvent{event}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Round) StartFinalization(connectorAddress string, connectors []string, congestionTree tree.CongestionTree, poolTx string) ([]RoundEvent, error) {
|
func (r *Round) StartFinalization(connectorAddress string, connectors []string, vtxoTree tree.VtxoTree, roundTx string) ([]RoundEvent, error) {
|
||||||
if len(poolTx) <= 0 {
|
if len(roundTx) <= 0 {
|
||||||
return nil, fmt.Errorf("missing unsigned pool tx")
|
return nil, fmt.Errorf("missing unsigned round tx")
|
||||||
}
|
}
|
||||||
if r.Stage.Code != RegistrationStage || r.IsFailed() {
|
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 {
|
if len(r.TxRequests) <= 0 {
|
||||||
return nil, fmt.Errorf("no payments registered")
|
return nil, fmt.Errorf("no tx requests registered")
|
||||||
}
|
}
|
||||||
|
|
||||||
event := RoundFinalizationStarted{
|
event := RoundFinalizationStarted{
|
||||||
Id: r.Id,
|
Id: r.Id,
|
||||||
CongestionTree: congestionTree,
|
VtxoTree: vtxoTree,
|
||||||
Connectors: connectors,
|
Connectors: connectors,
|
||||||
ConnectorAddress: connectorAddress,
|
ConnectorAddress: connectorAddress,
|
||||||
RoundTx: poolTx,
|
RoundTx: roundTx,
|
||||||
}
|
}
|
||||||
r.raise(event)
|
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) {
|
func (r *Round) EndFinalization(forfeitTxs []string, txid string) ([]RoundEvent, error) {
|
||||||
if len(forfeitTxs) <= 0 {
|
if len(forfeitTxs) <= 0 {
|
||||||
for _, p := range r.Payments {
|
for _, request := range r.TxRequests {
|
||||||
if len(p.Inputs) > 0 {
|
if len(request.Inputs) > 0 {
|
||||||
return nil, fmt.Errorf("missing list of signed forfeit txs")
|
return nil, fmt.Errorf("missing list of signed forfeit txs")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(txid) <= 0 {
|
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() {
|
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 {
|
if r.Stage.Ended {
|
||||||
return nil, fmt.Errorf("round already finalized")
|
return nil, fmt.Errorf("round already finalized")
|
||||||
@@ -231,16 +231,16 @@ func (r *Round) IsFailed() bool {
|
|||||||
|
|
||||||
func (r *Round) TotalInputAmount() uint64 {
|
func (r *Round) TotalInputAmount() uint64 {
|
||||||
totInputs := 0
|
totInputs := 0
|
||||||
for _, p := range r.Payments {
|
for _, request := range r.TxRequests {
|
||||||
totInputs += len(p.Inputs)
|
totInputs += len(request.Inputs)
|
||||||
}
|
}
|
||||||
return uint64(totInputs * int(r.DustAmount))
|
return uint64(totInputs * int(r.DustAmount))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Round) TotalOutputAmount() uint64 {
|
func (r *Round) TotalOutputAmount() uint64 {
|
||||||
tot := uint64(0)
|
tot := uint64(0)
|
||||||
for _, p := range r.Payments {
|
for _, request := range r.TxRequests {
|
||||||
tot += p.TotalOutputAmount()
|
tot += request.TotalOutputAmount()
|
||||||
}
|
}
|
||||||
return tot
|
return tot
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
dustAmount = uint64(450)
|
dustAmount = uint64(450)
|
||||||
payments = []domain.Payment{
|
requests = []domain.TxRequest{
|
||||||
{
|
{
|
||||||
Id: "0",
|
Id: "0",
|
||||||
Inputs: []domain.Vtxo{
|
Inputs: []domain.Vtxo{
|
||||||
@@ -20,21 +20,21 @@ var (
|
|||||||
Txid: txid,
|
Txid: txid,
|
||||||
VOut: 0,
|
VOut: 0,
|
||||||
},
|
},
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
Amount: 2000,
|
Amount: 2000,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Receivers: []domain.Receiver{
|
Receivers: []domain.Receiver{
|
||||||
{
|
{
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
Amount: 700,
|
Amount: 700,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
Amount: 700,
|
Amount: 700,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
Amount: 600,
|
Amount: 600,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -47,7 +47,7 @@ var (
|
|||||||
Txid: txid,
|
Txid: txid,
|
||||||
VOut: 0,
|
VOut: 0,
|
||||||
},
|
},
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
Amount: 1000,
|
Amount: 1000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -55,20 +55,20 @@ var (
|
|||||||
Txid: txid,
|
Txid: txid,
|
||||||
VOut: 0,
|
VOut: 0,
|
||||||
},
|
},
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
Amount: 1000,
|
Amount: 1000,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Receivers: []domain.Receiver{{
|
Receivers: []domain.Receiver{{
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
Amount: 2000,
|
Amount: 2000,
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
emptyPtx = "cHNldP8BAgQCAAAAAQQBAAEFAQABBgEDAfsEAgAAAAA="
|
emptyPtx = "cHNldP8BAgQCAAAAAQQBAAEFAQABBgEDAfsEAgAAAAA="
|
||||||
emptyTx = "0200000000000000000000"
|
emptyTx = "0200000000000000000000"
|
||||||
txid = "0000000000000000000000000000000000000000000000000000000000000000"
|
txid = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
congestionTree = tree.CongestionTree{
|
vtxoTree = tree.VtxoTree{
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
Txid: txid,
|
Txid: txid,
|
||||||
@@ -113,13 +113,13 @@ var (
|
|||||||
}
|
}
|
||||||
connectors = []string{emptyPtx, emptyPtx, emptyPtx}
|
connectors = []string{emptyPtx, emptyPtx, emptyPtx}
|
||||||
forfeitTxs = []string{emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx}
|
forfeitTxs = []string{emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx, emptyPtx}
|
||||||
poolTx = emptyTx
|
roundTx = emptyTx
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRound(t *testing.T) {
|
func TestRound(t *testing.T) {
|
||||||
testStartRegistration(t)
|
testStartRegistration(t)
|
||||||
|
|
||||||
testRegisterPayments(t)
|
testRegisterTxRequests(t)
|
||||||
|
|
||||||
testStartFinalization(t)
|
testStartFinalization(t)
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ func testStartRegistration(t *testing.T) {
|
|||||||
Failed: true,
|
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{
|
round: &domain.Round{
|
||||||
@@ -174,7 +174,7 @@ func testStartRegistration(t *testing.T) {
|
|||||||
Code: domain.RegistrationStage,
|
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{
|
round: &domain.Round{
|
||||||
@@ -183,7 +183,7 @@ func testStartRegistration(t *testing.T) {
|
|||||||
Code: domain.FinalizationStage,
|
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) {
|
func testRegisterTxRequests(t *testing.T) {
|
||||||
t.Run("register_payments", func(t *testing.T) {
|
t.Run("register_tx_requests", func(t *testing.T) {
|
||||||
t.Run("valid", func(t *testing.T) {
|
t.Run("valid", func(t *testing.T) {
|
||||||
round := domain.NewRound(dustAmount)
|
round := domain.NewRound(dustAmount)
|
||||||
events, err := round.StartRegistration()
|
events, err := round.StartRegistration()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, events)
|
require.NotEmpty(t, events)
|
||||||
|
|
||||||
events, err = round.RegisterPayments(payments)
|
events, err = round.RegisterTxRequests(requests)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, events, 1)
|
require.Len(t, events, 1)
|
||||||
require.Condition(t, func() bool {
|
require.Condition(t, func() bool {
|
||||||
for _, payment := range payments {
|
for _, request := range requests {
|
||||||
_, ok := round.Payments[payment.Id]
|
_, ok := round.TxRequests[request.Id]
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -217,16 +217,16 @@ func testRegisterPayments(t *testing.T) {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
event, ok := events[0].(domain.PaymentsRegistered)
|
event, ok := events[0].(domain.TxRequestsRegistered)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.Equal(t, round.Id, event.Id)
|
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) {
|
t.Run("invalid", func(t *testing.T) {
|
||||||
fixtures := []struct {
|
fixtures := []struct {
|
||||||
round *domain.Round
|
round *domain.Round
|
||||||
payments []domain.Payment
|
requests []domain.TxRequest
|
||||||
expectedErr string
|
expectedErr string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@@ -234,8 +234,8 @@ func testRegisterPayments(t *testing.T) {
|
|||||||
Id: "id",
|
Id: "id",
|
||||||
Stage: domain.Stage{},
|
Stage: domain.Stage{},
|
||||||
},
|
},
|
||||||
payments: payments,
|
requests: requests,
|
||||||
expectedErr: "not in a valid stage to register payments",
|
expectedErr: "not in a valid stage to register tx requests",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
round: &domain.Round{
|
round: &domain.Round{
|
||||||
@@ -245,8 +245,8 @@ func testRegisterPayments(t *testing.T) {
|
|||||||
Failed: true,
|
Failed: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
payments: payments,
|
requests: requests,
|
||||||
expectedErr: "not in a valid stage to register payments",
|
expectedErr: "not in a valid stage to register tx requests",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
round: &domain.Round{
|
round: &domain.Round{
|
||||||
@@ -255,8 +255,8 @@ func testRegisterPayments(t *testing.T) {
|
|||||||
Code: domain.FinalizationStage,
|
Code: domain.FinalizationStage,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
payments: payments,
|
requests: requests,
|
||||||
expectedErr: "not in a valid stage to register payments",
|
expectedErr: "not in a valid stage to register tx requests",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
round: &domain.Round{
|
round: &domain.Round{
|
||||||
@@ -265,13 +265,13 @@ func testRegisterPayments(t *testing.T) {
|
|||||||
Code: domain.RegistrationStage,
|
Code: domain.RegistrationStage,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
payments: nil,
|
requests: nil,
|
||||||
expectedErr: "missing payments to register",
|
expectedErr: "missing tx requests to register",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range fixtures {
|
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.EqualError(t, err, f.expectedErr)
|
||||||
require.Empty(t, events)
|
require.Empty(t, events)
|
||||||
}
|
}
|
||||||
@@ -287,11 +287,11 @@ func testStartFinalization(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, events)
|
require.NotEmpty(t, events)
|
||||||
|
|
||||||
events, err = round.RegisterPayments(payments)
|
events, err = round.RegisterTxRequests(requests)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, events)
|
require.NotEmpty(t, events)
|
||||||
|
|
||||||
events, err = round.StartFinalization("", connectors, congestionTree, poolTx)
|
events, err = round.StartFinalization("", connectors, vtxoTree, roundTx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, events, 1)
|
require.Len(t, events, 1)
|
||||||
require.True(t, round.IsStarted())
|
require.True(t, round.IsStarted())
|
||||||
@@ -302,20 +302,20 @@ func testStartFinalization(t *testing.T) {
|
|||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.Equal(t, round.Id, event.Id)
|
require.Equal(t, round.Id, event.Id)
|
||||||
require.Exactly(t, connectors, event.Connectors)
|
require.Exactly(t, connectors, event.Connectors)
|
||||||
require.Exactly(t, congestionTree, event.CongestionTree)
|
require.Exactly(t, vtxoTree, event.VtxoTree)
|
||||||
require.Exactly(t, poolTx, event.RoundTx)
|
require.Exactly(t, roundTx, event.RoundTx)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("invalid", func(t *testing.T) {
|
t.Run("invalid", func(t *testing.T) {
|
||||||
paymentsById := map[string]domain.Payment{}
|
requestsById := map[string]domain.TxRequest{}
|
||||||
for _, p := range payments {
|
for _, p := range requests {
|
||||||
paymentsById[p.Id] = p
|
requestsById[p.Id] = p
|
||||||
}
|
}
|
||||||
fixtures := []struct {
|
fixtures := []struct {
|
||||||
round *domain.Round
|
round *domain.Round
|
||||||
connectors []string
|
connectors []string
|
||||||
tree tree.CongestionTree
|
tree tree.VtxoTree
|
||||||
poolTx string
|
roundTx string
|
||||||
expectedErr string
|
expectedErr string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@@ -324,12 +324,12 @@ func testStartFinalization(t *testing.T) {
|
|||||||
Stage: domain.Stage{
|
Stage: domain.Stage{
|
||||||
Code: domain.RegistrationStage,
|
Code: domain.RegistrationStage,
|
||||||
},
|
},
|
||||||
Payments: paymentsById,
|
TxRequests: requestsById,
|
||||||
},
|
},
|
||||||
connectors: connectors,
|
connectors: connectors,
|
||||||
tree: congestionTree,
|
tree: vtxoTree,
|
||||||
poolTx: "",
|
roundTx: "",
|
||||||
expectedErr: "missing unsigned pool tx",
|
expectedErr: "missing unsigned round tx",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
round: &domain.Round{
|
round: &domain.Round{
|
||||||
@@ -337,12 +337,12 @@ func testStartFinalization(t *testing.T) {
|
|||||||
Stage: domain.Stage{
|
Stage: domain.Stage{
|
||||||
Code: domain.RegistrationStage,
|
Code: domain.RegistrationStage,
|
||||||
},
|
},
|
||||||
Payments: nil,
|
TxRequests: nil,
|
||||||
},
|
},
|
||||||
connectors: connectors,
|
connectors: connectors,
|
||||||
tree: congestionTree,
|
tree: vtxoTree,
|
||||||
poolTx: poolTx,
|
roundTx: roundTx,
|
||||||
expectedErr: "no payments registered",
|
expectedErr: "no tx requests registered",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
round: &domain.Round{
|
round: &domain.Round{
|
||||||
@@ -350,12 +350,12 @@ func testStartFinalization(t *testing.T) {
|
|||||||
Stage: domain.Stage{
|
Stage: domain.Stage{
|
||||||
Code: domain.UndefinedStage,
|
Code: domain.UndefinedStage,
|
||||||
},
|
},
|
||||||
Payments: paymentsById,
|
TxRequests: requestsById,
|
||||||
},
|
},
|
||||||
connectors: connectors,
|
connectors: connectors,
|
||||||
tree: congestionTree,
|
tree: vtxoTree,
|
||||||
poolTx: poolTx,
|
roundTx: roundTx,
|
||||||
expectedErr: "not in a valid stage to start payment finalization",
|
expectedErr: "not in a valid stage to start finalization",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
round: &domain.Round{
|
round: &domain.Round{
|
||||||
@@ -364,12 +364,12 @@ func testStartFinalization(t *testing.T) {
|
|||||||
Code: domain.RegistrationStage,
|
Code: domain.RegistrationStage,
|
||||||
Failed: true,
|
Failed: true,
|
||||||
},
|
},
|
||||||
Payments: paymentsById,
|
TxRequests: requestsById,
|
||||||
},
|
},
|
||||||
connectors: connectors,
|
connectors: connectors,
|
||||||
tree: congestionTree,
|
tree: vtxoTree,
|
||||||
poolTx: poolTx,
|
roundTx: roundTx,
|
||||||
expectedErr: "not in a valid stage to start payment finalization",
|
expectedErr: "not in a valid stage to start finalization",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
round: &domain.Round{
|
round: &domain.Round{
|
||||||
@@ -377,18 +377,18 @@ func testStartFinalization(t *testing.T) {
|
|||||||
Stage: domain.Stage{
|
Stage: domain.Stage{
|
||||||
Code: domain.FinalizationStage,
|
Code: domain.FinalizationStage,
|
||||||
},
|
},
|
||||||
Payments: paymentsById,
|
TxRequests: requestsById,
|
||||||
},
|
},
|
||||||
connectors: connectors,
|
connectors: connectors,
|
||||||
tree: congestionTree,
|
tree: vtxoTree,
|
||||||
poolTx: poolTx,
|
roundTx: roundTx,
|
||||||
expectedErr: "not in a valid stage to start payment finalization",
|
expectedErr: "not in a valid stage to start finalization",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range fixtures {
|
for _, f := range fixtures {
|
||||||
// TODO fix this
|
// 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.EqualError(t, err, f.expectedErr)
|
||||||
require.Empty(t, events)
|
require.Empty(t, events)
|
||||||
}
|
}
|
||||||
@@ -404,11 +404,11 @@ func testEndFinalization(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, events)
|
require.NotEmpty(t, events)
|
||||||
|
|
||||||
events, err = round.RegisterPayments(payments)
|
events, err = round.RegisterTxRequests(requests)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, events)
|
require.NotEmpty(t, events)
|
||||||
|
|
||||||
events, err = round.StartFinalization("", connectors, congestionTree, poolTx)
|
events, err = round.StartFinalization("", connectors, vtxoTree, roundTx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, events)
|
require.NotEmpty(t, events)
|
||||||
|
|
||||||
@@ -428,9 +428,9 @@ func testEndFinalization(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("invalid", func(t *testing.T) {
|
t.Run("invalid", func(t *testing.T) {
|
||||||
paymentsById := map[string]domain.Payment{}
|
requestsById := map[string]domain.TxRequest{}
|
||||||
for _, p := range payments {
|
for _, p := range requests {
|
||||||
paymentsById[p.Id] = p
|
requestsById[p.Id] = p
|
||||||
}
|
}
|
||||||
fixtures := []struct {
|
fixtures := []struct {
|
||||||
round *domain.Round
|
round *domain.Round
|
||||||
@@ -444,7 +444,7 @@ func testEndFinalization(t *testing.T) {
|
|||||||
Stage: domain.Stage{
|
Stage: domain.Stage{
|
||||||
Code: domain.FinalizationStage,
|
Code: domain.FinalizationStage,
|
||||||
},
|
},
|
||||||
Payments: paymentsById,
|
TxRequests: requestsById,
|
||||||
},
|
},
|
||||||
forfeitTxs: nil,
|
forfeitTxs: nil,
|
||||||
txid: txid,
|
txid: txid,
|
||||||
@@ -459,7 +459,7 @@ func testEndFinalization(t *testing.T) {
|
|||||||
},
|
},
|
||||||
forfeitTxs: forfeitTxs,
|
forfeitTxs: forfeitTxs,
|
||||||
txid: "",
|
txid: "",
|
||||||
expectedErr: "missing pool txid",
|
expectedErr: "missing round txid",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
round: &domain.Round{
|
round: &domain.Round{
|
||||||
@@ -467,7 +467,7 @@ func testEndFinalization(t *testing.T) {
|
|||||||
},
|
},
|
||||||
forfeitTxs: forfeitTxs,
|
forfeitTxs: forfeitTxs,
|
||||||
txid: txid,
|
txid: txid,
|
||||||
expectedErr: "not in a valid stage to end payment finalization",
|
expectedErr: "not in a valid stage to end finalization",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
round: &domain.Round{
|
round: &domain.Round{
|
||||||
@@ -478,7 +478,7 @@ func testEndFinalization(t *testing.T) {
|
|||||||
},
|
},
|
||||||
forfeitTxs: forfeitTxs,
|
forfeitTxs: forfeitTxs,
|
||||||
txid: txid,
|
txid: txid,
|
||||||
expectedErr: "not in a valid stage to end payment finalization",
|
expectedErr: "not in a valid stage to end finalization",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
round: &domain.Round{
|
round: &domain.Round{
|
||||||
@@ -490,7 +490,7 @@ func testEndFinalization(t *testing.T) {
|
|||||||
},
|
},
|
||||||
forfeitTxs: []string{emptyPtx, emptyPtx, emptyPtx, emptyPtx},
|
forfeitTxs: []string{emptyPtx, emptyPtx, emptyPtx, emptyPtx},
|
||||||
txid: txid,
|
txid: txid,
|
||||||
expectedErr: "not in a valid stage to end payment finalization",
|
expectedErr: "not in a valid stage to end finalization",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
round: &domain.Round{
|
round: &domain.Round{
|
||||||
@@ -523,7 +523,7 @@ func testFail(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, events)
|
require.NotEmpty(t, events)
|
||||||
|
|
||||||
events, err = round.RegisterPayments(payments)
|
events, err = round.RegisterTxRequests(requests)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, events)
|
require.NotEmpty(t, events)
|
||||||
|
|
||||||
|
|||||||
@@ -27,15 +27,15 @@ type BoardingInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TxBuilder interface {
|
type TxBuilder interface {
|
||||||
// BuildRoundTx builds a round tx for the given payments, boarding inputs
|
// BuildRoundTx builds a round tx for the given tx requests, boarding inputs
|
||||||
// it selects coin from swept rounds and ASP wallet
|
// it selects coin from swept rounds and server wallet
|
||||||
// returns the round partial tx, the vtxo tree and the set of connectors
|
// returns the round partial tx, the vtxo tree and the set of connectors
|
||||||
BuildRoundTx(
|
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,
|
cosigners ...*secp256k1.PublicKey,
|
||||||
) (
|
) (
|
||||||
roundTx string,
|
roundTx string,
|
||||||
congestionTree tree.CongestionTree,
|
vtxoTree tree.VtxoTree,
|
||||||
connectorAddress string,
|
connectorAddress string,
|
||||||
connectors []string,
|
connectors []string,
|
||||||
err error,
|
err error,
|
||||||
@@ -51,7 +51,7 @@ type TxBuilder interface {
|
|||||||
FinalizeAndExtract(tx string) (txhex string, err error)
|
FinalizeAndExtract(tx string) (txhex string, err error)
|
||||||
VerifyTapscriptPartialSigs(tx string) (valid bool, err error)
|
VerifyTapscriptPartialSigs(tx string) (valid bool, err error)
|
||||||
// FindLeaves returns all the leaves txs that are reachable from the given outpoint
|
// 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)
|
VerifyAndCombinePartialTx(dest string, src string) (string, error)
|
||||||
GetTxID(tx string) (string, error)
|
GetTxID(tx string) (string, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,8 +100,8 @@ func deserializeEvent(buf []byte) (domain.RoundEvent, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
var event = domain.PaymentsRegistered{}
|
var event = domain.TxRequestsRegistered{}
|
||||||
if err := json.Unmarshal(buf, &event); err == nil && len(event.Payments) > 0 {
|
if err := json.Unmarshal(buf, &event); err == nil && len(event.TxRequests) > 0 {
|
||||||
return event, nil
|
return event, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func (r *vtxoRepository) GetVtxos(
|
|||||||
func (r *vtxoRepository) GetVtxosForRound(
|
func (r *vtxoRepository) GetVtxosForRound(
|
||||||
ctx context.Context, txid string,
|
ctx context.Context, txid string,
|
||||||
) ([]domain.Vtxo, error) {
|
) ([]domain.Vtxo, error) {
|
||||||
query := badgerhold.Where("PoolTx").Eq(txid)
|
query := badgerhold.Where("RoundTx").Eq(txid)
|
||||||
return r.findVtxos(ctx, query)
|
return r.findVtxos(ctx, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ func (r *vtxoRepository) GetAllVtxos(
|
|||||||
) ([]domain.Vtxo, []domain.Vtxo, error) {
|
) ([]domain.Vtxo, []domain.Vtxo, error) {
|
||||||
query := badgerhold.Where("Redeemed").Eq(false)
|
query := badgerhold.Where("Redeemed").Eq(false)
|
||||||
if len(pubkey) > 0 {
|
if len(pubkey) > 0 {
|
||||||
query = query.And("Pubkey").Eq(pubkey)
|
query = query.And("PubKey").Eq(pubkey)
|
||||||
}
|
}
|
||||||
vtxos, err := r.findVtxos(ctx, query)
|
vtxos, err := r.findVtxos(ctx, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const (
|
|||||||
pubkey2 = "33ffb3dee353b1a9ebe4ced64b946238d0a4ac364f275d771da6ad2445d07ae0"
|
pubkey2 = "33ffb3dee353b1a9ebe4ced64b946238d0a4ac364f275d771da6ad2445d07ae0"
|
||||||
)
|
)
|
||||||
|
|
||||||
var congestionTree = [][]tree.Node{
|
var vtxoTree = [][]tree.Node{
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
Txid: randomString(32),
|
Txid: randomString(32),
|
||||||
@@ -148,17 +148,17 @@ func testRoundEventRepository(t *testing.T, svc ports.RepoManager) {
|
|||||||
Timestamp: 1701190270,
|
Timestamp: 1701190270,
|
||||||
},
|
},
|
||||||
domain.RoundFinalizationStarted{
|
domain.RoundFinalizationStarted{
|
||||||
Id: "1ea610ff-bf3e-4068-9bfd-b6c3f553467e",
|
Id: "1ea610ff-bf3e-4068-9bfd-b6c3f553467e",
|
||||||
CongestionTree: congestionTree,
|
VtxoTree: vtxoTree,
|
||||||
Connectors: []string{emptyPtx, emptyPtx},
|
Connectors: []string{emptyPtx, emptyPtx},
|
||||||
RoundTx: emptyTx,
|
RoundTx: emptyTx,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
handler: func(round *domain.Round) {
|
handler: func(round *domain.Round) {
|
||||||
require.NotNil(t, round)
|
require.NotNil(t, round)
|
||||||
require.Len(t, round.Events(), 2)
|
require.Len(t, round.Events(), 2)
|
||||||
require.Len(t, round.CongestionTree, 3)
|
require.Len(t, round.VtxoTree, 3)
|
||||||
require.Equal(t, round.CongestionTree.NumberOfNodes(), 7)
|
require.Equal(t, round.VtxoTree.NumberOfNodes(), 7)
|
||||||
require.Len(t, round.Connectors, 2)
|
require.Len(t, round.Connectors, 2)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -170,10 +170,10 @@ func testRoundEventRepository(t *testing.T, svc ports.RepoManager) {
|
|||||||
Timestamp: 1701190270,
|
Timestamp: 1701190270,
|
||||||
},
|
},
|
||||||
domain.RoundFinalizationStarted{
|
domain.RoundFinalizationStarted{
|
||||||
Id: "7578231e-428d-45ae-aaa4-e62c77ad5cec",
|
Id: "7578231e-428d-45ae-aaa4-e62c77ad5cec",
|
||||||
CongestionTree: congestionTree,
|
VtxoTree: vtxoTree,
|
||||||
Connectors: []string{emptyPtx, emptyPtx},
|
Connectors: []string{emptyPtx, emptyPtx},
|
||||||
RoundTx: emptyTx,
|
RoundTx: emptyTx,
|
||||||
},
|
},
|
||||||
domain.RoundFinalized{
|
domain.RoundFinalized{
|
||||||
Id: "7578231e-428d-45ae-aaa4-e62c77ad5cec",
|
Id: "7578231e-428d-45ae-aaa4-e62c77ad5cec",
|
||||||
@@ -237,9 +237,9 @@ func testRoundRepository(t *testing.T, svc ports.RepoManager) {
|
|||||||
require.Condition(t, roundsMatch(*round, *roundById))
|
require.Condition(t, roundsMatch(*round, *roundById))
|
||||||
|
|
||||||
newEvents := []domain.RoundEvent{
|
newEvents := []domain.RoundEvent{
|
||||||
domain.PaymentsRegistered{
|
domain.TxRequestsRegistered{
|
||||||
Id: roundId,
|
Id: roundId,
|
||||||
Payments: []domain.Payment{
|
TxRequests: []domain.TxRequest{
|
||||||
{
|
{
|
||||||
Id: uuid.New().String(),
|
Id: uuid.New().String(),
|
||||||
Inputs: []domain.Vtxo{
|
Inputs: []domain.Vtxo{
|
||||||
@@ -250,12 +250,12 @@ func testRoundRepository(t *testing.T, svc ports.RepoManager) {
|
|||||||
},
|
},
|
||||||
RoundTxid: randomString(32),
|
RoundTxid: randomString(32),
|
||||||
ExpireAt: 7980322,
|
ExpireAt: 7980322,
|
||||||
Pubkey: randomString(32),
|
PubKey: randomString(32),
|
||||||
Amount: 300,
|
Amount: 300,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Receivers: []domain.Receiver{{
|
Receivers: []domain.Receiver{{
|
||||||
Pubkey: randomString(32),
|
PubKey: randomString(32),
|
||||||
Amount: 300,
|
Amount: 300,
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
@@ -270,17 +270,17 @@ func testRoundRepository(t *testing.T, svc ports.RepoManager) {
|
|||||||
},
|
},
|
||||||
RoundTxid: randomString(32),
|
RoundTxid: randomString(32),
|
||||||
ExpireAt: 7980322,
|
ExpireAt: 7980322,
|
||||||
Pubkey: randomString(32),
|
PubKey: randomString(32),
|
||||||
Amount: 600,
|
Amount: 600,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Receivers: []domain.Receiver{
|
Receivers: []domain.Receiver{
|
||||||
{
|
{
|
||||||
Pubkey: randomString(32),
|
PubKey: randomString(32),
|
||||||
Amount: 400,
|
Amount: 400,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Pubkey: randomString(32),
|
PubKey: randomString(32),
|
||||||
Amount: 200,
|
Amount: 200,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -288,16 +288,16 @@ func testRoundRepository(t *testing.T, svc ports.RepoManager) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
domain.RoundFinalizationStarted{
|
domain.RoundFinalizationStarted{
|
||||||
Id: roundId,
|
Id: roundId,
|
||||||
CongestionTree: congestionTree,
|
VtxoTree: vtxoTree,
|
||||||
Connectors: []string{emptyPtx, emptyPtx},
|
Connectors: []string{emptyPtx, emptyPtx},
|
||||||
RoundTx: emptyTx,
|
RoundTx: emptyTx,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
events = append(events, newEvents...)
|
events = append(events, newEvents...)
|
||||||
updatedRound := domain.NewRoundFromEvents(events)
|
updatedRound := domain.NewRoundFromEvents(events)
|
||||||
for _, pay := range updatedRound.Payments {
|
for _, request := range updatedRound.TxRequests {
|
||||||
err = svc.Vtxos().AddVtxos(ctx, pay.Inputs)
|
err = svc.Vtxos().AddVtxos(ctx, request.Inputs)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,7 +346,7 @@ func testVtxoRepository(t *testing.T, svc ports.RepoManager) {
|
|||||||
Txid: randomString(32),
|
Txid: randomString(32),
|
||||||
VOut: 0,
|
VOut: 0,
|
||||||
},
|
},
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
Amount: 1000,
|
Amount: 1000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -354,7 +354,7 @@ func testVtxoRepository(t *testing.T, svc ports.RepoManager) {
|
|||||||
Txid: randomString(32),
|
Txid: randomString(32),
|
||||||
VOut: 1,
|
VOut: 1,
|
||||||
},
|
},
|
||||||
Pubkey: pubkey,
|
PubKey: pubkey,
|
||||||
Amount: 2000,
|
Amount: 2000,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -363,7 +363,7 @@ func testVtxoRepository(t *testing.T, svc ports.RepoManager) {
|
|||||||
Txid: randomString(32),
|
Txid: randomString(32),
|
||||||
VOut: 1,
|
VOut: 1,
|
||||||
},
|
},
|
||||||
Pubkey: pubkey2,
|
PubKey: pubkey2,
|
||||||
Amount: 2000,
|
Amount: 2000,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -567,8 +567,8 @@ func roundsMatch(expected, got domain.Round) assert.Comparison {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range expected.Payments {
|
for k, v := range expected.TxRequests {
|
||||||
gotValue, ok := got.Payments[k]
|
gotValue, ok := got.TxRequests[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
DROP TABLE IF EXISTS round;
|
DROP TABLE IF EXISTS round;
|
||||||
|
|
||||||
DROP TABLE IF EXISTS payment;
|
DROP TABLE IF EXISTS tx_request;
|
||||||
|
|
||||||
DROP TABLE IF EXISTS receiver;
|
DROP TABLE IF EXISTS receiver;
|
||||||
|
|
||||||
|
|||||||
@@ -13,19 +13,19 @@ CREATE TABLE IF NOT EXISTS round (
|
|||||||
swept BOOLEAN NOT NULL
|
swept BOOLEAN NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS payment (
|
CREATE TABLE IF NOT EXISTS tx_request (
|
||||||
id TEXT PRIMARY KEY,
|
id TEXT PRIMARY KEY,
|
||||||
round_id TEXT NOT NULL,
|
round_id TEXT NOT NULL,
|
||||||
FOREIGN KEY (round_id) REFERENCES round(id)
|
FOREIGN KEY (round_id) REFERENCES round(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS receiver (
|
CREATE TABLE IF NOT EXISTS receiver (
|
||||||
payment_id TEXT NOT NULL,
|
request_id TEXT NOT NULL,
|
||||||
pubkey TEXT,
|
pubkey TEXT,
|
||||||
onchain_address TEXT,
|
onchain_address TEXT,
|
||||||
amount INTEGER NOT NULL,
|
amount INTEGER NOT NULL,
|
||||||
FOREIGN KEY (payment_id) REFERENCES payment(id),
|
FOREIGN KEY (request_id) REFERENCES tx_request(id),
|
||||||
PRIMARY KEY (payment_id, pubkey, onchain_address)
|
PRIMARY KEY (request_id, pubkey, onchain_address)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS tx (
|
CREATE TABLE IF NOT EXISTS tx (
|
||||||
@@ -46,17 +46,17 @@ CREATE TABLE IF NOT EXISTS vtxo (
|
|||||||
vout INTEGER NOT NULL,
|
vout INTEGER NOT NULL,
|
||||||
pubkey TEXT NOT NULL,
|
pubkey TEXT NOT NULL,
|
||||||
amount INTEGER NOT NULL,
|
amount INTEGER NOT NULL,
|
||||||
pool_tx TEXT NOT NULL,
|
round_tx TEXT NOT NULL,
|
||||||
spent_by TEXT NOT NULL,
|
spent_by TEXT NOT NULL,
|
||||||
spent BOOLEAN NOT NULL,
|
spent BOOLEAN NOT NULL,
|
||||||
redeemed BOOLEAN NOT NULL,
|
redeemed BOOLEAN NOT NULL,
|
||||||
swept BOOLEAN NOT NULL,
|
swept BOOLEAN NOT NULL,
|
||||||
expire_at INTEGER NOT NULL,
|
expire_at INTEGER NOT NULL,
|
||||||
created_at INTEGER NOT NULL,
|
created_at INTEGER NOT NULL,
|
||||||
payment_id TEXT,
|
request_id TEXT,
|
||||||
redeem_tx TEXT,
|
redeem_tx TEXT,
|
||||||
PRIMARY KEY (txid, vout),
|
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 (
|
CREATE TABLE IF NOT EXISTS note (
|
||||||
@@ -81,22 +81,22 @@ FROM entity
|
|||||||
LEFT OUTER JOIN entity_vtxo
|
LEFT OUTER JOIN entity_vtxo
|
||||||
ON entity.id=entity_vtxo.entity_id;
|
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
|
FROM round
|
||||||
LEFT OUTER JOIN payment
|
LEFT OUTER JOIN tx_request
|
||||||
ON round.id=payment.round_id;
|
ON round.id=tx_request.round_id;
|
||||||
|
|
||||||
CREATE VIEW round_tx_vw AS SELECT tx.*
|
CREATE VIEW round_tx_vw AS SELECT tx.*
|
||||||
FROM round
|
FROM round
|
||||||
LEFT OUTER JOIN tx
|
LEFT OUTER JOIN tx
|
||||||
ON round.id=tx.round_id;
|
ON round.id=tx.round_id;
|
||||||
|
|
||||||
CREATE VIEW payment_receiver_vw AS SELECT receiver.*
|
CREATE VIEW request_receiver_vw AS SELECT receiver.*
|
||||||
FROM payment
|
FROM tx_request
|
||||||
LEFT OUTER JOIN receiver
|
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.*
|
CREATE VIEW request_vtxo_vw AS SELECT vtxo.*
|
||||||
FROM payment
|
FROM tx_request
|
||||||
LEFT OUTER JOIN vtxo
|
LEFT OUTER JOIN vtxo
|
||||||
ON payment.id=vtxo.payment_id;
|
ON tx_request.id=vtxo.request_id;
|
||||||
@@ -86,7 +86,7 @@ func (r *roundRepository) AddOrUpdateRound(ctx context.Context, round domain.Rou
|
|||||||
return fmt.Errorf("failed to upsert round: %w", err)
|
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 {
|
for pos, tx := range round.ForfeitTxs {
|
||||||
if err := querierWithTx.UpsertTransaction(
|
if err := querierWithTx.UpsertTransaction(
|
||||||
ctx,
|
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 {
|
for pos, tx := range levelTxs {
|
||||||
if err := querierWithTx.UpsertTransaction(
|
if err := querierWithTx.UpsertTransaction(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -148,27 +148,27 @@ func (r *roundRepository) AddOrUpdateRound(ctx context.Context, round domain.Rou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(round.Payments) > 0 {
|
if len(round.TxRequests) > 0 {
|
||||||
for _, payment := range round.Payments {
|
for _, request := range round.TxRequests {
|
||||||
if err := querierWithTx.UpsertPayment(
|
if err := querierWithTx.UpsertTxRequest(
|
||||||
ctx,
|
ctx,
|
||||||
queries.UpsertPaymentParams{
|
queries.UpsertTxRequestParams{
|
||||||
ID: payment.Id,
|
ID: request.Id,
|
||||||
RoundID: round.Id,
|
RoundID: round.Id,
|
||||||
},
|
},
|
||||||
); err != nil {
|
); 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(
|
if err := querierWithTx.UpsertReceiver(
|
||||||
ctx,
|
ctx,
|
||||||
queries.UpsertReceiverParams{
|
queries.UpsertReceiverParams{
|
||||||
PaymentID: payment.Id,
|
RequestID: request.Id,
|
||||||
Amount: int64(receiver.Amount),
|
Amount: int64(receiver.Amount),
|
||||||
Pubkey: sql.NullString{
|
Pubkey: sql.NullString{
|
||||||
String: receiver.Pubkey,
|
String: receiver.PubKey,
|
||||||
Valid: len(receiver.Pubkey) > 0,
|
Valid: len(receiver.PubKey) > 0,
|
||||||
},
|
},
|
||||||
OnchainAddress: sql.NullString{
|
OnchainAddress: sql.NullString{
|
||||||
String: receiver.OnchainAddress,
|
String: receiver.OnchainAddress,
|
||||||
@@ -180,19 +180,19 @@ func (r *roundRepository) AddOrUpdateRound(ctx context.Context, round domain.Rou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, input := range payment.Inputs {
|
for _, input := range request.Inputs {
|
||||||
if err := querierWithTx.UpdateVtxoPaymentId(
|
if err := querierWithTx.UpdateVtxoRequestId(
|
||||||
ctx,
|
ctx,
|
||||||
queries.UpdateVtxoPaymentIdParams{
|
queries.UpdateVtxoRequestIdParams{
|
||||||
PaymentID: sql.NullString{
|
RequestID: sql.NullString{
|
||||||
String: payment.Id,
|
String: request.Id,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
},
|
},
|
||||||
Txid: input.Txid,
|
Txid: input.Txid,
|
||||||
Vout: int64(input.VOut),
|
Vout: int64(input.VOut),
|
||||||
},
|
},
|
||||||
); err != nil {
|
); 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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rvs := make([]roundPaymentTxReceiverVtxoRow, 0, len(rows))
|
rvs := make([]combinedRow, 0, len(rows))
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
rvs = append(rvs, roundPaymentTxReceiverVtxoRow{
|
rvs = append(rvs, combinedRow{
|
||||||
round: row.Round,
|
round: row.Round,
|
||||||
payment: row.RoundPaymentVw,
|
request: row.RoundRequestVw,
|
||||||
tx: row.RoundTxVw,
|
tx: row.RoundTxVw,
|
||||||
receiver: row.PaymentReceiverVw,
|
receiver: row.RequestReceiverVw,
|
||||||
vtxo: row.PaymentVtxoVw,
|
vtxo: row.RequestVtxoVw,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
rounds, err := readRoundRows(rvs)
|
rounds, err := rowsToRounds(rvs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -239,18 +239,18 @@ func (r *roundRepository) GetRoundWithTxid(ctx context.Context, txid string) (*d
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rvs := make([]roundPaymentTxReceiverVtxoRow, 0, len(rows))
|
rvs := make([]combinedRow, 0, len(rows))
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
rvs = append(rvs, roundPaymentTxReceiverVtxoRow{
|
rvs = append(rvs, combinedRow{
|
||||||
round: row.Round,
|
round: row.Round,
|
||||||
payment: row.RoundPaymentVw,
|
request: row.RoundRequestVw,
|
||||||
tx: row.RoundTxVw,
|
tx: row.RoundTxVw,
|
||||||
receiver: row.PaymentReceiverVw,
|
receiver: row.RequestReceiverVw,
|
||||||
vtxo: row.PaymentVtxoVw,
|
vtxo: row.RequestVtxoVw,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
rounds, err := readRoundRows(rvs)
|
rounds, err := rowsToRounds(rvs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -268,18 +268,18 @@ func (r *roundRepository) GetSweepableRounds(ctx context.Context) ([]domain.Roun
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rvs := make([]roundPaymentTxReceiverVtxoRow, 0, len(rows))
|
rvs := make([]combinedRow, 0, len(rows))
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
rvs = append(rvs, roundPaymentTxReceiverVtxoRow{
|
rvs = append(rvs, combinedRow{
|
||||||
round: row.Round,
|
round: row.Round,
|
||||||
payment: row.RoundPaymentVw,
|
request: row.RoundRequestVw,
|
||||||
tx: row.RoundTxVw,
|
tx: row.RoundTxVw,
|
||||||
receiver: row.PaymentReceiverVw,
|
receiver: row.RequestReceiverVw,
|
||||||
vtxo: row.PaymentVtxoVw,
|
vtxo: row.RequestVtxoVw,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
rounds, err := readRoundRows(rvs)
|
rounds, err := rowsToRounds(rvs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -299,18 +299,18 @@ func (r *roundRepository) GetSweptRounds(ctx context.Context) ([]domain.Round, e
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rvs := make([]roundPaymentTxReceiverVtxoRow, 0, len(rows))
|
rvs := make([]combinedRow, 0, len(rows))
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
rvs = append(rvs, roundPaymentTxReceiverVtxoRow{
|
rvs = append(rvs, combinedRow{
|
||||||
round: row.Round,
|
round: row.Round,
|
||||||
payment: row.RoundPaymentVw,
|
request: row.RoundRequestVw,
|
||||||
tx: row.RoundTxVw,
|
tx: row.RoundTxVw,
|
||||||
receiver: row.PaymentReceiverVw,
|
receiver: row.RequestReceiverVw,
|
||||||
vtxo: row.PaymentVtxoVw,
|
vtxo: row.RequestVtxoVw,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
rounds, err := readRoundRows(rvs)
|
rounds, err := rowsToRounds(rvs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -324,23 +324,23 @@ func (r *roundRepository) GetSweptRounds(ctx context.Context) ([]domain.Round, e
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func rowToReceiver(row queries.PaymentReceiverVw) domain.Receiver {
|
func rowToReceiver(row queries.RequestReceiverVw) domain.Receiver {
|
||||||
return domain.Receiver{
|
return domain.Receiver{
|
||||||
Amount: uint64(row.Amount.Int64),
|
Amount: uint64(row.Amount.Int64),
|
||||||
Pubkey: row.Pubkey.String,
|
PubKey: row.Pubkey.String,
|
||||||
OnchainAddress: row.OnchainAddress.String,
|
OnchainAddress: row.OnchainAddress.String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type roundPaymentTxReceiverVtxoRow struct {
|
type combinedRow struct {
|
||||||
round queries.Round
|
round queries.Round
|
||||||
payment queries.RoundPaymentVw
|
request queries.RoundRequestVw
|
||||||
tx queries.RoundTxVw
|
tx queries.RoundTxVw
|
||||||
receiver queries.PaymentReceiverVw
|
receiver queries.RequestReceiverVw
|
||||||
vtxo queries.PaymentVtxoVw
|
vtxo queries.RequestVtxoVw
|
||||||
}
|
}
|
||||||
|
|
||||||
func readRoundRows(rows []roundPaymentTxReceiverVtxoRow) ([]*domain.Round, error) {
|
func rowsToRounds(rows []combinedRow) ([]*domain.Round, error) {
|
||||||
rounds := make(map[string]*domain.Round)
|
rounds := make(map[string]*domain.Round)
|
||||||
|
|
||||||
for _, v := range rows {
|
for _, v := range rows {
|
||||||
@@ -364,35 +364,34 @@ func readRoundRows(rows []roundPaymentTxReceiverVtxoRow) ([]*domain.Round, error
|
|||||||
DustAmount: uint64(v.round.DustAmount),
|
DustAmount: uint64(v.round.DustAmount),
|
||||||
Version: uint(v.round.Version),
|
Version: uint(v.round.Version),
|
||||||
Swept: v.round.Swept,
|
Swept: v.round.Swept,
|
||||||
Payments: make(map[string]domain.Payment),
|
TxRequests: make(map[string]domain.TxRequest),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.payment.ID.Valid {
|
if v.request.ID.Valid {
|
||||||
payment, ok := round.Payments[v.payment.ID.String]
|
request, ok := round.TxRequests[v.request.ID.String]
|
||||||
if !ok {
|
if !ok {
|
||||||
payment = domain.Payment{
|
request = domain.TxRequest{
|
||||||
Id: v.payment.ID.String,
|
Id: v.request.ID.String,
|
||||||
Inputs: make([]domain.Vtxo, 0),
|
Inputs: make([]domain.Vtxo, 0),
|
||||||
Receivers: make([]domain.Receiver, 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 {
|
if v.vtxo.RequestID.Valid {
|
||||||
payment, ok = round.Payments[v.vtxo.PaymentID.String]
|
request, ok = round.TxRequests[v.vtxo.RequestID.String]
|
||||||
if !ok {
|
if !ok {
|
||||||
payment = domain.Payment{
|
request = domain.TxRequest{
|
||||||
Id: v.vtxo.PaymentID.String,
|
Id: v.vtxo.RequestID.String,
|
||||||
Inputs: make([]domain.Vtxo, 0),
|
Inputs: make([]domain.Vtxo, 0),
|
||||||
Receivers: make([]domain.Receiver, 0),
|
Receivers: make([]domain.Receiver, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vtxo := rowToPaymentVtxoVw(v.vtxo)
|
vtxo := combinedRowToVtxo(v.vtxo)
|
||||||
found := false
|
found := false
|
||||||
|
for _, v := range request.Inputs {
|
||||||
for _, v := range payment.Inputs {
|
|
||||||
if vtxo.Txid == v.Txid && vtxo.VOut == v.VOut {
|
if vtxo.Txid == v.Txid && vtxo.VOut == v.VOut {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
@@ -400,16 +399,16 @@ func readRoundRows(rows []roundPaymentTxReceiverVtxoRow) ([]*domain.Round, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
payment.Inputs = append(payment.Inputs, rowToPaymentVtxoVw(v.vtxo))
|
request.Inputs = append(request.Inputs, combinedRowToVtxo(v.vtxo))
|
||||||
round.Payments[v.vtxo.PaymentID.String] = payment
|
round.TxRequests[v.vtxo.RequestID.String] = request
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.receiver.PaymentID.Valid {
|
if v.receiver.RequestID.Valid {
|
||||||
payment, ok = round.Payments[v.receiver.PaymentID.String]
|
request, ok = round.TxRequests[v.receiver.RequestID.String]
|
||||||
if !ok {
|
if !ok {
|
||||||
payment = domain.Payment{
|
request = domain.TxRequest{
|
||||||
Id: v.receiver.PaymentID.String,
|
Id: v.receiver.RequestID.String,
|
||||||
Inputs: make([]domain.Vtxo, 0),
|
Inputs: make([]domain.Vtxo, 0),
|
||||||
Receivers: make([]domain.Receiver, 0),
|
Receivers: make([]domain.Receiver, 0),
|
||||||
}
|
}
|
||||||
@@ -418,17 +417,17 @@ func readRoundRows(rows []roundPaymentTxReceiverVtxoRow) ([]*domain.Round, error
|
|||||||
rcv := rowToReceiver(v.receiver)
|
rcv := rowToReceiver(v.receiver)
|
||||||
|
|
||||||
found := false
|
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 (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
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
payment.Receivers = append(payment.Receivers, rcv)
|
request.Receivers = append(request.Receivers, rcv)
|
||||||
round.Payments[v.receiver.PaymentID.String] = payment
|
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
|
round.Connectors[position.Int64] = v.tx.Tx.String
|
||||||
case "tree":
|
case "tree":
|
||||||
level := v.tx.TreeLevel
|
level := v.tx.TreeLevel
|
||||||
round.CongestionTree = extendArray(round.CongestionTree, int(level.Int64))
|
round.VtxoTree = extendArray(round.VtxoTree, int(level.Int64))
|
||||||
round.CongestionTree[int(level.Int64)] = extendArray(round.CongestionTree[int(level.Int64)], int(position.Int64))
|
round.VtxoTree[int(level.Int64)] = extendArray(round.VtxoTree[int(level.Int64)], int(position.Int64))
|
||||||
if round.CongestionTree[int(level.Int64)][position.Int64] == (tree.Node{}) {
|
if round.VtxoTree[int(level.Int64)][position.Int64] == (tree.Node{}) {
|
||||||
round.CongestionTree[int(level.Int64)][position.Int64] = tree.Node{
|
round.VtxoTree[int(level.Int64)][position.Int64] = tree.Node{
|
||||||
Tx: v.tx.Tx.String,
|
Tx: v.tx.Tx.String,
|
||||||
Txid: v.tx.Txid.String,
|
Txid: v.tx.Txid.String,
|
||||||
ParentTxid: v.tx.ParentTxid.String,
|
ParentTxid: v.tx.ParentTxid.String,
|
||||||
@@ -469,15 +468,15 @@ func readRoundRows(rows []roundPaymentTxReceiverVtxoRow) ([]*domain.Round, error
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func rowToPaymentVtxoVw(row queries.PaymentVtxoVw) domain.Vtxo {
|
func combinedRowToVtxo(row queries.RequestVtxoVw) domain.Vtxo {
|
||||||
return domain.Vtxo{
|
return domain.Vtxo{
|
||||||
VtxoKey: domain.VtxoKey{
|
VtxoKey: domain.VtxoKey{
|
||||||
Txid: row.Txid.String,
|
Txid: row.Txid.String,
|
||||||
VOut: uint32(row.Vout.Int64),
|
VOut: uint32(row.Vout.Int64),
|
||||||
},
|
},
|
||||||
Amount: uint64(row.Amount.Int64),
|
Amount: uint64(row.Amount.Int64),
|
||||||
Pubkey: row.Pubkey.String,
|
PubKey: row.Pubkey.String,
|
||||||
RoundTxid: row.PoolTx.String,
|
RoundTxid: row.RoundTx.String,
|
||||||
SpentBy: row.SpentBy.String,
|
SpentBy: row.SpentBy.String,
|
||||||
Spent: row.Spent.Bool,
|
Spent: row.Spent.Bool,
|
||||||
Redeemed: row.Redeemed.Bool,
|
Redeemed: row.Redeemed.Bool,
|
||||||
|
|||||||
@@ -39,41 +39,36 @@ type Note struct {
|
|||||||
ID int64
|
ID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Payment struct {
|
type Receiver struct {
|
||||||
ID string
|
RequestID string
|
||||||
RoundID string
|
Pubkey sql.NullString
|
||||||
|
OnchainAddress sql.NullString
|
||||||
|
Amount int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type PaymentReceiverVw struct {
|
type RequestReceiverVw struct {
|
||||||
PaymentID sql.NullString
|
RequestID sql.NullString
|
||||||
Pubkey sql.NullString
|
Pubkey sql.NullString
|
||||||
OnchainAddress sql.NullString
|
OnchainAddress sql.NullString
|
||||||
Amount sql.NullInt64
|
Amount sql.NullInt64
|
||||||
}
|
}
|
||||||
|
|
||||||
type PaymentVtxoVw struct {
|
type RequestVtxoVw struct {
|
||||||
Txid sql.NullString
|
Txid sql.NullString
|
||||||
Vout sql.NullInt64
|
Vout sql.NullInt64
|
||||||
Pubkey sql.NullString
|
Pubkey sql.NullString
|
||||||
Amount sql.NullInt64
|
Amount sql.NullInt64
|
||||||
PoolTx sql.NullString
|
RoundTx sql.NullString
|
||||||
SpentBy sql.NullString
|
SpentBy sql.NullString
|
||||||
Spent sql.NullBool
|
Spent sql.NullBool
|
||||||
Redeemed sql.NullBool
|
Redeemed sql.NullBool
|
||||||
Swept sql.NullBool
|
Swept sql.NullBool
|
||||||
ExpireAt sql.NullInt64
|
ExpireAt sql.NullInt64
|
||||||
CreatedAt sql.NullInt64
|
CreatedAt sql.NullInt64
|
||||||
PaymentID sql.NullString
|
RequestID sql.NullString
|
||||||
RedeemTx sql.NullString
|
RedeemTx sql.NullString
|
||||||
}
|
}
|
||||||
|
|
||||||
type Receiver struct {
|
|
||||||
PaymentID string
|
|
||||||
Pubkey sql.NullString
|
|
||||||
OnchainAddress sql.NullString
|
|
||||||
Amount int64
|
|
||||||
}
|
|
||||||
|
|
||||||
type Round struct {
|
type Round struct {
|
||||||
ID string
|
ID string
|
||||||
StartingTimestamp int64
|
StartingTimestamp int64
|
||||||
@@ -89,7 +84,7 @@ type Round struct {
|
|||||||
Swept bool
|
Swept bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type RoundPaymentVw struct {
|
type RoundRequestVw struct {
|
||||||
ID sql.NullString
|
ID sql.NullString
|
||||||
RoundID sql.NullString
|
RoundID sql.NullString
|
||||||
}
|
}
|
||||||
@@ -118,18 +113,23 @@ type Tx struct {
|
|||||||
IsLeaf sql.NullBool
|
IsLeaf sql.NullBool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TxRequest struct {
|
||||||
|
ID string
|
||||||
|
RoundID string
|
||||||
|
}
|
||||||
|
|
||||||
type Vtxo struct {
|
type Vtxo struct {
|
||||||
Txid string
|
Txid string
|
||||||
Vout int64
|
Vout int64
|
||||||
Pubkey string
|
Pubkey string
|
||||||
Amount int64
|
Amount int64
|
||||||
PoolTx string
|
RoundTx string
|
||||||
SpentBy string
|
SpentBy string
|
||||||
Spent bool
|
Spent bool
|
||||||
Redeemed bool
|
Redeemed bool
|
||||||
Swept bool
|
Swept bool
|
||||||
ExpireAt int64
|
ExpireAt int64
|
||||||
CreatedAt int64
|
CreatedAt int64
|
||||||
PaymentID sql.NullString
|
RequestID sql.NullString
|
||||||
RedeemTx sql.NullString
|
RedeemTx sql.NullString
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ func (q *Queries) SelectEntitiesByVtxo(ctx context.Context, arg SelectEntitiesBy
|
|||||||
}
|
}
|
||||||
|
|
||||||
const selectNotRedeemedVtxos = `-- name: SelectNotRedeemedVtxos :many
|
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
|
WHERE redeemed = false
|
||||||
`
|
`
|
||||||
|
|
||||||
@@ -213,14 +213,14 @@ func (q *Queries) SelectNotRedeemedVtxos(ctx context.Context) ([]SelectNotRedeem
|
|||||||
&i.Vtxo.Vout,
|
&i.Vtxo.Vout,
|
||||||
&i.Vtxo.Pubkey,
|
&i.Vtxo.Pubkey,
|
||||||
&i.Vtxo.Amount,
|
&i.Vtxo.Amount,
|
||||||
&i.Vtxo.PoolTx,
|
&i.Vtxo.RoundTx,
|
||||||
&i.Vtxo.SpentBy,
|
&i.Vtxo.SpentBy,
|
||||||
&i.Vtxo.Spent,
|
&i.Vtxo.Spent,
|
||||||
&i.Vtxo.Redeemed,
|
&i.Vtxo.Redeemed,
|
||||||
&i.Vtxo.Swept,
|
&i.Vtxo.Swept,
|
||||||
&i.Vtxo.ExpireAt,
|
&i.Vtxo.ExpireAt,
|
||||||
&i.Vtxo.CreatedAt,
|
&i.Vtxo.CreatedAt,
|
||||||
&i.Vtxo.PaymentID,
|
&i.Vtxo.RequestID,
|
||||||
&i.Vtxo.RedeemTx,
|
&i.Vtxo.RedeemTx,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -237,7 +237,7 @@ func (q *Queries) SelectNotRedeemedVtxos(ctx context.Context) ([]SelectNotRedeem
|
|||||||
}
|
}
|
||||||
|
|
||||||
const selectNotRedeemedVtxosWithPubkey = `-- name: SelectNotRedeemedVtxosWithPubkey :many
|
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 = ?
|
WHERE redeemed = false AND pubkey = ?
|
||||||
`
|
`
|
||||||
|
|
||||||
@@ -259,14 +259,14 @@ func (q *Queries) SelectNotRedeemedVtxosWithPubkey(ctx context.Context, pubkey s
|
|||||||
&i.Vtxo.Vout,
|
&i.Vtxo.Vout,
|
||||||
&i.Vtxo.Pubkey,
|
&i.Vtxo.Pubkey,
|
||||||
&i.Vtxo.Amount,
|
&i.Vtxo.Amount,
|
||||||
&i.Vtxo.PoolTx,
|
&i.Vtxo.RoundTx,
|
||||||
&i.Vtxo.SpentBy,
|
&i.Vtxo.SpentBy,
|
||||||
&i.Vtxo.Spent,
|
&i.Vtxo.Spent,
|
||||||
&i.Vtxo.Redeemed,
|
&i.Vtxo.Redeemed,
|
||||||
&i.Vtxo.Swept,
|
&i.Vtxo.Swept,
|
||||||
&i.Vtxo.ExpireAt,
|
&i.Vtxo.ExpireAt,
|
||||||
&i.Vtxo.CreatedAt,
|
&i.Vtxo.CreatedAt,
|
||||||
&i.Vtxo.PaymentID,
|
&i.Vtxo.RequestID,
|
||||||
&i.Vtxo.RedeemTx,
|
&i.Vtxo.RedeemTx,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -343,24 +343,24 @@ func (q *Queries) SelectRoundIdsInRange(ctx context.Context, arg SelectRoundIdsI
|
|||||||
|
|
||||||
const selectRoundWithRoundId = `-- name: SelectRoundWithRoundId :many
|
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,
|
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,
|
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,
|
request_receiver_vw.request_id, request_receiver_vw.pubkey, request_receiver_vw.onchain_address, request_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_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
|
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 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 request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id
|
||||||
LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id
|
LEFT OUTER JOIN request_vtxo_vw ON round_request_vw.id=request_vtxo_vw.request_id
|
||||||
WHERE round.id = ?
|
WHERE round.id = ?
|
||||||
`
|
`
|
||||||
|
|
||||||
type SelectRoundWithRoundIdRow struct {
|
type SelectRoundWithRoundIdRow struct {
|
||||||
Round Round
|
Round Round
|
||||||
RoundPaymentVw RoundPaymentVw
|
RoundRequestVw RoundRequestVw
|
||||||
RoundTxVw RoundTxVw
|
RoundTxVw RoundTxVw
|
||||||
PaymentReceiverVw PaymentReceiverVw
|
RequestReceiverVw RequestReceiverVw
|
||||||
PaymentVtxoVw PaymentVtxoVw
|
RequestVtxoVw RequestVtxoVw
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) SelectRoundWithRoundId(ctx context.Context, id string) ([]SelectRoundWithRoundIdRow, error) {
|
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.DustAmount,
|
||||||
&i.Round.Version,
|
&i.Round.Version,
|
||||||
&i.Round.Swept,
|
&i.Round.Swept,
|
||||||
&i.RoundPaymentVw.ID,
|
&i.RoundRequestVw.ID,
|
||||||
&i.RoundPaymentVw.RoundID,
|
&i.RoundRequestVw.RoundID,
|
||||||
&i.RoundTxVw.ID,
|
&i.RoundTxVw.ID,
|
||||||
&i.RoundTxVw.Tx,
|
&i.RoundTxVw.Tx,
|
||||||
&i.RoundTxVw.RoundID,
|
&i.RoundTxVw.RoundID,
|
||||||
@@ -396,23 +396,23 @@ func (q *Queries) SelectRoundWithRoundId(ctx context.Context, id string) ([]Sele
|
|||||||
&i.RoundTxVw.TreeLevel,
|
&i.RoundTxVw.TreeLevel,
|
||||||
&i.RoundTxVw.ParentTxid,
|
&i.RoundTxVw.ParentTxid,
|
||||||
&i.RoundTxVw.IsLeaf,
|
&i.RoundTxVw.IsLeaf,
|
||||||
&i.PaymentReceiverVw.PaymentID,
|
&i.RequestReceiverVw.RequestID,
|
||||||
&i.PaymentReceiverVw.Pubkey,
|
&i.RequestReceiverVw.Pubkey,
|
||||||
&i.PaymentReceiverVw.OnchainAddress,
|
&i.RequestReceiverVw.OnchainAddress,
|
||||||
&i.PaymentReceiverVw.Amount,
|
&i.RequestReceiverVw.Amount,
|
||||||
&i.PaymentVtxoVw.Txid,
|
&i.RequestVtxoVw.Txid,
|
||||||
&i.PaymentVtxoVw.Vout,
|
&i.RequestVtxoVw.Vout,
|
||||||
&i.PaymentVtxoVw.Pubkey,
|
&i.RequestVtxoVw.Pubkey,
|
||||||
&i.PaymentVtxoVw.Amount,
|
&i.RequestVtxoVw.Amount,
|
||||||
&i.PaymentVtxoVw.PoolTx,
|
&i.RequestVtxoVw.RoundTx,
|
||||||
&i.PaymentVtxoVw.SpentBy,
|
&i.RequestVtxoVw.SpentBy,
|
||||||
&i.PaymentVtxoVw.Spent,
|
&i.RequestVtxoVw.Spent,
|
||||||
&i.PaymentVtxoVw.Redeemed,
|
&i.RequestVtxoVw.Redeemed,
|
||||||
&i.PaymentVtxoVw.Swept,
|
&i.RequestVtxoVw.Swept,
|
||||||
&i.PaymentVtxoVw.ExpireAt,
|
&i.RequestVtxoVw.ExpireAt,
|
||||||
&i.PaymentVtxoVw.CreatedAt,
|
&i.RequestVtxoVw.CreatedAt,
|
||||||
&i.PaymentVtxoVw.PaymentID,
|
&i.RequestVtxoVw.RequestID,
|
||||||
&i.PaymentVtxoVw.RedeemTx,
|
&i.RequestVtxoVw.RedeemTx,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -429,24 +429,24 @@ func (q *Queries) SelectRoundWithRoundId(ctx context.Context, id string) ([]Sele
|
|||||||
|
|
||||||
const selectRoundWithRoundTxId = `-- name: SelectRoundWithRoundTxId :many
|
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,
|
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,
|
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,
|
request_receiver_vw.request_id, request_receiver_vw.pubkey, request_receiver_vw.onchain_address, request_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_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
|
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 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 request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id
|
||||||
LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id
|
LEFT OUTER JOIN request_vtxo_vw ON round_request_vw.id=request_vtxo_vw.request_id
|
||||||
WHERE round.txid = ?
|
WHERE round.txid = ?
|
||||||
`
|
`
|
||||||
|
|
||||||
type SelectRoundWithRoundTxIdRow struct {
|
type SelectRoundWithRoundTxIdRow struct {
|
||||||
Round Round
|
Round Round
|
||||||
RoundPaymentVw RoundPaymentVw
|
RoundRequestVw RoundRequestVw
|
||||||
RoundTxVw RoundTxVw
|
RoundTxVw RoundTxVw
|
||||||
PaymentReceiverVw PaymentReceiverVw
|
RequestReceiverVw RequestReceiverVw
|
||||||
PaymentVtxoVw PaymentVtxoVw
|
RequestVtxoVw RequestVtxoVw
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) SelectRoundWithRoundTxId(ctx context.Context, txid string) ([]SelectRoundWithRoundTxIdRow, error) {
|
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.DustAmount,
|
||||||
&i.Round.Version,
|
&i.Round.Version,
|
||||||
&i.Round.Swept,
|
&i.Round.Swept,
|
||||||
&i.RoundPaymentVw.ID,
|
&i.RoundRequestVw.ID,
|
||||||
&i.RoundPaymentVw.RoundID,
|
&i.RoundRequestVw.RoundID,
|
||||||
&i.RoundTxVw.ID,
|
&i.RoundTxVw.ID,
|
||||||
&i.RoundTxVw.Tx,
|
&i.RoundTxVw.Tx,
|
||||||
&i.RoundTxVw.RoundID,
|
&i.RoundTxVw.RoundID,
|
||||||
@@ -482,23 +482,23 @@ func (q *Queries) SelectRoundWithRoundTxId(ctx context.Context, txid string) ([]
|
|||||||
&i.RoundTxVw.TreeLevel,
|
&i.RoundTxVw.TreeLevel,
|
||||||
&i.RoundTxVw.ParentTxid,
|
&i.RoundTxVw.ParentTxid,
|
||||||
&i.RoundTxVw.IsLeaf,
|
&i.RoundTxVw.IsLeaf,
|
||||||
&i.PaymentReceiverVw.PaymentID,
|
&i.RequestReceiverVw.RequestID,
|
||||||
&i.PaymentReceiverVw.Pubkey,
|
&i.RequestReceiverVw.Pubkey,
|
||||||
&i.PaymentReceiverVw.OnchainAddress,
|
&i.RequestReceiverVw.OnchainAddress,
|
||||||
&i.PaymentReceiverVw.Amount,
|
&i.RequestReceiverVw.Amount,
|
||||||
&i.PaymentVtxoVw.Txid,
|
&i.RequestVtxoVw.Txid,
|
||||||
&i.PaymentVtxoVw.Vout,
|
&i.RequestVtxoVw.Vout,
|
||||||
&i.PaymentVtxoVw.Pubkey,
|
&i.RequestVtxoVw.Pubkey,
|
||||||
&i.PaymentVtxoVw.Amount,
|
&i.RequestVtxoVw.Amount,
|
||||||
&i.PaymentVtxoVw.PoolTx,
|
&i.RequestVtxoVw.RoundTx,
|
||||||
&i.PaymentVtxoVw.SpentBy,
|
&i.RequestVtxoVw.SpentBy,
|
||||||
&i.PaymentVtxoVw.Spent,
|
&i.RequestVtxoVw.Spent,
|
||||||
&i.PaymentVtxoVw.Redeemed,
|
&i.RequestVtxoVw.Redeemed,
|
||||||
&i.PaymentVtxoVw.Swept,
|
&i.RequestVtxoVw.Swept,
|
||||||
&i.PaymentVtxoVw.ExpireAt,
|
&i.RequestVtxoVw.ExpireAt,
|
||||||
&i.PaymentVtxoVw.CreatedAt,
|
&i.RequestVtxoVw.CreatedAt,
|
||||||
&i.PaymentVtxoVw.PaymentID,
|
&i.RequestVtxoVw.RequestID,
|
||||||
&i.PaymentVtxoVw.RedeemTx,
|
&i.RequestVtxoVw.RedeemTx,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -515,24 +515,24 @@ func (q *Queries) SelectRoundWithRoundTxId(ctx context.Context, txid string) ([]
|
|||||||
|
|
||||||
const selectSweepableRounds = `-- name: SelectSweepableRounds :many
|
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,
|
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,
|
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,
|
request_receiver_vw.request_id, request_receiver_vw.pubkey, request_receiver_vw.onchain_address, request_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_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
|
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 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 request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id
|
||||||
LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_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
|
WHERE round.swept = false AND round.ended = true AND round.failed = false
|
||||||
`
|
`
|
||||||
|
|
||||||
type SelectSweepableRoundsRow struct {
|
type SelectSweepableRoundsRow struct {
|
||||||
Round Round
|
Round Round
|
||||||
RoundPaymentVw RoundPaymentVw
|
RoundRequestVw RoundRequestVw
|
||||||
RoundTxVw RoundTxVw
|
RoundTxVw RoundTxVw
|
||||||
PaymentReceiverVw PaymentReceiverVw
|
RequestReceiverVw RequestReceiverVw
|
||||||
PaymentVtxoVw PaymentVtxoVw
|
RequestVtxoVw RequestVtxoVw
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) SelectSweepableRounds(ctx context.Context) ([]SelectSweepableRoundsRow, error) {
|
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.DustAmount,
|
||||||
&i.Round.Version,
|
&i.Round.Version,
|
||||||
&i.Round.Swept,
|
&i.Round.Swept,
|
||||||
&i.RoundPaymentVw.ID,
|
&i.RoundRequestVw.ID,
|
||||||
&i.RoundPaymentVw.RoundID,
|
&i.RoundRequestVw.RoundID,
|
||||||
&i.RoundTxVw.ID,
|
&i.RoundTxVw.ID,
|
||||||
&i.RoundTxVw.Tx,
|
&i.RoundTxVw.Tx,
|
||||||
&i.RoundTxVw.RoundID,
|
&i.RoundTxVw.RoundID,
|
||||||
@@ -568,23 +568,23 @@ func (q *Queries) SelectSweepableRounds(ctx context.Context) ([]SelectSweepableR
|
|||||||
&i.RoundTxVw.TreeLevel,
|
&i.RoundTxVw.TreeLevel,
|
||||||
&i.RoundTxVw.ParentTxid,
|
&i.RoundTxVw.ParentTxid,
|
||||||
&i.RoundTxVw.IsLeaf,
|
&i.RoundTxVw.IsLeaf,
|
||||||
&i.PaymentReceiverVw.PaymentID,
|
&i.RequestReceiverVw.RequestID,
|
||||||
&i.PaymentReceiverVw.Pubkey,
|
&i.RequestReceiverVw.Pubkey,
|
||||||
&i.PaymentReceiverVw.OnchainAddress,
|
&i.RequestReceiverVw.OnchainAddress,
|
||||||
&i.PaymentReceiverVw.Amount,
|
&i.RequestReceiverVw.Amount,
|
||||||
&i.PaymentVtxoVw.Txid,
|
&i.RequestVtxoVw.Txid,
|
||||||
&i.PaymentVtxoVw.Vout,
|
&i.RequestVtxoVw.Vout,
|
||||||
&i.PaymentVtxoVw.Pubkey,
|
&i.RequestVtxoVw.Pubkey,
|
||||||
&i.PaymentVtxoVw.Amount,
|
&i.RequestVtxoVw.Amount,
|
||||||
&i.PaymentVtxoVw.PoolTx,
|
&i.RequestVtxoVw.RoundTx,
|
||||||
&i.PaymentVtxoVw.SpentBy,
|
&i.RequestVtxoVw.SpentBy,
|
||||||
&i.PaymentVtxoVw.Spent,
|
&i.RequestVtxoVw.Spent,
|
||||||
&i.PaymentVtxoVw.Redeemed,
|
&i.RequestVtxoVw.Redeemed,
|
||||||
&i.PaymentVtxoVw.Swept,
|
&i.RequestVtxoVw.Swept,
|
||||||
&i.PaymentVtxoVw.ExpireAt,
|
&i.RequestVtxoVw.ExpireAt,
|
||||||
&i.PaymentVtxoVw.CreatedAt,
|
&i.RequestVtxoVw.CreatedAt,
|
||||||
&i.PaymentVtxoVw.PaymentID,
|
&i.RequestVtxoVw.RequestID,
|
||||||
&i.PaymentVtxoVw.RedeemTx,
|
&i.RequestVtxoVw.RedeemTx,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -600,7 +600,7 @@ func (q *Queries) SelectSweepableRounds(ctx context.Context) ([]SelectSweepableR
|
|||||||
}
|
}
|
||||||
|
|
||||||
const selectSweepableVtxos = `-- name: SelectSweepableVtxos :many
|
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
|
WHERE redeemed = false AND swept = false
|
||||||
`
|
`
|
||||||
|
|
||||||
@@ -622,14 +622,14 @@ func (q *Queries) SelectSweepableVtxos(ctx context.Context) ([]SelectSweepableVt
|
|||||||
&i.Vtxo.Vout,
|
&i.Vtxo.Vout,
|
||||||
&i.Vtxo.Pubkey,
|
&i.Vtxo.Pubkey,
|
||||||
&i.Vtxo.Amount,
|
&i.Vtxo.Amount,
|
||||||
&i.Vtxo.PoolTx,
|
&i.Vtxo.RoundTx,
|
||||||
&i.Vtxo.SpentBy,
|
&i.Vtxo.SpentBy,
|
||||||
&i.Vtxo.Spent,
|
&i.Vtxo.Spent,
|
||||||
&i.Vtxo.Redeemed,
|
&i.Vtxo.Redeemed,
|
||||||
&i.Vtxo.Swept,
|
&i.Vtxo.Swept,
|
||||||
&i.Vtxo.ExpireAt,
|
&i.Vtxo.ExpireAt,
|
||||||
&i.Vtxo.CreatedAt,
|
&i.Vtxo.CreatedAt,
|
||||||
&i.Vtxo.PaymentID,
|
&i.Vtxo.RequestID,
|
||||||
&i.Vtxo.RedeemTx,
|
&i.Vtxo.RedeemTx,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -647,24 +647,24 @@ func (q *Queries) SelectSweepableVtxos(ctx context.Context) ([]SelectSweepableVt
|
|||||||
|
|
||||||
const selectSweptRounds = `-- name: SelectSweptRounds :many
|
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,
|
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,
|
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,
|
request_receiver_vw.request_id, request_receiver_vw.pubkey, request_receiver_vw.onchain_address, request_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_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
|
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 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 request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id
|
||||||
LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_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 <> ''
|
WHERE round.swept = true AND round.failed = false AND round.ended = true AND round.connector_address <> ''
|
||||||
`
|
`
|
||||||
|
|
||||||
type SelectSweptRoundsRow struct {
|
type SelectSweptRoundsRow struct {
|
||||||
Round Round
|
Round Round
|
||||||
RoundPaymentVw RoundPaymentVw
|
RoundRequestVw RoundRequestVw
|
||||||
RoundTxVw RoundTxVw
|
RoundTxVw RoundTxVw
|
||||||
PaymentReceiverVw PaymentReceiverVw
|
RequestReceiverVw RequestReceiverVw
|
||||||
PaymentVtxoVw PaymentVtxoVw
|
RequestVtxoVw RequestVtxoVw
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) SelectSweptRounds(ctx context.Context) ([]SelectSweptRoundsRow, error) {
|
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.DustAmount,
|
||||||
&i.Round.Version,
|
&i.Round.Version,
|
||||||
&i.Round.Swept,
|
&i.Round.Swept,
|
||||||
&i.RoundPaymentVw.ID,
|
&i.RoundRequestVw.ID,
|
||||||
&i.RoundPaymentVw.RoundID,
|
&i.RoundRequestVw.RoundID,
|
||||||
&i.RoundTxVw.ID,
|
&i.RoundTxVw.ID,
|
||||||
&i.RoundTxVw.Tx,
|
&i.RoundTxVw.Tx,
|
||||||
&i.RoundTxVw.RoundID,
|
&i.RoundTxVw.RoundID,
|
||||||
@@ -700,23 +700,23 @@ func (q *Queries) SelectSweptRounds(ctx context.Context) ([]SelectSweptRoundsRow
|
|||||||
&i.RoundTxVw.TreeLevel,
|
&i.RoundTxVw.TreeLevel,
|
||||||
&i.RoundTxVw.ParentTxid,
|
&i.RoundTxVw.ParentTxid,
|
||||||
&i.RoundTxVw.IsLeaf,
|
&i.RoundTxVw.IsLeaf,
|
||||||
&i.PaymentReceiverVw.PaymentID,
|
&i.RequestReceiverVw.RequestID,
|
||||||
&i.PaymentReceiverVw.Pubkey,
|
&i.RequestReceiverVw.Pubkey,
|
||||||
&i.PaymentReceiverVw.OnchainAddress,
|
&i.RequestReceiverVw.OnchainAddress,
|
||||||
&i.PaymentReceiverVw.Amount,
|
&i.RequestReceiverVw.Amount,
|
||||||
&i.PaymentVtxoVw.Txid,
|
&i.RequestVtxoVw.Txid,
|
||||||
&i.PaymentVtxoVw.Vout,
|
&i.RequestVtxoVw.Vout,
|
||||||
&i.PaymentVtxoVw.Pubkey,
|
&i.RequestVtxoVw.Pubkey,
|
||||||
&i.PaymentVtxoVw.Amount,
|
&i.RequestVtxoVw.Amount,
|
||||||
&i.PaymentVtxoVw.PoolTx,
|
&i.RequestVtxoVw.RoundTx,
|
||||||
&i.PaymentVtxoVw.SpentBy,
|
&i.RequestVtxoVw.SpentBy,
|
||||||
&i.PaymentVtxoVw.Spent,
|
&i.RequestVtxoVw.Spent,
|
||||||
&i.PaymentVtxoVw.Redeemed,
|
&i.RequestVtxoVw.Redeemed,
|
||||||
&i.PaymentVtxoVw.Swept,
|
&i.RequestVtxoVw.Swept,
|
||||||
&i.PaymentVtxoVw.ExpireAt,
|
&i.RequestVtxoVw.ExpireAt,
|
||||||
&i.PaymentVtxoVw.CreatedAt,
|
&i.RequestVtxoVw.CreatedAt,
|
||||||
&i.PaymentVtxoVw.PaymentID,
|
&i.RequestVtxoVw.RequestID,
|
||||||
&i.PaymentVtxoVw.RedeemTx,
|
&i.RequestVtxoVw.RedeemTx,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -732,7 +732,7 @@ func (q *Queries) SelectSweptRounds(ctx context.Context) ([]SelectSweptRoundsRow
|
|||||||
}
|
}
|
||||||
|
|
||||||
const selectVtxoByOutpoint = `-- name: SelectVtxoByOutpoint :one
|
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 = ?
|
WHERE txid = ? AND vout = ?
|
||||||
`
|
`
|
||||||
|
|
||||||
@@ -753,50 +753,50 @@ func (q *Queries) SelectVtxoByOutpoint(ctx context.Context, arg SelectVtxoByOutp
|
|||||||
&i.Vtxo.Vout,
|
&i.Vtxo.Vout,
|
||||||
&i.Vtxo.Pubkey,
|
&i.Vtxo.Pubkey,
|
||||||
&i.Vtxo.Amount,
|
&i.Vtxo.Amount,
|
||||||
&i.Vtxo.PoolTx,
|
&i.Vtxo.RoundTx,
|
||||||
&i.Vtxo.SpentBy,
|
&i.Vtxo.SpentBy,
|
||||||
&i.Vtxo.Spent,
|
&i.Vtxo.Spent,
|
||||||
&i.Vtxo.Redeemed,
|
&i.Vtxo.Redeemed,
|
||||||
&i.Vtxo.Swept,
|
&i.Vtxo.Swept,
|
||||||
&i.Vtxo.ExpireAt,
|
&i.Vtxo.ExpireAt,
|
||||||
&i.Vtxo.CreatedAt,
|
&i.Vtxo.CreatedAt,
|
||||||
&i.Vtxo.PaymentID,
|
&i.Vtxo.RequestID,
|
||||||
&i.Vtxo.RedeemTx,
|
&i.Vtxo.RedeemTx,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectVtxosByPoolTxid = `-- name: SelectVtxosByPoolTxid :many
|
const selectVtxosByRoundTxid = `-- name: SelectVtxosByRoundTxid :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 pool_tx = ?
|
WHERE round_tx = ?
|
||||||
`
|
`
|
||||||
|
|
||||||
type SelectVtxosByPoolTxidRow struct {
|
type SelectVtxosByRoundTxidRow struct {
|
||||||
Vtxo Vtxo
|
Vtxo Vtxo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) SelectVtxosByPoolTxid(ctx context.Context, poolTx string) ([]SelectVtxosByPoolTxidRow, error) {
|
func (q *Queries) SelectVtxosByRoundTxid(ctx context.Context, roundTx string) ([]SelectVtxosByRoundTxidRow, error) {
|
||||||
rows, err := q.db.QueryContext(ctx, selectVtxosByPoolTxid, poolTx)
|
rows, err := q.db.QueryContext(ctx, selectVtxosByRoundTxid, roundTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []SelectVtxosByPoolTxidRow
|
var items []SelectVtxosByRoundTxidRow
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i SelectVtxosByPoolTxidRow
|
var i SelectVtxosByRoundTxidRow
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&i.Vtxo.Txid,
|
&i.Vtxo.Txid,
|
||||||
&i.Vtxo.Vout,
|
&i.Vtxo.Vout,
|
||||||
&i.Vtxo.Pubkey,
|
&i.Vtxo.Pubkey,
|
||||||
&i.Vtxo.Amount,
|
&i.Vtxo.Amount,
|
||||||
&i.Vtxo.PoolTx,
|
&i.Vtxo.RoundTx,
|
||||||
&i.Vtxo.SpentBy,
|
&i.Vtxo.SpentBy,
|
||||||
&i.Vtxo.Spent,
|
&i.Vtxo.Spent,
|
||||||
&i.Vtxo.Redeemed,
|
&i.Vtxo.Redeemed,
|
||||||
&i.Vtxo.Swept,
|
&i.Vtxo.Swept,
|
||||||
&i.Vtxo.ExpireAt,
|
&i.Vtxo.ExpireAt,
|
||||||
&i.Vtxo.CreatedAt,
|
&i.Vtxo.CreatedAt,
|
||||||
&i.Vtxo.PaymentID,
|
&i.Vtxo.RequestID,
|
||||||
&i.Vtxo.RedeemTx,
|
&i.Vtxo.RedeemTx,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -868,18 +868,18 @@ func (q *Queries) UpdateVtxoExpireAt(ctx context.Context, arg UpdateVtxoExpireAt
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateVtxoPaymentId = `-- name: UpdateVtxoPaymentId :exec
|
const updateVtxoRequestId = `-- name: UpdateVtxoRequestId :exec
|
||||||
UPDATE vtxo SET payment_id = ? WHERE txid = ? AND vout = ?
|
UPDATE vtxo SET request_id = ? WHERE txid = ? AND vout = ?
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateVtxoPaymentIdParams struct {
|
type UpdateVtxoRequestIdParams struct {
|
||||||
PaymentID sql.NullString
|
RequestID sql.NullString
|
||||||
Txid string
|
Txid string
|
||||||
Vout int64
|
Vout int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateVtxoPaymentId(ctx context.Context, arg UpdateVtxoPaymentIdParams) error {
|
func (q *Queries) UpdateVtxoRequestId(ctx context.Context, arg UpdateVtxoRequestIdParams) error {
|
||||||
_, err := q.db.ExecContext(ctx, updateVtxoPaymentId, arg.PaymentID, arg.Txid, arg.Vout)
|
_, err := q.db.ExecContext(ctx, updateVtxoRequestId, arg.RequestID, arg.Txid, arg.Vout)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -916,31 +916,16 @@ func (q *Queries) UpsertEntityVtxo(ctx context.Context, arg UpsertEntityVtxoPara
|
|||||||
return err
|
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
|
const upsertReceiver = `-- name: UpsertReceiver :exec
|
||||||
INSERT INTO receiver (payment_id, pubkey, onchain_address, amount) VALUES (?, ?, ?, ?)
|
INSERT INTO receiver (request_id, pubkey, onchain_address, amount) VALUES (?, ?, ?, ?)
|
||||||
ON CONFLICT(payment_id, pubkey, onchain_address) DO UPDATE SET
|
ON CONFLICT(request_id, pubkey, onchain_address) DO UPDATE SET
|
||||||
amount = EXCLUDED.amount,
|
amount = EXCLUDED.amount,
|
||||||
pubkey = EXCLUDED.pubkey,
|
pubkey = EXCLUDED.pubkey,
|
||||||
onchain_address = EXCLUDED.onchain_address
|
onchain_address = EXCLUDED.onchain_address
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpsertReceiverParams struct {
|
type UpsertReceiverParams struct {
|
||||||
PaymentID string
|
RequestID string
|
||||||
Pubkey sql.NullString
|
Pubkey sql.NullString
|
||||||
OnchainAddress sql.NullString
|
OnchainAddress sql.NullString
|
||||||
Amount int64
|
Amount int64
|
||||||
@@ -948,7 +933,7 @@ type UpsertReceiverParams struct {
|
|||||||
|
|
||||||
func (q *Queries) UpsertReceiver(ctx context.Context, arg UpsertReceiverParams) error {
|
func (q *Queries) UpsertReceiver(ctx context.Context, arg UpsertReceiverParams) error {
|
||||||
_, err := q.db.ExecContext(ctx, upsertReceiver,
|
_, err := q.db.ExecContext(ctx, upsertReceiver,
|
||||||
arg.PaymentID,
|
arg.RequestID,
|
||||||
arg.Pubkey,
|
arg.Pubkey,
|
||||||
arg.OnchainAddress,
|
arg.OnchainAddress,
|
||||||
arg.Amount,
|
arg.Amount,
|
||||||
@@ -1057,12 +1042,27 @@ func (q *Queries) UpsertTransaction(ctx context.Context, arg UpsertTransactionPa
|
|||||||
return err
|
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
|
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
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET
|
||||||
pubkey = EXCLUDED.pubkey,
|
pubkey = EXCLUDED.pubkey,
|
||||||
amount = EXCLUDED.amount,
|
amount = EXCLUDED.amount,
|
||||||
pool_tx = EXCLUDED.pool_tx,
|
round_tx = EXCLUDED.round_tx,
|
||||||
spent_by = EXCLUDED.spent_by,
|
spent_by = EXCLUDED.spent_by,
|
||||||
spent = EXCLUDED.spent,
|
spent = EXCLUDED.spent,
|
||||||
redeemed = EXCLUDED.redeemed,
|
redeemed = EXCLUDED.redeemed,
|
||||||
@@ -1077,7 +1077,7 @@ type UpsertVtxoParams struct {
|
|||||||
Vout int64
|
Vout int64
|
||||||
Pubkey string
|
Pubkey string
|
||||||
Amount int64
|
Amount int64
|
||||||
PoolTx string
|
RoundTx string
|
||||||
SpentBy string
|
SpentBy string
|
||||||
Spent bool
|
Spent bool
|
||||||
Redeemed bool
|
Redeemed bool
|
||||||
@@ -1093,7 +1093,7 @@ func (q *Queries) UpsertVtxo(ctx context.Context, arg UpsertVtxoParams) error {
|
|||||||
arg.Vout,
|
arg.Vout,
|
||||||
arg.Pubkey,
|
arg.Pubkey,
|
||||||
arg.Amount,
|
arg.Amount,
|
||||||
arg.PoolTx,
|
arg.RoundTx,
|
||||||
arg.SpentBy,
|
arg.SpentBy,
|
||||||
arg.Spent,
|
arg.Spent,
|
||||||
arg.Redeemed,
|
arg.Redeemed,
|
||||||
|
|||||||
@@ -39,70 +39,70 @@ ON CONFLICT(id) DO UPDATE SET
|
|||||||
version = EXCLUDED.version,
|
version = EXCLUDED.version,
|
||||||
swept = EXCLUDED.swept;
|
swept = EXCLUDED.swept;
|
||||||
|
|
||||||
-- name: UpsertPayment :exec
|
-- name: UpsertTxRequest :exec
|
||||||
INSERT INTO payment (id, round_id) VALUES (?, ?)
|
INSERT INTO tx_request (id, round_id) VALUES (?, ?)
|
||||||
ON CONFLICT(id) DO UPDATE SET round_id = EXCLUDED.round_id;
|
ON CONFLICT(id) DO UPDATE SET round_id = EXCLUDED.round_id;
|
||||||
|
|
||||||
-- name: UpsertReceiver :exec
|
-- name: UpsertReceiver :exec
|
||||||
INSERT INTO receiver (payment_id, pubkey, onchain_address, amount) VALUES (?, ?, ?, ?)
|
INSERT INTO receiver (request_id, pubkey, onchain_address, amount) VALUES (?, ?, ?, ?)
|
||||||
ON CONFLICT(payment_id, pubkey, onchain_address) DO UPDATE SET
|
ON CONFLICT(request_id, pubkey, onchain_address) DO UPDATE SET
|
||||||
amount = EXCLUDED.amount,
|
amount = EXCLUDED.amount,
|
||||||
pubkey = EXCLUDED.pubkey,
|
pubkey = EXCLUDED.pubkey,
|
||||||
onchain_address = EXCLUDED.onchain_address;
|
onchain_address = EXCLUDED.onchain_address;
|
||||||
|
|
||||||
-- name: UpdateVtxoPaymentId :exec
|
-- name: UpdateVtxoRequestId :exec
|
||||||
UPDATE vtxo SET payment_id = ? WHERE txid = ? AND vout = ?;
|
UPDATE vtxo SET request_id = ? WHERE txid = ? AND vout = ?;
|
||||||
|
|
||||||
-- name: SelectRoundWithRoundId :many
|
-- name: SelectRoundWithRoundId :many
|
||||||
SELECT sqlc.embed(round),
|
SELECT sqlc.embed(round),
|
||||||
sqlc.embed(round_payment_vw),
|
sqlc.embed(round_request_vw),
|
||||||
sqlc.embed(round_tx_vw),
|
sqlc.embed(round_tx_vw),
|
||||||
sqlc.embed(payment_receiver_vw),
|
sqlc.embed(request_receiver_vw),
|
||||||
sqlc.embed(payment_vtxo_vw)
|
sqlc.embed(request_vtxo_vw)
|
||||||
FROM round
|
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 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 request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id
|
||||||
LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id
|
LEFT OUTER JOIN request_vtxo_vw ON round_request_vw.id=request_vtxo_vw.request_id
|
||||||
WHERE round.id = ?;
|
WHERE round.id = ?;
|
||||||
|
|
||||||
-- name: SelectRoundWithRoundTxId :many
|
-- name: SelectRoundWithRoundTxId :many
|
||||||
SELECT sqlc.embed(round),
|
SELECT sqlc.embed(round),
|
||||||
sqlc.embed(round_payment_vw),
|
sqlc.embed(round_request_vw),
|
||||||
sqlc.embed(round_tx_vw),
|
sqlc.embed(round_tx_vw),
|
||||||
sqlc.embed(payment_receiver_vw),
|
sqlc.embed(request_receiver_vw),
|
||||||
sqlc.embed(payment_vtxo_vw)
|
sqlc.embed(request_vtxo_vw)
|
||||||
FROM round
|
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 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 request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id
|
||||||
LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id
|
LEFT OUTER JOIN request_vtxo_vw ON round_request_vw.id=request_vtxo_vw.request_id
|
||||||
WHERE round.txid = ?;
|
WHERE round.txid = ?;
|
||||||
|
|
||||||
-- name: SelectSweepableRounds :many
|
-- name: SelectSweepableRounds :many
|
||||||
SELECT sqlc.embed(round),
|
SELECT sqlc.embed(round),
|
||||||
sqlc.embed(round_payment_vw),
|
sqlc.embed(round_request_vw),
|
||||||
sqlc.embed(round_tx_vw),
|
sqlc.embed(round_tx_vw),
|
||||||
sqlc.embed(payment_receiver_vw),
|
sqlc.embed(request_receiver_vw),
|
||||||
sqlc.embed(payment_vtxo_vw)
|
sqlc.embed(request_vtxo_vw)
|
||||||
FROM round
|
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 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 request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id
|
||||||
LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_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;
|
WHERE round.swept = false AND round.ended = true AND round.failed = false;
|
||||||
|
|
||||||
-- name: SelectSweptRounds :many
|
-- name: SelectSweptRounds :many
|
||||||
SELECT sqlc.embed(round),
|
SELECT sqlc.embed(round),
|
||||||
sqlc.embed(round_payment_vw),
|
sqlc.embed(round_request_vw),
|
||||||
sqlc.embed(round_tx_vw),
|
sqlc.embed(round_tx_vw),
|
||||||
sqlc.embed(payment_receiver_vw),
|
sqlc.embed(request_receiver_vw),
|
||||||
sqlc.embed(payment_vtxo_vw)
|
sqlc.embed(request_vtxo_vw)
|
||||||
FROM round
|
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 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 request_receiver_vw ON round_request_vw.id=request_receiver_vw.request_id
|
||||||
LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_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 <> '';
|
WHERE round.swept = true AND round.failed = false AND round.ended = true AND round.connector_address <> '';
|
||||||
|
|
||||||
-- name: SelectRoundIdsInRange :many
|
-- name: SelectRoundIdsInRange :many
|
||||||
@@ -112,11 +112,11 @@ SELECT id FROM round WHERE starting_timestamp > ? AND starting_timestamp < ?;
|
|||||||
SELECT id FROM round;
|
SELECT id FROM round;
|
||||||
|
|
||||||
-- name: UpsertVtxo :exec
|
-- 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
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET
|
||||||
pubkey = EXCLUDED.pubkey,
|
pubkey = EXCLUDED.pubkey,
|
||||||
amount = EXCLUDED.amount,
|
amount = EXCLUDED.amount,
|
||||||
pool_tx = EXCLUDED.pool_tx,
|
round_tx = EXCLUDED.round_tx,
|
||||||
spent_by = EXCLUDED.spent_by,
|
spent_by = EXCLUDED.spent_by,
|
||||||
spent = EXCLUDED.spent,
|
spent = EXCLUDED.spent,
|
||||||
redeemed = EXCLUDED.redeemed,
|
redeemed = EXCLUDED.redeemed,
|
||||||
@@ -141,9 +141,9 @@ WHERE redeemed = false AND pubkey = ?;
|
|||||||
SELECT sqlc.embed(vtxo) FROM vtxo
|
SELECT sqlc.embed(vtxo) FROM vtxo
|
||||||
WHERE txid = ? AND vout = ?;
|
WHERE txid = ? AND vout = ?;
|
||||||
|
|
||||||
-- name: SelectVtxosByPoolTxid :many
|
-- name: SelectVtxosByRoundTxid :many
|
||||||
SELECT sqlc.embed(vtxo) FROM vtxo
|
SELECT sqlc.embed(vtxo) FROM vtxo
|
||||||
WHERE pool_tx = ?;
|
WHERE round_tx = ?;
|
||||||
|
|
||||||
-- name: MarkVtxoAsRedeemed :exec
|
-- name: MarkVtxoAsRedeemed :exec
|
||||||
UPDATE vtxo SET redeemed = true WHERE txid = ? AND vout = ?;
|
UPDATE vtxo SET redeemed = true WHERE txid = ? AND vout = ?;
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ func (v *vxtoRepository) AddVtxos(ctx context.Context, vtxos []domain.Vtxo) erro
|
|||||||
ctx, queries.UpsertVtxoParams{
|
ctx, queries.UpsertVtxoParams{
|
||||||
Txid: vtxo.Txid,
|
Txid: vtxo.Txid,
|
||||||
Vout: int64(vtxo.VOut),
|
Vout: int64(vtxo.VOut),
|
||||||
Pubkey: vtxo.Pubkey,
|
Pubkey: vtxo.PubKey,
|
||||||
Amount: int64(vtxo.Amount),
|
Amount: int64(vtxo.Amount),
|
||||||
PoolTx: vtxo.RoundTxid,
|
RoundTx: vtxo.RoundTxid,
|
||||||
SpentBy: vtxo.SpentBy,
|
SpentBy: vtxo.SpentBy,
|
||||||
Spent: vtxo.Spent,
|
Spent: vtxo.Spent,
|
||||||
Redeemed: vtxo.Redeemed,
|
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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -251,8 +251,8 @@ func rowToVtxo(row queries.Vtxo) domain.Vtxo {
|
|||||||
VOut: uint32(row.Vout),
|
VOut: uint32(row.Vout),
|
||||||
},
|
},
|
||||||
Amount: uint64(row.Amount),
|
Amount: uint64(row.Amount),
|
||||||
Pubkey: row.Pubkey,
|
PubKey: row.Pubkey,
|
||||||
RoundTxid: row.PoolTx,
|
RoundTxid: row.RoundTx,
|
||||||
SpentBy: row.SpentBy,
|
SpentBy: row.SpentBy,
|
||||||
Spent: row.Spent,
|
Spent: row.Spent,
|
||||||
Redeemed: row.Redeemed,
|
Redeemed: row.Redeemed,
|
||||||
|
|||||||
@@ -315,41 +315,41 @@ func (b *txBuilder) VerifyForfeitTxs(vtxos []domain.Vtxo, connectors []string, f
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *txBuilder) BuildRoundTx(
|
func (b *txBuilder) BuildRoundTx(
|
||||||
aspPubkey *secp256k1.PublicKey,
|
serverPubkey *secp256k1.PublicKey,
|
||||||
payments []domain.Payment,
|
requests []domain.TxRequest,
|
||||||
boardingInputs []ports.BoardingInput,
|
boardingInputs []ports.BoardingInput,
|
||||||
sweptRounds []domain.Round,
|
sweptRounds []domain.Round,
|
||||||
_ ...*secp256k1.PublicKey, // cosigners are not used in the covenant
|
_ ...*secp256k1.PublicKey, // cosigners are not used in the covenant
|
||||||
) (roundTx string, congestionTree tree.CongestionTree, connectorAddress string, connectors []string, err error) {
|
) (roundTx string, vtxoTree tree.VtxoTree, connectorAddress string, connectors []string, err error) {
|
||||||
// The creation of the tree and the pool tx are tightly coupled:
|
// The creation of the tree and the round tx are tightly coupled:
|
||||||
// - building the tree requires knowing the shared outpoint (txid:vout)
|
// - 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
|
// 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.
|
// of the vtxo tree to calculate the shared output script and amount.
|
||||||
// With these data the pool tx can be created, and once the shared utxo
|
// With these data the round tx can be created, and once the shared utxo
|
||||||
// outpoint is obtained, the congestion tree can be finally created.
|
// outpoint is obtained, the vtxo tree can be finally created.
|
||||||
// The factory function `treeFactoryFn` returned below holds all outputs data
|
// The factory function `treeFactoryFn` returned below holds all outputs data
|
||||||
// generated in the process and takes the shared utxo outpoint as argument.
|
// generated in the process and takes the shared utxo outpoint as argument.
|
||||||
// This is safe as the memory allocated for `craftCongestionTree` is freed
|
// This is safe as the memory allocated for `BuildVtxoTree` is flushed
|
||||||
// only after `BuildPoolTx` returns.
|
// only after `BuildRoundTx` returns.
|
||||||
|
|
||||||
var sharedOutputScript []byte
|
var sharedOutputScript []byte
|
||||||
var sharedOutputAmount uint64
|
var sharedOutputAmount uint64
|
||||||
var treeFactoryFn tree.TreeFactory
|
var treeFactoryFn tree.TreeFactory
|
||||||
|
|
||||||
if !isOnchainOnly(payments) {
|
if !isOnchainOnly(requests) {
|
||||||
feeSatsPerNode, err := b.wallet.MinRelayFee(context.Background(), uint64(common.CovenantTreeTxSize))
|
feeSatsPerNode, err := b.wallet.MinRelayFee(context.Background(), uint64(common.CovenantTreeTxSize))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, "", nil, err
|
return "", nil, "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
vtxosLeaves, err := getOutputVtxosLeaves(payments)
|
vtxosLeaves, err := getOutputVtxosLeaves(requests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, "", nil, err
|
return "", nil, "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
treeFactoryFn, sharedOutputScript, sharedOutputAmount, err = tree.CraftCongestionTree(
|
treeFactoryFn, sharedOutputScript, sharedOutputAmount, err = tree.BuildVtxoTree(
|
||||||
b.onchainNetwork().AssetID, aspPubkey, vtxosLeaves, feeSatsPerNode, b.roundLifetime,
|
b.onchainNetwork().AssetID, serverPubkey, vtxosLeaves, feeSatsPerNode, b.roundLifetime,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, "", nil, err
|
return "", nil, "", nil, err
|
||||||
@@ -361,8 +361,8 @@ func (b *txBuilder) BuildRoundTx(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ptx, err := b.createPoolTx(
|
ptx, err := b.createRoundTx(
|
||||||
sharedOutputAmount, sharedOutputScript, payments, boardingInputs, aspPubkey, connectorAddress, sweptRounds,
|
sharedOutputAmount, sharedOutputScript, requests, boardingInputs, serverPubkey, connectorAddress, sweptRounds,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -374,7 +374,7 @@ func (b *txBuilder) BuildRoundTx(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if treeFactoryFn != nil {
|
if treeFactoryFn != nil {
|
||||||
congestionTree, err = treeFactoryFn(psetv2.InputArgs{
|
vtxoTree, err = treeFactoryFn(psetv2.InputArgs{
|
||||||
Txid: unsignedTx.TxHash().String(),
|
Txid: unsignedTx.TxHash().String(),
|
||||||
TxIndex: 0,
|
TxIndex: 0,
|
||||||
})
|
})
|
||||||
@@ -388,7 +388,7 @@ func (b *txBuilder) BuildRoundTx(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if countSpentVtxos(payments) <= 0 {
|
if countSpentVtxos(requests) <= 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,7 +402,7 @@ func (b *txBuilder) BuildRoundTx(
|
|||||||
return "", nil, "", nil, err
|
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 {
|
if err != nil {
|
||||||
return "", nil, "", nil, err
|
return "", nil, "", nil, err
|
||||||
}
|
}
|
||||||
@@ -477,7 +477,7 @@ func (b *txBuilder) verifyTapscriptPartialSigs(pset *psetv2.Pset) (bool, error)
|
|||||||
utx, _ := pset.UnsignedTx()
|
utx, _ := pset.UnsignedTx()
|
||||||
txid := utx.TxHash().String()
|
txid := utx.TxHash().String()
|
||||||
|
|
||||||
aspPublicKey, err := b.wallet.GetPubkey(context.Background())
|
serverPubkey, err := b.wallet.GetPubkey(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
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
|
// we don't need to check if server signed
|
||||||
keys[hex.EncodeToString(schnorr.SerializePubKey(aspPublicKey))] = true
|
keys[hex.EncodeToString(schnorr.SerializePubKey(serverPubkey))] = true
|
||||||
|
|
||||||
rootHash := tapLeaf.ControlBlock.RootHash(tapLeaf.Script)
|
rootHash := tapLeaf.ControlBlock.RootHash(tapLeaf.Script)
|
||||||
tapKeyFromControlBlock := taproot.ComputeTaprootOutputKey(tree.UnspendableKey(), rootHash[:])
|
tapKeyFromControlBlock := taproot.ComputeTaprootOutputKey(tree.UnspendableKey(), rootHash[:])
|
||||||
@@ -629,15 +629,15 @@ func (b *txBuilder) FinalizeAndExtract(tx string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *txBuilder) FindLeaves(
|
func (b *txBuilder) FindLeaves(
|
||||||
congestionTree tree.CongestionTree,
|
vtxoTree tree.VtxoTree,
|
||||||
fromtxid string,
|
fromtxid string,
|
||||||
fromvout uint32,
|
fromvout uint32,
|
||||||
) ([]tree.Node, error) {
|
) ([]tree.Node, error) {
|
||||||
allLeaves := congestionTree.Leaves()
|
allLeaves := vtxoTree.Leaves()
|
||||||
foundLeaves := make([]tree.Node, 0)
|
foundLeaves := make([]tree.Node, 0)
|
||||||
|
|
||||||
for _, leaf := range allLeaves {
|
for _, leaf := range allLeaves {
|
||||||
branch, err := congestionTree.Branch(leaf.Txid)
|
branch, err := vtxoTree.Branch(leaf.Txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -669,16 +669,16 @@ func (b *txBuilder) FindLeaves(
|
|||||||
return foundLeaves, nil
|
return foundLeaves, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *txBuilder) createPoolTx(
|
func (b *txBuilder) createRoundTx(
|
||||||
sharedOutputAmount uint64,
|
sharedOutputAmount uint64,
|
||||||
sharedOutputScript []byte,
|
sharedOutputScript []byte,
|
||||||
payments []domain.Payment,
|
requests []domain.TxRequest,
|
||||||
boardingInputs []ports.BoardingInput,
|
boardingInputs []ports.BoardingInput,
|
||||||
aspPubKey *secp256k1.PublicKey,
|
serverPubkey *secp256k1.PublicKey,
|
||||||
connectorAddress string,
|
connectorAddress string,
|
||||||
sweptRounds []domain.Round,
|
sweptRounds []domain.Round,
|
||||||
) (*psetv2.Pset, error) {
|
) (*psetv2.Pset, error) {
|
||||||
aspScript, err := p2wpkhScript(aspPubKey, b.onchainNetwork())
|
serverScript, err := p2wpkhScript(serverPubkey, b.onchainNetwork())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -698,7 +698,7 @@ func (b *txBuilder) createPoolTx(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nbOfInputs := countSpentVtxos(payments)
|
nbOfInputs := countSpentVtxos(requests)
|
||||||
connectorsAmount := (dustAmount + connectorMinRelayFee) * nbOfInputs
|
connectorsAmount := (dustAmount + connectorMinRelayFee) * nbOfInputs
|
||||||
if nbOfInputs > 1 {
|
if nbOfInputs > 1 {
|
||||||
connectorsAmount -= connectorMinRelayFee
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -760,7 +760,7 @@ func (b *txBuilder) createPoolTx(
|
|||||||
outputs = append(outputs, psetv2.OutputArgs{
|
outputs = append(outputs, psetv2.OutputArgs{
|
||||||
Asset: b.onchainNetwork().AssetID,
|
Asset: b.onchainNetwork().AssetID,
|
||||||
Amount: change,
|
Amount: change,
|
||||||
Script: aspScript,
|
Script: serverScript,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -878,7 +878,7 @@ func (b *txBuilder) createPoolTx(
|
|||||||
{
|
{
|
||||||
Asset: b.onchainNetwork().AssetID,
|
Asset: b.onchainNetwork().AssetID,
|
||||||
Amount: change,
|
Amount: change,
|
||||||
Script: aspScript,
|
Script: serverScript,
|
||||||
},
|
},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -904,7 +904,7 @@ func (b *txBuilder) createPoolTx(
|
|||||||
{
|
{
|
||||||
Asset: b.onchainNetwork().AssetID,
|
Asset: b.onchainNetwork().AssetID,
|
||||||
Amount: change,
|
Amount: change,
|
||||||
Script: aspScript,
|
Script: serverScript,
|
||||||
},
|
},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1009,24 +1009,24 @@ func (b *txBuilder) VerifyAndCombinePartialTx(dest string, src string) (string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *txBuilder) createConnectors(
|
func (b *txBuilder) createConnectors(
|
||||||
roundTx string, payments []domain.Payment,
|
roundTx string, requests []domain.TxRequest,
|
||||||
connectorAddress string,
|
connectorAddress string,
|
||||||
connectorAmount, feeAmount uint64,
|
connectorAmount, feeAmount uint64,
|
||||||
) ([]*psetv2.Pset, error) {
|
) ([]*psetv2.Pset, error) {
|
||||||
txid, _ := getTxid(roundTx)
|
txid, _ := getTxid(roundTx)
|
||||||
|
|
||||||
aspScript, err := address.ToOutputScript(connectorAddress)
|
serverScript, err := address.ToOutputScript(connectorAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
connectorOutput := psetv2.OutputArgs{
|
connectorOutput := psetv2.OutputArgs{
|
||||||
Asset: b.onchainNetwork().AssetID,
|
Asset: b.onchainNetwork().AssetID,
|
||||||
Script: aspScript,
|
Script: serverScript,
|
||||||
Amount: connectorAmount,
|
Amount: connectorAmount,
|
||||||
}
|
}
|
||||||
|
|
||||||
numberOfConnectors := countSpentVtxos(payments)
|
numberOfConnectors := countSpentVtxos(requests)
|
||||||
|
|
||||||
previousInput := psetv2.InputArgs{
|
previousInput := psetv2.InputArgs{
|
||||||
Txid: txid,
|
Txid: txid,
|
||||||
@@ -1035,7 +1035,7 @@ func (b *txBuilder) createConnectors(
|
|||||||
|
|
||||||
if numberOfConnectors == 1 {
|
if numberOfConnectors == 1 {
|
||||||
outputs := []psetv2.OutputArgs{connectorOutput}
|
outputs := []psetv2.OutputArgs{connectorOutput}
|
||||||
connectorTx, err := craftConnectorTx(previousInput, aspScript, outputs, feeAmount)
|
connectorTx, err := craftConnectorTx(previousInput, serverScript, outputs, feeAmount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1056,11 +1056,11 @@ func (b *txBuilder) createConnectors(
|
|||||||
if totalConnectorAmount > 0 {
|
if totalConnectorAmount > 0 {
|
||||||
outputs = append(outputs, psetv2.OutputArgs{
|
outputs = append(outputs, psetv2.OutputArgs{
|
||||||
Asset: b.onchainNetwork().AssetID,
|
Asset: b.onchainNetwork().AssetID,
|
||||||
Script: aspScript,
|
Script: serverScript,
|
||||||
Amount: totalConnectorAmount,
|
Amount: totalConnectorAmount,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
connectorTx, err := craftConnectorTx(previousInput, aspScript, outputs, feeAmount)
|
connectorTx, err := craftConnectorTx(previousInput, serverScript, outputs, feeAmount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,30 +53,30 @@ func TestMain(m *testing.M) {
|
|||||||
os.Exit(m.Run())
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuildPoolTx(t *testing.T) {
|
func TestBuildRoundTx(t *testing.T) {
|
||||||
builder := txbuilder.NewTxBuilder(
|
builder := txbuilder.NewTxBuilder(
|
||||||
wallet, common.Liquid, roundLifetime, boardingExitDelay,
|
wallet, common.Liquid, roundLifetime, boardingExitDelay,
|
||||||
)
|
)
|
||||||
|
|
||||||
fixtures, err := parsePoolTxFixtures()
|
fixtures, err := parseRoundTxFixtures()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, fixtures)
|
require.NotEmpty(t, fixtures)
|
||||||
|
|
||||||
if len(fixtures.Valid) > 0 {
|
if len(fixtures.Valid) > 0 {
|
||||||
t.Run("valid", func(t *testing.T) {
|
t.Run("valid", func(t *testing.T) {
|
||||||
for _, f := range fixtures.Valid {
|
for _, f := range fixtures.Valid {
|
||||||
poolTx, congestionTree, connAddr, _, err := builder.BuildRoundTx(
|
roundTx, vtxoTree, connAddr, _, err := builder.BuildRoundTx(
|
||||||
pubkey, f.Payments, []ports.BoardingInput{}, []domain.Round{},
|
pubkey, f.Requests, []ports.BoardingInput{}, []domain.Round{},
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, poolTx)
|
require.NotEmpty(t, roundTx)
|
||||||
require.NotEmpty(t, congestionTree)
|
require.NotEmpty(t, vtxoTree)
|
||||||
require.Equal(t, connectorAddress, connAddr)
|
require.Equal(t, connectorAddress, connAddr)
|
||||||
require.Equal(t, f.ExpectedNumOfNodes, congestionTree.NumberOfNodes())
|
require.Equal(t, f.ExpectedNumOfNodes, vtxoTree.NumberOfNodes())
|
||||||
require.Len(t, congestionTree.Leaves(), f.ExpectedNumOfLeaves)
|
require.Len(t, vtxoTree.Leaves(), f.ExpectedNumOfLeaves)
|
||||||
|
|
||||||
err = tree.ValidateCongestionTree(
|
err = tree.ValidateVtxoTree(
|
||||||
congestionTree, poolTx, pubkey, roundLifetime,
|
vtxoTree, roundTx, pubkey, roundLifetime,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
@@ -86,13 +86,13 @@ func TestBuildPoolTx(t *testing.T) {
|
|||||||
if len(fixtures.Invalid) > 0 {
|
if len(fixtures.Invalid) > 0 {
|
||||||
t.Run("invalid", func(t *testing.T) {
|
t.Run("invalid", func(t *testing.T) {
|
||||||
for _, f := range fixtures.Invalid {
|
for _, f := range fixtures.Invalid {
|
||||||
poolTx, congestionTree, connAddr, _, err := builder.BuildRoundTx(
|
roundTx, vtxoTree, connAddr, _, err := builder.BuildRoundTx(
|
||||||
pubkey, f.Payments, []ports.BoardingInput{}, []domain.Round{},
|
pubkey, f.Requests, []ports.BoardingInput{}, []domain.Round{},
|
||||||
)
|
)
|
||||||
require.EqualError(t, err, f.ExpectedErr)
|
require.EqualError(t, err, f.ExpectedErr)
|
||||||
require.Empty(t, poolTx)
|
require.Empty(t, roundTx)
|
||||||
require.Empty(t, connAddr)
|
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)
|
return hex.EncodeToString(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
type poolTxFixtures struct {
|
type roundTxFixtures struct {
|
||||||
Valid []struct {
|
Valid []struct {
|
||||||
Payments []domain.Payment
|
Requests []domain.TxRequest
|
||||||
ExpectedNumOfNodes int
|
ExpectedNumOfNodes int
|
||||||
ExpectedNumOfLeaves int
|
ExpectedNumOfLeaves int
|
||||||
}
|
}
|
||||||
Invalid []struct {
|
Invalid []struct {
|
||||||
Payments []domain.Payment
|
Requests []domain.TxRequest
|
||||||
ExpectedErr string
|
ExpectedErr string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePoolTxFixtures() (*poolTxFixtures, error) {
|
func parseRoundTxFixtures() (*roundTxFixtures, error) {
|
||||||
file, err := os.ReadFile("testdata/fixtures.json")
|
file, err := os.ReadFile("testdata/fixtures.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -139,9 +139,9 @@ func parsePoolTxFixtures() (*poolTxFixtures, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
vv := v["buildPoolTx"].(map[string]interface{})
|
vv := v["buildRoundTx"].(map[string]interface{})
|
||||||
file, _ = json.Marshal(vv)
|
file, _ = json.Marshal(vv)
|
||||||
var fixtures poolTxFixtures
|
var fixtures roundTxFixtures
|
||||||
if err := json.Unmarshal(file, &fixtures); err != nil {
|
if err := json.Unmarshal(file, &fixtures); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"buildPoolTx": {
|
"buildRoundTx": {
|
||||||
"valid": [
|
"valid": [
|
||||||
{
|
{
|
||||||
"payments": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"id": "0",
|
"id": "0",
|
||||||
"inputs": [
|
"inputs": [
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"expectedNumOfLeaves": 1
|
"expectedNumOfLeaves": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"payments": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"id": "0",
|
"id": "0",
|
||||||
"inputs": [
|
"inputs": [
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
"expectedNumOfLeaves": 2
|
"expectedNumOfLeaves": 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"payments": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"id": "0",
|
"id": "0",
|
||||||
"inputs": [
|
"inputs": [
|
||||||
@@ -126,7 +126,7 @@
|
|||||||
"expectedNumOfLeaves": 6
|
"expectedNumOfLeaves": 6
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"payments": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"id": "a242cdd8-f3d5-46c0-ae98-94135a2bee3f",
|
"id": "a242cdd8-f3d5-46c0-ae98-94135a2bee3f",
|
||||||
"inputs": [
|
"inputs": [
|
||||||
@@ -199,7 +199,7 @@
|
|||||||
"buildForfeitTxs": {
|
"buildForfeitTxs": {
|
||||||
"valid": [
|
"valid": [
|
||||||
{
|
{
|
||||||
"payments": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"id": "0",
|
"id": "0",
|
||||||
"inputs": [
|
"inputs": [
|
||||||
@@ -230,8 +230,8 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"poolTx": "cHNldP8BAgQCAAAAAQQBAQEFAQMBBgEDAfsEAgAAAAABDiDk7dXxh4KQzgLO8i1ABtaLCe4aPL12GVhN1E9zM1ePLwEPBAAAAAABEAT/////AAEDCOgDAAAAAAAAAQQWABSNnpy01UJqd99eTg2M1IpdKId11gf8BHBzZXQCICWyUQcOKcoZBDzzPM1zJOLdqwPsxK4LXnfE/A5c9slaB/wEcHNldAgEAAAAAAABAwh4BQAAAAAAAAEEFgAUjZ6ctNVCanffXk4NjNSKXSiHddYH/ARwc2V0AiAlslEHDinKGQQ88zzNcyTi3asD7MSuC153xPwOXPbJWgf8BHBzZXQIBAAAAAAAAQMI9AEAAAAAAAABBAAH/ARwc2V0AiAlslEHDinKGQQ88zzNcyTi3asD7MSuC153xPwOXPbJWgf8BHBzZXQIBAAAAAAA",
|
"roundTx": "cHNldP8BAgQCAAAAAQQBAQEFAQMBBgEDAfsEAgAAAAABDiDk7dXxh4KQzgLO8i1ABtaLCe4aPL12GVhN1E9zM1ePLwEPBAAAAAABEAT/////AAEDCOgDAAAAAAAAAQQWABSNnpy01UJqd99eTg2M1IpdKId11gf8BHBzZXQCICWyUQcOKcoZBDzzPM1zJOLdqwPsxK4LXnfE/A5c9slaB/wEcHNldAgEAAAAAAABAwh4BQAAAAAAAAEEFgAUjZ6ctNVCanffXk4NjNSKXSiHddYH/ARwc2V0AiAlslEHDinKGQQ88zzNcyTi3asD7MSuC153xPwOXPbJWgf8BHBzZXQIBAAAAAAAAQMI9AEAAAAAAAABBAAH/ARwc2V0AiAlslEHDinKGQQ88zzNcyTi3asD7MSuC153xPwOXPbJWgf8BHBzZXQIBAAAAAAA",
|
||||||
"poolTxid": "7981fce656f266472cc742444527cb32a8bed8c90fed6d47adbfc4c8780d4d9a",
|
"roundTxid": "7981fce656f266472cc742444527cb32a8bed8c90fed6d47adbfc4c8780d4d9a",
|
||||||
"expectedNumOfForfeitTxs": 4,
|
"expectedNumOfForfeitTxs": 4,
|
||||||
"expectedNumOfConnectors": 1
|
"expectedNumOfConnectors": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ import (
|
|||||||
"github.com/vulpemventures/go-elements/transaction"
|
"github.com/vulpemventures/go-elements/transaction"
|
||||||
)
|
)
|
||||||
|
|
||||||
func p2wpkhScript(publicKey *secp256k1.PublicKey, net *network.Network) ([]byte, error) {
|
func p2wpkhScript(pubkey *secp256k1.PublicKey, net *network.Network) ([]byte, error) {
|
||||||
payment := payment.FromPublicKey(publicKey, net, nil)
|
payment := payment.FromPublicKey(pubkey, net, nil)
|
||||||
addr, err := payment.WitnessPubKeyHash()
|
addr, err := payment.WitnessPubKeyHash()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -46,11 +46,11 @@ func getPsetId(pset *psetv2.Pset) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getOnchainOutputs(
|
func getOnchainOutputs(
|
||||||
payments []domain.Payment, net *network.Network,
|
requests []domain.TxRequest, net *network.Network,
|
||||||
) ([]psetv2.OutputArgs, error) {
|
) ([]psetv2.OutputArgs, error) {
|
||||||
outputs := make([]psetv2.OutputArgs, 0)
|
outputs := make([]psetv2.OutputArgs, 0)
|
||||||
for _, payment := range payments {
|
for _, request := range requests {
|
||||||
for _, receiver := range payment.Receivers {
|
for _, receiver := range request.Receivers {
|
||||||
if receiver.IsOnchain() {
|
if receiver.IsOnchain() {
|
||||||
receiverScript, err := address.ToOutputScript(receiver.OnchainAddress)
|
receiverScript, err := address.ToOutputScript(receiver.OnchainAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -69,14 +69,14 @@ func getOnchainOutputs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getOutputVtxosLeaves(
|
func getOutputVtxosLeaves(
|
||||||
payments []domain.Payment,
|
requests []domain.TxRequest,
|
||||||
) ([]tree.VtxoLeaf, error) {
|
) ([]tree.VtxoLeaf, error) {
|
||||||
receivers := make([]tree.VtxoLeaf, 0)
|
receivers := make([]tree.VtxoLeaf, 0)
|
||||||
for _, payment := range payments {
|
for _, request := range requests {
|
||||||
for _, receiver := range payment.Receivers {
|
for _, receiver := range request.Receivers {
|
||||||
if !receiver.IsOnchain() {
|
if !receiver.IsOnchain() {
|
||||||
receivers = append(receivers, tree.VtxoLeaf{
|
receivers = append(receivers, tree.VtxoLeaf{
|
||||||
Pubkey: receiver.Pubkey,
|
PubKey: receiver.PubKey,
|
||||||
Amount: receiver.Amount,
|
Amount: receiver.Amount,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -104,10 +104,10 @@ func toWitnessUtxo(in ports.TxInput) (*transaction.TxOutput, error) {
|
|||||||
return transaction.NewTxOutput(assetBytes, valueBytes, scriptBytes), nil
|
return transaction.NewTxOutput(assetBytes, valueBytes, scriptBytes), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func countSpentVtxos(payments []domain.Payment) uint64 {
|
func countSpentVtxos(requests []domain.TxRequest) uint64 {
|
||||||
var sum uint64
|
var sum uint64
|
||||||
for _, payment := range payments {
|
for _, request := range requests {
|
||||||
sum += uint64(len(payment.Inputs))
|
sum += uint64(len(request.Inputs))
|
||||||
}
|
}
|
||||||
return sum
|
return sum
|
||||||
}
|
}
|
||||||
@@ -144,9 +144,9 @@ func addInputs(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isOnchainOnly(payments []domain.Payment) bool {
|
func isOnchainOnly(requests []domain.TxRequest) bool {
|
||||||
for _, p := range payments {
|
for _, request := range requests {
|
||||||
for _, r := range p.Receivers {
|
for _, r := range request.Receivers {
|
||||||
if !r.IsOnchain() {
|
if !r.IsOnchain() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func (b *txBuilder) VerifyTapscriptPartialSigs(tx string) (bool, error) {
|
|||||||
func (b *txBuilder) verifyTapscriptPartialSigs(ptx *psbt.Packet) (bool, error) {
|
func (b *txBuilder) verifyTapscriptPartialSigs(ptx *psbt.Packet) (bool, error) {
|
||||||
txid := ptx.UnsignedTx.TxID()
|
txid := ptx.UnsignedTx.TxID()
|
||||||
|
|
||||||
aspPublicKey, err := b.wallet.GetPubkey(context.Background())
|
serverPubkey, err := b.wallet.GetPubkey(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
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
|
// we don't need to check if server signed
|
||||||
keys[hex.EncodeToString(schnorr.SerializePubKey(aspPublicKey))] = true
|
keys[hex.EncodeToString(schnorr.SerializePubKey(serverPubkey))] = true
|
||||||
|
|
||||||
if len(tapLeaf.ControlBlock) == 0 {
|
if len(tapLeaf.ControlBlock) == 0 {
|
||||||
return false, fmt.Errorf("missing control block for input %d", index)
|
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(
|
func (b *txBuilder) BuildRoundTx(
|
||||||
aspPubkey *secp256k1.PublicKey,
|
serverPubkey *secp256k1.PublicKey,
|
||||||
payments []domain.Payment,
|
requests []domain.TxRequest,
|
||||||
boardingInputs []ports.BoardingInput,
|
boardingInputs []ports.BoardingInput,
|
||||||
sweptRounds []domain.Round,
|
sweptRounds []domain.Round,
|
||||||
cosigners ...*secp256k1.PublicKey,
|
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 sharedOutputScript []byte
|
||||||
var sharedOutputAmount int64
|
var sharedOutputAmount int64
|
||||||
|
|
||||||
@@ -484,7 +484,7 @@ func (b *txBuilder) BuildRoundTx(
|
|||||||
return "", nil, "", nil, fmt.Errorf("missing cosigners")
|
return "", nil, "", nil, fmt.Errorf("missing cosigners")
|
||||||
}
|
}
|
||||||
|
|
||||||
receivers, err := getOutputVtxosLeaves(payments)
|
receivers, err := getOutputVtxosLeaves(requests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, "", nil, err
|
return "", nil, "", nil, err
|
||||||
}
|
}
|
||||||
@@ -494,9 +494,9 @@ func (b *txBuilder) BuildRoundTx(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isOnchainOnly(payments) {
|
if !isOnchainOnly(requests) {
|
||||||
sharedOutputScript, sharedOutputAmount, err = bitcointree.CraftSharedOutput(
|
sharedOutputScript, sharedOutputAmount, err = bitcointree.CraftSharedOutput(
|
||||||
cosigners, aspPubkey, receivers, feeAmount, b.roundLifetime,
|
cosigners, serverPubkey, receivers, feeAmount, b.roundLifetime,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -509,7 +509,7 @@ func (b *txBuilder) BuildRoundTx(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ptx, err := b.createRoundTx(
|
ptx, err := b.createRoundTx(
|
||||||
sharedOutputAmount, sharedOutputScript, payments, boardingInputs, connectorAddress, sweptRounds,
|
sharedOutputAmount, sharedOutputScript, requests, boardingInputs, connectorAddress, sweptRounds,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -520,21 +520,21 @@ func (b *txBuilder) BuildRoundTx(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isOnchainOnly(payments) {
|
if !isOnchainOnly(requests) {
|
||||||
initialOutpoint := &wire.OutPoint{
|
initialOutpoint := &wire.OutPoint{
|
||||||
Hash: ptx.UnsignedTx.TxHash(),
|
Hash: ptx.UnsignedTx.TxHash(),
|
||||||
Index: 0,
|
Index: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
congestionTree, err = bitcointree.CraftCongestionTree(
|
vtxoTree, err = bitcointree.BuildVtxoTree(
|
||||||
initialOutpoint, cosigners, aspPubkey, receivers, feeAmount, b.roundLifetime,
|
initialOutpoint, cosigners, serverPubkey, receivers, feeAmount, b.roundLifetime,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, "", nil, err
|
return "", nil, "", nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if countSpentVtxos(payments) <= 0 {
|
if countSpentVtxos(requests) <= 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -553,7 +553,7 @@ func (b *txBuilder) BuildRoundTx(
|
|||||||
return "", nil, "", nil, err
|
return "", nil, "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
connectorsPsbts, err := b.createConnectors(roundTx, payments, connectorPkScript, minRelayFeeConnectorTx)
|
connectorsPsbts, err := b.createConnectors(roundTx, requests, connectorPkScript, minRelayFeeConnectorTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, "", nil, err
|
return "", nil, "", nil, err
|
||||||
}
|
}
|
||||||
@@ -566,7 +566,7 @@ func (b *txBuilder) BuildRoundTx(
|
|||||||
connectors = append(connectors, b64)
|
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) {
|
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
|
return lifetime, sweepInput, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *txBuilder) FindLeaves(congestionTree tree.CongestionTree, fromtxid string, vout uint32) ([]tree.Node, error) {
|
func (b *txBuilder) FindLeaves(vtxoTree tree.VtxoTree, fromtxid string, vout uint32) ([]tree.Node, error) {
|
||||||
allLeaves := congestionTree.Leaves()
|
allLeaves := vtxoTree.Leaves()
|
||||||
foundLeaves := make([]tree.Node, 0)
|
foundLeaves := make([]tree.Node, 0)
|
||||||
|
|
||||||
for _, leaf := range allLeaves {
|
for _, leaf := range allLeaves {
|
||||||
branch, err := congestionTree.Branch(leaf.Txid)
|
branch, err := vtxoTree.Branch(leaf.Txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -647,7 +647,7 @@ func (b *txBuilder) FindLeaves(congestionTree tree.CongestionTree, fromtxid stri
|
|||||||
func (b *txBuilder) createRoundTx(
|
func (b *txBuilder) createRoundTx(
|
||||||
sharedOutputAmount int64,
|
sharedOutputAmount int64,
|
||||||
sharedOutputScript []byte,
|
sharedOutputScript []byte,
|
||||||
payments []domain.Payment,
|
requests []domain.TxRequest,
|
||||||
boardingInputs []ports.BoardingInput,
|
boardingInputs []ports.BoardingInput,
|
||||||
connectorAddress string,
|
connectorAddress string,
|
||||||
sweptRounds []domain.Round,
|
sweptRounds []domain.Round,
|
||||||
@@ -674,7 +674,7 @@ func (b *txBuilder) createRoundTx(
|
|||||||
|
|
||||||
connectorAmount := dustLimit
|
connectorAmount := dustLimit
|
||||||
|
|
||||||
nbOfInputs := countSpentVtxos(payments)
|
nbOfInputs := countSpentVtxos(requests)
|
||||||
connectorsAmount := (connectorAmount + connectorMinRelayFee) * nbOfInputs
|
connectorsAmount := (connectorAmount + connectorMinRelayFee) * nbOfInputs
|
||||||
if nbOfInputs > 1 {
|
if nbOfInputs > 1 {
|
||||||
connectorsAmount -= connectorMinRelayFee
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1021,9 +1021,9 @@ func (b *txBuilder) VerifyAndCombinePartialTx(dest string, src string) (string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *txBuilder) createConnectors(
|
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) {
|
) ([]*psbt.Packet, error) {
|
||||||
partialTx, err := psbt.NewFromRawBytes(strings.NewReader(poolTx), true)
|
partialTx, err := psbt.NewFromRawBytes(strings.NewReader(roundTx), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1038,7 +1038,7 @@ func (b *txBuilder) createConnectors(
|
|||||||
Value: int64(connectorAmount),
|
Value: int64(connectorAmount),
|
||||||
}
|
}
|
||||||
|
|
||||||
numberOfConnectors := countSpentVtxos(payments)
|
numberOfConnectors := countSpentVtxos(requests)
|
||||||
|
|
||||||
previousInput := &wire.OutPoint{
|
previousInput := &wire.OutPoint{
|
||||||
Hash: partialTx.UnsignedTx.TxHash(),
|
Hash: partialTx.UnsignedTx.TxHash(),
|
||||||
|
|||||||
@@ -55,12 +55,12 @@ func TestMain(m *testing.M) {
|
|||||||
os.Exit(m.Run())
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuildPoolTx(t *testing.T) {
|
func TestBuildRoundTx(t *testing.T) {
|
||||||
builder := txbuilder.NewTxBuilder(
|
builder := txbuilder.NewTxBuilder(
|
||||||
wallet, common.Bitcoin, roundLifetime, boardingExitDelay,
|
wallet, common.Bitcoin, roundLifetime, boardingExitDelay,
|
||||||
)
|
)
|
||||||
|
|
||||||
fixtures, err := parsePoolTxFixtures()
|
fixtures, err := parseRoundTxFixtures()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, fixtures)
|
require.NotEmpty(t, fixtures)
|
||||||
|
|
||||||
@@ -68,25 +68,25 @@ func TestBuildPoolTx(t *testing.T) {
|
|||||||
t.Run("valid", func(t *testing.T) {
|
t.Run("valid", func(t *testing.T) {
|
||||||
for _, f := range fixtures.Valid {
|
for _, f := range fixtures.Valid {
|
||||||
cosigners := make([]*secp256k1.PublicKey, 0)
|
cosigners := make([]*secp256k1.PublicKey, 0)
|
||||||
for range f.Payments {
|
for range f.Requests {
|
||||||
randKey, err := secp256k1.GeneratePrivateKey()
|
randKey, err := secp256k1.GeneratePrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
cosigners = append(cosigners, randKey.PubKey())
|
cosigners = append(cosigners, randKey.PubKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
poolTx, congestionTree, connAddr, _, err := builder.BuildRoundTx(
|
roundTx, vtxoTree, connAddr, _, err := builder.BuildRoundTx(
|
||||||
pubkey, f.Payments, []ports.BoardingInput{}, []domain.Round{}, cosigners...,
|
pubkey, f.Requests, []ports.BoardingInput{}, []domain.Round{}, cosigners...,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, poolTx)
|
require.NotEmpty(t, roundTx)
|
||||||
require.NotEmpty(t, congestionTree)
|
require.NotEmpty(t, vtxoTree)
|
||||||
require.Equal(t, connectorAddress, connAddr)
|
require.Equal(t, connectorAddress, connAddr)
|
||||||
require.Equal(t, f.ExpectedNumOfNodes, congestionTree.NumberOfNodes())
|
require.Equal(t, f.ExpectedNumOfNodes, vtxoTree.NumberOfNodes())
|
||||||
require.Len(t, congestionTree.Leaves(), f.ExpectedNumOfLeaves)
|
require.Len(t, vtxoTree.Leaves(), f.ExpectedNumOfLeaves)
|
||||||
|
|
||||||
err = bitcointree.ValidateCongestionTree(
|
err = bitcointree.ValidateVtxoTree(
|
||||||
congestionTree, poolTx, pubkey, roundLifetime,
|
vtxoTree, roundTx, pubkey, roundLifetime,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
@@ -96,13 +96,13 @@ func TestBuildPoolTx(t *testing.T) {
|
|||||||
if len(fixtures.Invalid) > 0 {
|
if len(fixtures.Invalid) > 0 {
|
||||||
t.Run("invalid", func(t *testing.T) {
|
t.Run("invalid", func(t *testing.T) {
|
||||||
for _, f := range fixtures.Invalid {
|
for _, f := range fixtures.Invalid {
|
||||||
poolTx, congestionTree, connAddr, _, err := builder.BuildRoundTx(
|
roundTx, vtxoTree, connAddr, _, err := builder.BuildRoundTx(
|
||||||
pubkey, f.Payments, []ports.BoardingInput{}, []domain.Round{},
|
pubkey, f.Requests, []ports.BoardingInput{}, []domain.Round{},
|
||||||
)
|
)
|
||||||
require.EqualError(t, err, f.ExpectedErr)
|
require.EqualError(t, err, f.ExpectedErr)
|
||||||
require.Empty(t, poolTx)
|
require.Empty(t, roundTx)
|
||||||
require.Empty(t, connAddr)
|
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)
|
return hex.EncodeToString(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
type poolTxFixtures struct {
|
type roundTxFixtures struct {
|
||||||
Valid []struct {
|
Valid []struct {
|
||||||
Payments []domain.Payment
|
Requests []domain.TxRequest
|
||||||
ExpectedNumOfNodes int
|
ExpectedNumOfNodes int
|
||||||
ExpectedNumOfLeaves int
|
ExpectedNumOfLeaves int
|
||||||
}
|
}
|
||||||
Invalid []struct {
|
Invalid []struct {
|
||||||
Payments []domain.Payment
|
Requests []domain.TxRequest
|
||||||
ExpectedErr string
|
ExpectedErr string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePoolTxFixtures() (*poolTxFixtures, error) {
|
func parseRoundTxFixtures() (*roundTxFixtures, error) {
|
||||||
file, err := os.ReadFile("testdata/fixtures.json")
|
file, err := os.ReadFile("testdata/fixtures.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -149,9 +149,9 @@ func parsePoolTxFixtures() (*poolTxFixtures, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
vv := v["buildPoolTx"].(map[string]interface{})
|
vv := v["buildRoundTx"].(map[string]interface{})
|
||||||
file, _ = json.Marshal(vv)
|
file, _ = json.Marshal(vv)
|
||||||
var fixtures poolTxFixtures
|
var fixtures roundTxFixtures
|
||||||
if err := json.Unmarshal(file, &fixtures); err != nil {
|
if err := json.Unmarshal(file, &fixtures); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"buildPoolTx": {
|
"buildRoundTx": {
|
||||||
"valid": [
|
"valid": [
|
||||||
{
|
{
|
||||||
"payments": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"id": "0",
|
"id": "0",
|
||||||
"inputs": [
|
"inputs": [
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"expectedNumOfLeaves": 1
|
"expectedNumOfLeaves": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"payments": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"id": "0",
|
"id": "0",
|
||||||
"inputs": [
|
"inputs": [
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
"expectedNumOfLeaves": 2
|
"expectedNumOfLeaves": 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"payments": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"id": "0",
|
"id": "0",
|
||||||
"inputs": [
|
"inputs": [
|
||||||
@@ -126,7 +126,7 @@
|
|||||||
"expectedNumOfLeaves": 6
|
"expectedNumOfLeaves": 6
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"payments": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"id": "a242cdd8-f3d5-46c0-ae98-94135a2bee3f",
|
"id": "a242cdd8-f3d5-46c0-ae98-94135a2bee3f",
|
||||||
"inputs": [
|
"inputs": [
|
||||||
@@ -199,7 +199,7 @@
|
|||||||
"buildForfeitTxs": {
|
"buildForfeitTxs": {
|
||||||
"valid": [
|
"valid": [
|
||||||
{
|
{
|
||||||
"payments": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"id": "a242cdd8-f3d5-46c0-ae98-94135a2bee3f",
|
"id": "a242cdd8-f3d5-46c0-ae98-94135a2bee3f",
|
||||||
"inputs": [
|
"inputs": [
|
||||||
@@ -263,8 +263,8 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"poolTx": "cHNidP8BALICAAAAAnonOnsJBkHUUaKf/7fdS0/sVyBCgDPusYzGSZZiXPbtAAAAAAD/////VLtr81ZII3QJnXgrIwgcnbsq3aa4L3qdHOAn2evlFtEAAAAAAP////8CohIAAAAAAAAiUSBZarBUuSIHnlkuIoel9MmvexqTGK8jCZaRjt8L+Pb3s+gDAAAAAAAAIlEgI95L4kHEn2fAA+vysD+RIR4eD3AIQwc+FyCInJ8HivYAAAAAAAEBIOgDAAAAAAAAF6kU6p9IboLvs92Dpp/Zbj8BE3V9oDyHAAEBIOgDAAAAAAAAF6kU6p9IboLvs92Dpp/Zbj8BE3V9oDyHAAAA",
|
"roundTx": "cHNidP8BALICAAAAAnonOnsJBkHUUaKf/7fdS0/sVyBCgDPusYzGSZZiXPbtAAAAAAD/////VLtr81ZII3QJnXgrIwgcnbsq3aa4L3qdHOAn2evlFtEAAAAAAP////8CohIAAAAAAAAiUSBZarBUuSIHnlkuIoel9MmvexqTGK8jCZaRjt8L+Pb3s+gDAAAAAAAAIlEgI95L4kHEn2fAA+vysD+RIR4eD3AIQwc+FyCInJ8HivYAAAAAAAEBIOgDAAAAAAAAF6kU6p9IboLvs92Dpp/Zbj8BE3V9oDyHAAEBIOgDAAAAAAAAF6kU6p9IboLvs92Dpp/Zbj8BE3V9oDyHAAAA",
|
||||||
"poolTxid": "7c0c10756cdb9ab8e605f1c82e25989761308cf4c60e6a6f42b72d46144c4ce0",
|
"roundTxid": "7c0c10756cdb9ab8e605f1c82e25989761308cf4c60e6a6f42b72d46144c4ce0",
|
||||||
"expectedNumOfForfeitTxs": 25,
|
"expectedNumOfForfeitTxs": 25,
|
||||||
"expectedNumOfConnectors": 4
|
"expectedNumOfConnectors": 4
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user