mirror of
https://github.com/aljazceru/ark.git
synced 2025-12-17 12:14:21 +01:00
Make the round participants sign the vtxo tree (#271)
* [proto] add APIs to send and receive musig2 signing data * [common] add serialization functions for nonces and signatures * [application] implements tree signing * fix: remove old debug logs * [proto] cleaning * [common] fix musig2.go * [application] fixes and logs * [interface] fix: stop forwarding 2 times the events * [client] add musig2 support + sign the tree when joining a round * [interface] add new APIs into permissions.go * [application][proto] rework PingResponse (return all events type) * [common] split SetKeys into 2 distinct methods * [client] fixes according to musig2.go changes * [sdk] support tree signing + new PingResponse * [sdk] fixes * [application] revert event channel type * [application] use domain.RoundEvent as lastEvent type * [application] remove IsCovenantLess * comments * [application] revert roundAborted changes * [interface] remove bitcointree dependencie
This commit is contained in:
@@ -261,6 +261,70 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/v1/payment/tree/nonces": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "ArkService_SendTreeNonces",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1SendTreeNoncesResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1SendTreeNoncesRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"ArkService"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/v1/payment/tree/signatures": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "ArkService_SendTreeSignatures",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1SendTreeSignaturesResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1SendTreeSignaturesRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"ArkService"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/v1/ping/{paymentId}": {
|
"/v1/ping/{paymentId}": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "ArkService_Ping",
|
"operationId": "ArkService_Ping",
|
||||||
@@ -323,7 +387,6 @@
|
|||||||
},
|
},
|
||||||
"/v1/round/{txid}": {
|
"/v1/round/{txid}": {
|
||||||
"get": {
|
"get": {
|
||||||
"summary": "TODO BTC: signTree rpc",
|
|
||||||
"operationId": "ArkService_GetRound",
|
"operationId": "ArkService_GetRound",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
@@ -502,14 +565,19 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"roundFinalization": {
|
"roundFinalization": {
|
||||||
"$ref": "#/definitions/v1RoundFinalizationEvent",
|
"$ref": "#/definitions/v1RoundFinalizationEvent"
|
||||||
"title": "TODO: BTC add \"signTree\" event"
|
|
||||||
},
|
},
|
||||||
"roundFinalized": {
|
"roundFinalized": {
|
||||||
"$ref": "#/definitions/v1RoundFinalizedEvent"
|
"$ref": "#/definitions/v1RoundFinalizedEvent"
|
||||||
},
|
},
|
||||||
"roundFailed": {
|
"roundFailed": {
|
||||||
"$ref": "#/definitions/v1RoundFailed"
|
"$ref": "#/definitions/v1RoundFailed"
|
||||||
|
},
|
||||||
|
"roundSigning": {
|
||||||
|
"$ref": "#/definitions/v1RoundSigningEvent"
|
||||||
|
},
|
||||||
|
"roundSigningNoncesGenerated": {
|
||||||
|
"$ref": "#/definitions/v1RoundSigningNoncesGeneratedEvent"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -649,14 +717,20 @@
|
|||||||
"v1PingResponse": {
|
"v1PingResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"forfeitTxs": {
|
"roundFinalization": {
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"event": {
|
|
||||||
"$ref": "#/definitions/v1RoundFinalizationEvent"
|
"$ref": "#/definitions/v1RoundFinalizationEvent"
|
||||||
|
},
|
||||||
|
"roundFinalized": {
|
||||||
|
"$ref": "#/definitions/v1RoundFinalizedEvent"
|
||||||
|
},
|
||||||
|
"roundFailed": {
|
||||||
|
"$ref": "#/definitions/v1RoundFailed"
|
||||||
|
},
|
||||||
|
"roundSigning": {
|
||||||
|
"$ref": "#/definitions/v1RoundSigningEvent"
|
||||||
|
},
|
||||||
|
"roundSigningNoncesGenerated": {
|
||||||
|
"$ref": "#/definitions/v1RoundSigningNoncesGeneratedEvent"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -669,6 +743,9 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"$ref": "#/definitions/v1Input"
|
"$ref": "#/definitions/v1Input"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ephemeralPubkey": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -766,6 +843,34 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"v1RoundSigningEvent": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"cosignersPubkeys": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unsignedTree": {
|
||||||
|
"$ref": "#/definitions/v1Tree"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1RoundSigningNoncesGeneratedEvent": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"treeNonces": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"v1RoundStage": {
|
"v1RoundStage": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
@@ -777,6 +882,40 @@
|
|||||||
],
|
],
|
||||||
"default": "ROUND_STAGE_UNSPECIFIED"
|
"default": "ROUND_STAGE_UNSPECIFIED"
|
||||||
},
|
},
|
||||||
|
"v1SendTreeNoncesRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"roundId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"publicKey": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"treeNonces": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1SendTreeNoncesResponse": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"v1SendTreeSignaturesRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"roundId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"publicKey": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"treeSignatures": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1SendTreeSignaturesResponse": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"v1Tree": {
|
"v1Tree": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -17,13 +17,24 @@ service ArkService {
|
|||||||
body: "*"
|
body: "*"
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
rpc SendTreeNonces(SendTreeNoncesRequest) returns (SendTreeNoncesResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/v1/payment/tree/nonces"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
rpc SendTreeSignatures(SendTreeSignaturesRequest) returns (SendTreeSignaturesResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/v1/payment/tree/signatures"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
}
|
||||||
rpc FinalizePayment(FinalizePaymentRequest) returns (FinalizePaymentResponse) {
|
rpc FinalizePayment(FinalizePaymentRequest) returns (FinalizePaymentResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/v1/payment/finalize"
|
post: "/v1/payment/finalize"
|
||||||
body: "*"
|
body: "*"
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
// TODO BTC: signTree rpc
|
|
||||||
rpc GetRound(GetRoundRequest) returns (GetRoundResponse) {
|
rpc GetRound(GetRoundRequest) returns (GetRoundResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/round/{txid}"
|
get: "/v1/round/{txid}"
|
||||||
@@ -91,6 +102,7 @@ message CompletePaymentResponse {}
|
|||||||
|
|
||||||
message RegisterPaymentRequest {
|
message RegisterPaymentRequest {
|
||||||
repeated Input inputs = 1;
|
repeated Input inputs = 1;
|
||||||
|
optional string ephemeral_pubkey = 2;
|
||||||
}
|
}
|
||||||
message RegisterPaymentResponse {
|
message RegisterPaymentResponse {
|
||||||
// Mocks wabisabi's credentials.
|
// Mocks wabisabi's credentials.
|
||||||
@@ -128,10 +140,11 @@ message GetRoundByIdResponse {
|
|||||||
message GetEventStreamRequest {}
|
message GetEventStreamRequest {}
|
||||||
message GetEventStreamResponse {
|
message GetEventStreamResponse {
|
||||||
oneof event {
|
oneof event {
|
||||||
// TODO: BTC add "signTree" event
|
|
||||||
RoundFinalizationEvent round_finalization = 1;
|
RoundFinalizationEvent round_finalization = 1;
|
||||||
RoundFinalizedEvent round_finalized = 2;
|
RoundFinalizedEvent round_finalized = 2;
|
||||||
RoundFailed round_failed = 3;
|
RoundFailed round_failed = 3;
|
||||||
|
RoundSigningEvent round_signing = 4;
|
||||||
|
RoundSigningNoncesGeneratedEvent round_signing_nonces_generated = 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,8 +152,13 @@ message PingRequest {
|
|||||||
string payment_id = 1;
|
string payment_id = 1;
|
||||||
}
|
}
|
||||||
message PingResponse {
|
message PingResponse {
|
||||||
repeated string forfeit_txs = 1;
|
oneof event {
|
||||||
RoundFinalizationEvent event = 2;
|
RoundFinalizationEvent round_finalization = 1;
|
||||||
|
RoundFinalizedEvent round_finalized = 2;
|
||||||
|
RoundFailed round_failed = 3;
|
||||||
|
RoundSigningEvent round_signing = 4;
|
||||||
|
RoundSigningNoncesGeneratedEvent round_signing_nonces_generated = 5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListVtxosRequest {
|
message ListVtxosRequest {
|
||||||
@@ -189,6 +207,17 @@ message RoundFailed {
|
|||||||
string reason = 2;
|
string reason = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message RoundSigningEvent {
|
||||||
|
string id = 1;
|
||||||
|
repeated string cosigners_pubkeys = 2;
|
||||||
|
Tree unsigned_tree = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RoundSigningNoncesGeneratedEvent {
|
||||||
|
string id = 1;
|
||||||
|
string tree_nonces = 2;
|
||||||
|
}
|
||||||
|
|
||||||
// TYPES
|
// TYPES
|
||||||
|
|
||||||
enum RoundStage {
|
enum RoundStage {
|
||||||
@@ -251,4 +280,20 @@ message Vtxo {
|
|||||||
message PendingPayment {
|
message PendingPayment {
|
||||||
string redeem_tx = 1;
|
string redeem_tx = 1;
|
||||||
repeated string unconditional_forfeit_txs =2;
|
repeated string unconditional_forfeit_txs =2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message SendTreeNoncesRequest {
|
||||||
|
string round_id = 1;
|
||||||
|
string public_key = 2;
|
||||||
|
string tree_nonces = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SendTreeNoncesResponse {}
|
||||||
|
|
||||||
|
message SendTreeSignaturesRequest {
|
||||||
|
string round_id = 1;
|
||||||
|
string public_key = 2;
|
||||||
|
string tree_signatures = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SendTreeSignaturesResponse {}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -83,6 +83,58 @@ func local_request_ArkService_ClaimPayment_0(ctx context.Context, marshaler runt
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func request_ArkService_SendTreeNonces_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq SendTreeNoncesRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := client.SendTreeNonces(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func local_request_ArkService_SendTreeNonces_0(ctx context.Context, marshaler runtime.Marshaler, server ArkServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq SendTreeNoncesRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := server.SendTreeNonces(ctx, &protoReq)
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func request_ArkService_SendTreeSignatures_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq SendTreeSignaturesRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := client.SendTreeSignatures(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func local_request_ArkService_SendTreeSignatures_0(ctx context.Context, marshaler runtime.Marshaler, server ArkServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq SendTreeSignaturesRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := server.SendTreeSignatures(ctx, &protoReq)
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func request_ArkService_FinalizePayment_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
func request_ArkService_FinalizePayment_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
var protoReq FinalizePaymentRequest
|
var protoReq FinalizePaymentRequest
|
||||||
var metadata runtime.ServerMetadata
|
var metadata runtime.ServerMetadata
|
||||||
@@ -486,6 +538,56 @@ func RegisterArkServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mux.Handle("POST", pattern_ArkService_SendTreeNonces_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
var stream runtime.ServerTransportStream
|
||||||
|
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ark.v1.ArkService/SendTreeNonces", runtime.WithHTTPPathPattern("/v1/payment/tree/nonces"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := local_request_ArkService_SendTreeNonces_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||||
|
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_ArkService_SendTreeNonces_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
mux.Handle("POST", pattern_ArkService_SendTreeSignatures_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
var stream runtime.ServerTransportStream
|
||||||
|
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ark.v1.ArkService/SendTreeSignatures", runtime.WithHTTPPathPattern("/v1/payment/tree/signatures"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := local_request_ArkService_SendTreeSignatures_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||||
|
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_ArkService_SendTreeSignatures_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
mux.Handle("POST", pattern_ArkService_FinalizePayment_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("POST", pattern_ArkService_FinalizePayment_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -803,6 +905,50 @@ func RegisterArkServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mux.Handle("POST", pattern_ArkService_SendTreeNonces_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ark.v1.ArkService/SendTreeNonces", runtime.WithHTTPPathPattern("/v1/payment/tree/nonces"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_ArkService_SendTreeNonces_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_ArkService_SendTreeNonces_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
mux.Handle("POST", pattern_ArkService_SendTreeSignatures_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ark.v1.ArkService/SendTreeSignatures", runtime.WithHTTPPathPattern("/v1/payment/tree/signatures"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_ArkService_SendTreeSignatures_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_ArkService_SendTreeSignatures_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
mux.Handle("POST", pattern_ArkService_FinalizePayment_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("POST", pattern_ArkService_FinalizePayment_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -1031,6 +1177,10 @@ var (
|
|||||||
|
|
||||||
pattern_ArkService_ClaimPayment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "payment", "claim"}, ""))
|
pattern_ArkService_ClaimPayment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "payment", "claim"}, ""))
|
||||||
|
|
||||||
|
pattern_ArkService_SendTreeNonces_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "payment", "tree", "nonces"}, ""))
|
||||||
|
|
||||||
|
pattern_ArkService_SendTreeSignatures_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "payment", "tree", "signatures"}, ""))
|
||||||
|
|
||||||
pattern_ArkService_FinalizePayment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "payment", "finalize"}, ""))
|
pattern_ArkService_FinalizePayment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "payment", "finalize"}, ""))
|
||||||
|
|
||||||
pattern_ArkService_GetRound_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "round", "txid"}, ""))
|
pattern_ArkService_GetRound_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "round", "txid"}, ""))
|
||||||
@@ -1057,6 +1207,10 @@ var (
|
|||||||
|
|
||||||
forward_ArkService_ClaimPayment_0 = runtime.ForwardResponseMessage
|
forward_ArkService_ClaimPayment_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_ArkService_SendTreeNonces_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_ArkService_SendTreeSignatures_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_ArkService_FinalizePayment_0 = runtime.ForwardResponseMessage
|
forward_ArkService_FinalizePayment_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_ArkService_GetRound_0 = runtime.ForwardResponseMessage
|
forward_ArkService_GetRound_0 = runtime.ForwardResponseMessage
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ const _ = grpc.SupportPackageIsVersion7
|
|||||||
type ArkServiceClient interface {
|
type ArkServiceClient interface {
|
||||||
RegisterPayment(ctx context.Context, in *RegisterPaymentRequest, opts ...grpc.CallOption) (*RegisterPaymentResponse, error)
|
RegisterPayment(ctx context.Context, in *RegisterPaymentRequest, opts ...grpc.CallOption) (*RegisterPaymentResponse, error)
|
||||||
ClaimPayment(ctx context.Context, in *ClaimPaymentRequest, opts ...grpc.CallOption) (*ClaimPaymentResponse, error)
|
ClaimPayment(ctx context.Context, in *ClaimPaymentRequest, opts ...grpc.CallOption) (*ClaimPaymentResponse, error)
|
||||||
|
SendTreeNonces(ctx context.Context, in *SendTreeNoncesRequest, opts ...grpc.CallOption) (*SendTreeNoncesResponse, error)
|
||||||
|
SendTreeSignatures(ctx context.Context, in *SendTreeSignaturesRequest, opts ...grpc.CallOption) (*SendTreeSignaturesResponse, error)
|
||||||
FinalizePayment(ctx context.Context, in *FinalizePaymentRequest, opts ...grpc.CallOption) (*FinalizePaymentResponse, error)
|
FinalizePayment(ctx context.Context, in *FinalizePaymentRequest, opts ...grpc.CallOption) (*FinalizePaymentResponse, error)
|
||||||
// TODO BTC: signTree rpc
|
|
||||||
GetRound(ctx context.Context, in *GetRoundRequest, opts ...grpc.CallOption) (*GetRoundResponse, error)
|
GetRound(ctx context.Context, in *GetRoundRequest, opts ...grpc.CallOption) (*GetRoundResponse, error)
|
||||||
GetRoundById(ctx context.Context, in *GetRoundByIdRequest, opts ...grpc.CallOption) (*GetRoundByIdResponse, error)
|
GetRoundById(ctx context.Context, in *GetRoundByIdRequest, opts ...grpc.CallOption) (*GetRoundByIdResponse, error)
|
||||||
GetEventStream(ctx context.Context, in *GetEventStreamRequest, opts ...grpc.CallOption) (ArkService_GetEventStreamClient, error)
|
GetEventStream(ctx context.Context, in *GetEventStreamRequest, opts ...grpc.CallOption) (ArkService_GetEventStreamClient, error)
|
||||||
@@ -59,6 +60,24 @@ func (c *arkServiceClient) ClaimPayment(ctx context.Context, in *ClaimPaymentReq
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *arkServiceClient) SendTreeNonces(ctx context.Context, in *SendTreeNoncesRequest, opts ...grpc.CallOption) (*SendTreeNoncesResponse, error) {
|
||||||
|
out := new(SendTreeNoncesResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/ark.v1.ArkService/SendTreeNonces", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *arkServiceClient) SendTreeSignatures(ctx context.Context, in *SendTreeSignaturesRequest, opts ...grpc.CallOption) (*SendTreeSignaturesResponse, error) {
|
||||||
|
out := new(SendTreeSignaturesResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/ark.v1.ArkService/SendTreeSignatures", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *arkServiceClient) FinalizePayment(ctx context.Context, in *FinalizePaymentRequest, opts ...grpc.CallOption) (*FinalizePaymentResponse, error) {
|
func (c *arkServiceClient) FinalizePayment(ctx context.Context, in *FinalizePaymentRequest, opts ...grpc.CallOption) (*FinalizePaymentResponse, error) {
|
||||||
out := new(FinalizePaymentResponse)
|
out := new(FinalizePaymentResponse)
|
||||||
err := c.cc.Invoke(ctx, "/ark.v1.ArkService/FinalizePayment", in, out, opts...)
|
err := c.cc.Invoke(ctx, "/ark.v1.ArkService/FinalizePayment", in, out, opts...)
|
||||||
@@ -178,8 +197,9 @@ func (c *arkServiceClient) CompletePayment(ctx context.Context, in *CompletePaym
|
|||||||
type ArkServiceServer interface {
|
type ArkServiceServer interface {
|
||||||
RegisterPayment(context.Context, *RegisterPaymentRequest) (*RegisterPaymentResponse, error)
|
RegisterPayment(context.Context, *RegisterPaymentRequest) (*RegisterPaymentResponse, error)
|
||||||
ClaimPayment(context.Context, *ClaimPaymentRequest) (*ClaimPaymentResponse, error)
|
ClaimPayment(context.Context, *ClaimPaymentRequest) (*ClaimPaymentResponse, error)
|
||||||
|
SendTreeNonces(context.Context, *SendTreeNoncesRequest) (*SendTreeNoncesResponse, error)
|
||||||
|
SendTreeSignatures(context.Context, *SendTreeSignaturesRequest) (*SendTreeSignaturesResponse, error)
|
||||||
FinalizePayment(context.Context, *FinalizePaymentRequest) (*FinalizePaymentResponse, error)
|
FinalizePayment(context.Context, *FinalizePaymentRequest) (*FinalizePaymentResponse, error)
|
||||||
// TODO BTC: signTree rpc
|
|
||||||
GetRound(context.Context, *GetRoundRequest) (*GetRoundResponse, error)
|
GetRound(context.Context, *GetRoundRequest) (*GetRoundResponse, error)
|
||||||
GetRoundById(context.Context, *GetRoundByIdRequest) (*GetRoundByIdResponse, error)
|
GetRoundById(context.Context, *GetRoundByIdRequest) (*GetRoundByIdResponse, error)
|
||||||
GetEventStream(*GetEventStreamRequest, ArkService_GetEventStreamServer) error
|
GetEventStream(*GetEventStreamRequest, ArkService_GetEventStreamServer) error
|
||||||
@@ -201,6 +221,12 @@ func (UnimplementedArkServiceServer) RegisterPayment(context.Context, *RegisterP
|
|||||||
func (UnimplementedArkServiceServer) ClaimPayment(context.Context, *ClaimPaymentRequest) (*ClaimPaymentResponse, error) {
|
func (UnimplementedArkServiceServer) ClaimPayment(context.Context, *ClaimPaymentRequest) (*ClaimPaymentResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method ClaimPayment not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method ClaimPayment not implemented")
|
||||||
}
|
}
|
||||||
|
func (UnimplementedArkServiceServer) SendTreeNonces(context.Context, *SendTreeNoncesRequest) (*SendTreeNoncesResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method SendTreeNonces not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedArkServiceServer) SendTreeSignatures(context.Context, *SendTreeSignaturesRequest) (*SendTreeSignaturesResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method SendTreeSignatures not implemented")
|
||||||
|
}
|
||||||
func (UnimplementedArkServiceServer) FinalizePayment(context.Context, *FinalizePaymentRequest) (*FinalizePaymentResponse, error) {
|
func (UnimplementedArkServiceServer) FinalizePayment(context.Context, *FinalizePaymentRequest) (*FinalizePaymentResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method FinalizePayment not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method FinalizePayment not implemented")
|
||||||
}
|
}
|
||||||
@@ -279,6 +305,42 @@ func _ArkService_ClaimPayment_Handler(srv interface{}, ctx context.Context, dec
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _ArkService_SendTreeNonces_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(SendTreeNoncesRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(ArkServiceServer).SendTreeNonces(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/ark.v1.ArkService/SendTreeNonces",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(ArkServiceServer).SendTreeNonces(ctx, req.(*SendTreeNoncesRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _ArkService_SendTreeSignatures_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(SendTreeSignaturesRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(ArkServiceServer).SendTreeSignatures(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/ark.v1.ArkService/SendTreeSignatures",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(ArkServiceServer).SendTreeSignatures(ctx, req.(*SendTreeSignaturesRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
func _ArkService_FinalizePayment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _ArkService_FinalizePayment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(FinalizePaymentRequest)
|
in := new(FinalizePaymentRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
@@ -477,6 +539,14 @@ var ArkService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "ClaimPayment",
|
MethodName: "ClaimPayment",
|
||||||
Handler: _ArkService_ClaimPayment_Handler,
|
Handler: _ArkService_ClaimPayment_Handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
MethodName: "SendTreeNonces",
|
||||||
|
Handler: _ArkService_SendTreeNonces_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "SendTreeSignatures",
|
||||||
|
Handler: _ArkService_SendTreeSignatures_Handler,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
MethodName: "FinalizePayment",
|
MethodName: "FinalizePayment",
|
||||||
Handler: _ArkService_FinalizePayment_Handler,
|
Handler: _ArkService_FinalizePayment_Handler,
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package covenantless
|
package covenantless
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
|
||||||
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
||||||
"github.com/ark-network/ark/client/utils"
|
"github.com/ark-network/ark/client/utils"
|
||||||
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -69,8 +72,19 @@ func selfTransferAllPendingPayments(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ephemeralKey, err := secp256k1.GeneratePrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkey := hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed())
|
||||||
|
|
||||||
registerResponse, err := client.RegisterPayment(
|
registerResponse, err := client.RegisterPayment(
|
||||||
ctx.Context, &arkv1.RegisterPaymentRequest{Inputs: inputs},
|
ctx.Context,
|
||||||
|
&arkv1.RegisterPaymentRequest{
|
||||||
|
Inputs: inputs,
|
||||||
|
EphemeralPubkey: &pubkey,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -86,7 +100,7 @@ func selfTransferAllPendingPayments(
|
|||||||
|
|
||||||
poolTxID, err := handleRoundStream(
|
poolTxID, err := handleRoundStream(
|
||||||
ctx, client, registerResponse.GetId(),
|
ctx, client, registerResponse.GetId(),
|
||||||
pendingVtxos, secKey, receiversOutput,
|
pendingVtxos, secKey, receiversOutput, ephemeralKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package covenantless
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -14,6 +15,7 @@ import (
|
|||||||
"github.com/ark-network/ark/common/tree"
|
"github.com/ark-network/ark/common/tree"
|
||||||
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
||||||
"github.com/btcsuite/btcd/btcutil/psbt"
|
"github.com/btcsuite/btcd/btcutil/psbt"
|
||||||
|
"github.com/btcsuite/btcd/txscript"
|
||||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@@ -220,12 +222,15 @@ func castCongestionTree(congestionTree tree.CongestionTree) *arkv1.Tree {
|
|||||||
func handleRoundStream(
|
func handleRoundStream(
|
||||||
ctx *cli.Context, client arkv1.ArkServiceClient, paymentID string,
|
ctx *cli.Context, client arkv1.ArkServiceClient, paymentID string,
|
||||||
vtxosToSign []vtxo, secKey *secp256k1.PrivateKey, receivers []*arkv1.Output,
|
vtxosToSign []vtxo, secKey *secp256k1.PrivateKey, receivers []*arkv1.Output,
|
||||||
|
ephemeralKey *secp256k1.PrivateKey,
|
||||||
) (poolTxID string, err error) {
|
) (poolTxID string, err error) {
|
||||||
stream, err := client.GetEventStream(ctx.Context, &arkv1.GetEventStreamRequest{})
|
stream, err := client.GetEventStream(ctx.Context, &arkv1.GetEventStreamRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myEphemeralPublicKey := hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed())
|
||||||
|
|
||||||
var pingStop func()
|
var pingStop func()
|
||||||
pingReq := &arkv1.PingRequest{
|
pingReq := &arkv1.PingRequest{
|
||||||
PaymentId: paymentID,
|
PaymentId: paymentID,
|
||||||
@@ -236,6 +241,8 @@ func handleRoundStream(
|
|||||||
|
|
||||||
defer pingStop()
|
defer pingStop()
|
||||||
|
|
||||||
|
var treeSignerSession bitcointree.SignerSession
|
||||||
|
|
||||||
for {
|
for {
|
||||||
event, err := stream.Recv()
|
event, err := stream.Recv()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
@@ -250,6 +257,143 @@ func handleRoundStream(
|
|||||||
return "", fmt.Errorf("round failed: %s", e.GetReason())
|
return "", fmt.Errorf("round failed: %s", e.GetReason())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if e := event.GetRoundSigning(); e != nil {
|
||||||
|
pingStop()
|
||||||
|
fmt.Println("tree created, generating nonces...")
|
||||||
|
|
||||||
|
cosignersPubKeysHex := e.GetCosignersPubkeys()
|
||||||
|
|
||||||
|
cosigners := make([]*secp256k1.PublicKey, 0, len(cosignersPubKeysHex))
|
||||||
|
|
||||||
|
for _, pubkeyHex := range cosignersPubKeysHex {
|
||||||
|
pubkeyBytes, err := hex.DecodeString(pubkeyHex)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkey, err := secp256k1.ParsePubKey(pubkeyBytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
cosigners = append(cosigners, pubkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
congestionTree, err := toCongestionTree(e.GetUnsignedTree())
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
minRelayFee, err := utils.GetMinRelayFee(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
aspPubkey, err := utils.GetAspPublicKey(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
lifetime, err := utils.GetRoundLifetime(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
sweepClosure := bitcointree.CSVSigClosure{
|
||||||
|
Pubkey: aspPubkey,
|
||||||
|
Seconds: uint(lifetime),
|
||||||
|
}
|
||||||
|
|
||||||
|
sweepTapLeaf, err := sweepClosure.Leaf()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
sweepTapTree := txscript.AssembleTaprootScriptTree(*sweepTapLeaf)
|
||||||
|
root := sweepTapTree.RootNode.TapHash()
|
||||||
|
|
||||||
|
treeSignerSession = bitcointree.NewTreeSignerSession(
|
||||||
|
ephemeralKey, congestionTree, int64(minRelayFee), root.CloneBytes(),
|
||||||
|
)
|
||||||
|
|
||||||
|
nonces, err := treeSignerSession.GetNonces()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := treeSignerSession.SetKeys(cosigners); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var nonceBuffer bytes.Buffer
|
||||||
|
|
||||||
|
if err := nonces.Encode(&nonceBuffer); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedNonces := hex.EncodeToString(nonceBuffer.Bytes())
|
||||||
|
|
||||||
|
if _, err := client.SendTreeNonces(ctx.Context, &arkv1.SendTreeNoncesRequest{
|
||||||
|
RoundId: e.GetId(),
|
||||||
|
PublicKey: myEphemeralPublicKey,
|
||||||
|
TreeNonces: serializedNonces,
|
||||||
|
}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("nonces sent")
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if e := event.GetRoundSigningNoncesGenerated(); e != nil {
|
||||||
|
pingStop()
|
||||||
|
fmt.Println("nonces generated, signing the tree...")
|
||||||
|
|
||||||
|
if treeSignerSession == nil {
|
||||||
|
return "", fmt.Errorf("tree signer session not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
combinedNoncesBytes, err := hex.DecodeString(e.GetTreeNonces())
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
combinedNonces, err := bitcointree.DecodeNonces(bytes.NewReader(combinedNoncesBytes))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := treeSignerSession.SetAggregatedNonces(combinedNonces); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
sigs, err := treeSignerSession.Sign()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var sigBuffer bytes.Buffer
|
||||||
|
|
||||||
|
if err := sigs.Encode(&sigBuffer); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedSigs := hex.EncodeToString(sigBuffer.Bytes())
|
||||||
|
|
||||||
|
if _, err := client.SendTreeSignatures(ctx.Context, &arkv1.SendTreeSignaturesRequest{
|
||||||
|
RoundId: e.GetId(),
|
||||||
|
TreeSignatures: serializedSigs,
|
||||||
|
PublicKey: myEphemeralPublicKey,
|
||||||
|
}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("tree signed")
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if e := event.GetRoundFinalization(); e != nil {
|
if e := event.GetRoundFinalization(); e != nil {
|
||||||
// stop pinging as soon as we receive some forfeit txs
|
// stop pinging as soon as we receive some forfeit txs
|
||||||
pingStop()
|
pingStop()
|
||||||
|
|||||||
@@ -168,7 +168,11 @@ func (c *clArkBitcoinCLI) Onboard(ctx *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := signer.SetKeys(cosigners, aggregatedNonces); err != nil {
|
if err := signer.SetKeys(cosigners); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := signer.SetAggregatedNonces(aggregatedNonces); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package covenantless
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@@ -11,6 +12,7 @@ import (
|
|||||||
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
||||||
"github.com/ark-network/ark/client/utils"
|
"github.com/ark-network/ark/client/utils"
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -80,8 +82,16 @@ func collaborativeRedeem(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ephemeralKey, err := secp256k1.GeneratePrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkey := hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed())
|
||||||
|
|
||||||
registerResponse, err := client.RegisterPayment(ctx.Context, &arkv1.RegisterPaymentRequest{
|
registerResponse, err := client.RegisterPayment(ctx.Context, &arkv1.RegisterPaymentRequest{
|
||||||
Inputs: inputs,
|
Inputs: inputs,
|
||||||
|
EphemeralPubkey: &pubkey,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -102,6 +112,7 @@ func collaborativeRedeem(
|
|||||||
selectedCoins,
|
selectedCoins,
|
||||||
secKey,
|
secKey,
|
||||||
receivers,
|
receivers,
|
||||||
|
ephemeralKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package bitcointree
|
package bitcointree
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -12,20 +14,45 @@ import (
|
|||||||
"github.com/btcsuite/btcd/btcutil/psbt"
|
"github.com/btcsuite/btcd/btcutil/psbt"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/btcsuite/btcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrCongestionTreeNotSet = errors.New("congestion tree not set")
|
ErrCongestionTreeNotSet = errors.New("congestion tree not set")
|
||||||
ErrAggregateKeyNotSet = errors.New("aggregate key not set")
|
ErrAggregateKeyNotSet = errors.New("aggregate key not set")
|
||||||
|
|
||||||
|
columnSeparator = byte('|')
|
||||||
|
rowSeparator = byte('/')
|
||||||
)
|
)
|
||||||
|
|
||||||
type TreeNonces [][][66]byte // public nonces
|
type Musig2Nonce struct {
|
||||||
|
PubNonce [66]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Musig2Nonce) Encode(w io.Writer) error {
|
||||||
|
_, err := w.Write(n.PubNonce[:])
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Musig2Nonce) Decode(r io.Reader) error {
|
||||||
|
bytes := make([]byte, 66)
|
||||||
|
_, err := r.Read(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
n.PubNonce = [66]byte(bytes)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type TreeNonces [][]*Musig2Nonce // public nonces
|
||||||
type TreePartialSigs [][]*musig2.PartialSignature
|
type TreePartialSigs [][]*musig2.PartialSignature
|
||||||
|
|
||||||
type SignerSession interface {
|
type SignerSession interface {
|
||||||
GetNonces() (TreeNonces, error) // generate of return cached nonce for this session
|
GetNonces() (TreeNonces, error) // generate tree nonces for this session
|
||||||
SetKeys([]*btcec.PublicKey, TreeNonces) error // set the keys for this session (with the combined nonces)
|
SetKeys([]*btcec.PublicKey) error // set the cosigner public keys for this session
|
||||||
Sign() (TreePartialSigs, error) // sign the tree
|
SetAggregatedNonces(TreeNonces) error // set the aggregated nonces
|
||||||
|
Sign() (TreePartialSigs, error) // sign the tree
|
||||||
}
|
}
|
||||||
|
|
||||||
type CoordinatorSession interface {
|
type CoordinatorSession interface {
|
||||||
@@ -36,6 +63,34 @@ type CoordinatorSession interface {
|
|||||||
SignTree() (tree.CongestionTree, error)
|
SignTree() (tree.CongestionTree, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n TreeNonces) Encode(w io.Writer) error {
|
||||||
|
matrix, err := encodeMatrix(n)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = w.Write(matrix)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeNonces(r io.Reader) (TreeNonces, error) {
|
||||||
|
return decodeMatrix(func() *Musig2Nonce { return new(Musig2Nonce) }, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s TreePartialSigs) Encode(w io.Writer) error {
|
||||||
|
matrix, err := encodeMatrix(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = w.Write(matrix)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeSignatures(r io.Reader) (TreePartialSigs, error) {
|
||||||
|
return decodeMatrix(func() *musig2.PartialSignature { return new(musig2.PartialSignature) }, r)
|
||||||
|
}
|
||||||
|
|
||||||
func AggregateKeys(
|
func AggregateKeys(
|
||||||
pubkeys []*btcec.PublicKey,
|
pubkeys []*btcec.PublicKey,
|
||||||
scriptRoot []byte,
|
scriptRoot []byte,
|
||||||
@@ -100,62 +155,6 @@ func ValidateTreeSigs(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n TreeNonces) Decode(r io.Reader, matrixFormat []int) error {
|
|
||||||
for i := 0; i < len(matrixFormat); i++ {
|
|
||||||
for j := 0; j < matrixFormat[i]; j++ {
|
|
||||||
// read 66 bytes
|
|
||||||
nonce := make([]byte, 66)
|
|
||||||
_, err := r.Read(nonce)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
n[i][j] = [66]byte(nonce)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n TreeNonces) Encode(w io.Writer) error {
|
|
||||||
for i := 0; i < len(n); i++ {
|
|
||||||
for j := 0; j < len(n[i]); j++ {
|
|
||||||
nonce := n[i][j][:]
|
|
||||||
_, err := w.Write(nonce)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n TreePartialSigs) Decode(r io.Reader, matrixFormat []int) error {
|
|
||||||
for i := 0; i < len(matrixFormat); i++ {
|
|
||||||
for j := 0; j < matrixFormat[i]; j++ {
|
|
||||||
sig := &musig2.PartialSignature{}
|
|
||||||
if err := sig.Decode(r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n TreePartialSigs) Encode(w io.Writer) error {
|
|
||||||
for i := 0; i < len(n); i++ {
|
|
||||||
for j := 0; j < len(n[i]); j++ {
|
|
||||||
if err := n[i][j].Encode(w); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTreeSignerSession(
|
func NewTreeSignerSession(
|
||||||
signer *btcec.PrivateKey,
|
signer *btcec.PrivateKey,
|
||||||
congestionTree tree.CongestionTree,
|
congestionTree tree.CongestionTree,
|
||||||
@@ -221,9 +220,9 @@ func (t *treeSignerSession) GetNonces() (TreeNonces, error) {
|
|||||||
nonces := make(TreeNonces, 0)
|
nonces := make(TreeNonces, 0)
|
||||||
|
|
||||||
for _, level := range t.myNonces {
|
for _, level := range t.myNonces {
|
||||||
levelNonces := make([][66]byte, 0)
|
levelNonces := make([]*Musig2Nonce, 0)
|
||||||
for _, nonce := range level {
|
for _, nonce := range level {
|
||||||
levelNonces = append(levelNonces, nonce.PubNonce)
|
levelNonces = append(levelNonces, &Musig2Nonce{nonce.PubNonce})
|
||||||
}
|
}
|
||||||
nonces = append(nonces, levelNonces)
|
nonces = append(nonces, levelNonces)
|
||||||
}
|
}
|
||||||
@@ -231,15 +230,11 @@ func (t *treeSignerSession) GetNonces() (TreeNonces, error) {
|
|||||||
return nonces, nil
|
return nonces, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *treeSignerSession) SetKeys(keys []*btcec.PublicKey, nonces TreeNonces) error {
|
func (t *treeSignerSession) SetKeys(keys []*btcec.PublicKey) error {
|
||||||
if t.keys != nil {
|
if t.keys != nil {
|
||||||
return errors.New("keys already set")
|
return errors.New("keys already set")
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.aggregateNonces != nil {
|
|
||||||
return errors.New("nonces already set")
|
|
||||||
}
|
|
||||||
|
|
||||||
aggregateKey, err := AggregateKeys(keys, t.scriptRoot)
|
aggregateKey, err := AggregateKeys(keys, t.scriptRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -251,12 +246,20 @@ func (t *treeSignerSession) SetKeys(keys []*btcec.PublicKey, nonces TreeNonces)
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.prevoutFetcher = prevoutFetcher
|
t.prevoutFetcher = prevoutFetcher
|
||||||
t.aggregateNonces = nonces
|
|
||||||
t.keys = keys
|
t.keys = keys
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *treeSignerSession) SetAggregatedNonces(nonces TreeNonces) error {
|
||||||
|
if t.aggregateNonces != nil {
|
||||||
|
return errors.New("nonces already set")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.aggregateNonces = nonces
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t *treeSignerSession) Sign() (TreePartialSigs, error) {
|
func (t *treeSignerSession) Sign() (TreePartialSigs, error) {
|
||||||
if t.tree == nil {
|
if t.tree == nil {
|
||||||
return nil, ErrCongestionTreeNotSet
|
return nil, ErrCongestionTreeNotSet
|
||||||
@@ -313,7 +316,7 @@ func (t *treeSignerSession) signPartial(partialTx *psbt.Packet, posx int, posy i
|
|||||||
}
|
}
|
||||||
|
|
||||||
return musig2.Sign(
|
return musig2.Sign(
|
||||||
myNonce.SecNonce, seckey, aggregatedNonce, t.keys, [32]byte(message),
|
myNonce.SecNonce, seckey, aggregatedNonce.PubNonce, t.keys, [32]byte(message),
|
||||||
musig2.WithSortedKeys(), musig2.WithTaprootSignTweak(t.scriptRoot),
|
musig2.WithSortedKeys(), musig2.WithTaprootSignTweak(t.scriptRoot),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -390,12 +393,11 @@ func (t *treeCoordinatorSession) AggregateNonces() (TreeNonces, error) {
|
|||||||
aggregatedNonces := make(TreeNonces, 0)
|
aggregatedNonces := make(TreeNonces, 0)
|
||||||
|
|
||||||
for i, level := range t.tree {
|
for i, level := range t.tree {
|
||||||
levelNonces := make([][66]byte, 0)
|
levelNonces := make([]*Musig2Nonce, 0)
|
||||||
for j := range level {
|
for j := range level {
|
||||||
|
|
||||||
nonces := make([][66]byte, 0)
|
nonces := make([][66]byte, 0)
|
||||||
for _, n := range t.nonces {
|
for _, n := range t.nonces {
|
||||||
nonces = append(nonces, n[i][j])
|
nonces = append(nonces, n[i][j].PubNonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
aggregatedNonce, err := musig2.AggregateNonces(nonces)
|
aggregatedNonce, err := musig2.AggregateNonces(nonces)
|
||||||
@@ -403,7 +405,7 @@ func (t *treeCoordinatorSession) AggregateNonces() (TreeNonces, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
levelNonces = append(levelNonces, aggregatedNonce)
|
levelNonces = append(levelNonces, &Musig2Nonce{aggregatedNonce})
|
||||||
}
|
}
|
||||||
|
|
||||||
aggregatedNonces = append(aggregatedNonces, levelNonces)
|
aggregatedNonces = append(aggregatedNonces, levelNonces)
|
||||||
@@ -414,12 +416,17 @@ func (t *treeCoordinatorSession) AggregateNonces() (TreeNonces, error) {
|
|||||||
|
|
||||||
// SignTree implements CoordinatorSession.
|
// SignTree implements CoordinatorSession.
|
||||||
func (t *treeCoordinatorSession) SignTree() (tree.CongestionTree, error) {
|
func (t *treeCoordinatorSession) SignTree() (tree.CongestionTree, error) {
|
||||||
|
var missingSigs int
|
||||||
for _, sig := range t.sigs {
|
for _, sig := range t.sigs {
|
||||||
if sig == nil {
|
if sig == nil {
|
||||||
return nil, errors.New("signatures not set")
|
missingSigs++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if missingSigs > 0 {
|
||||||
|
return nil, fmt.Errorf("missing %d signature(s)", missingSigs)
|
||||||
|
}
|
||||||
|
|
||||||
aggregatedKey, err := AggregateKeys(t.keys, t.scriptRoot)
|
aggregatedKey, err := AggregateKeys(t.keys, t.scriptRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -432,9 +439,18 @@ func (t *treeCoordinatorSession) SignTree() (tree.CongestionTree, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var combinedNonce *secp256k1.PublicKey
|
||||||
sigs := make([]*musig2.PartialSignature, 0)
|
sigs := make([]*musig2.PartialSignature, 0)
|
||||||
for _, sig := range t.sigs {
|
for _, sig := range t.sigs {
|
||||||
sigs = append(sigs, sig[i][j])
|
s := sig[i][j]
|
||||||
|
if s.R != nil {
|
||||||
|
combinedNonce = s.R
|
||||||
|
}
|
||||||
|
sigs = append(sigs, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
if combinedNonce == nil {
|
||||||
|
return nil, errors.New("missing combined nonce")
|
||||||
}
|
}
|
||||||
|
|
||||||
inputFetcher := t.prevoutFetcher(partialTx)
|
inputFetcher := t.prevoutFetcher(partialTx)
|
||||||
@@ -448,7 +464,7 @@ func (t *treeCoordinatorSession) SignTree() (tree.CongestionTree, error) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
combinedSig := musig2.CombineSigs(
|
combinedSig := musig2.CombineSigs(
|
||||||
sigs[0].R, sigs,
|
combinedNonce, sigs,
|
||||||
musig2.WithTaprootTweakedCombine([32]byte(message), t.keys, t.scriptRoot, true),
|
musig2.WithTaprootTweakedCombine([32]byte(message), t.keys, t.scriptRoot, true),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -507,3 +523,71 @@ type treePrevOutFetcher struct {
|
|||||||
func (f *treePrevOutFetcher) FetchPrevOutput(wire.OutPoint) *wire.TxOut {
|
func (f *treePrevOutFetcher) FetchPrevOutput(wire.OutPoint) *wire.TxOut {
|
||||||
return f.prevout
|
return f.prevout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type writable interface {
|
||||||
|
Encode(w io.Writer) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type readable interface {
|
||||||
|
Decode(r io.Reader) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeMatrix encode a matrix of serializable objects into a byte stream
|
||||||
|
func encodeMatrix[T writable](matrix [][]T) ([]byte, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
for _, row := range matrix {
|
||||||
|
for _, cell := range row {
|
||||||
|
if err := buf.WriteByte(columnSeparator); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cell.Encode(&buf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := buf.WriteByte(rowSeparator); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeMatrix decode a byte stream into a matrix of serializable objects
|
||||||
|
func decodeMatrix[T readable](factory func() T, data io.Reader) ([][]T, error) {
|
||||||
|
matrix := make([][]T, 0)
|
||||||
|
row := make([]T, 0)
|
||||||
|
|
||||||
|
for {
|
||||||
|
separator := make([]byte, 1)
|
||||||
|
|
||||||
|
if _, err := data.Read(separator); err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := separator[0]
|
||||||
|
|
||||||
|
if b == rowSeparator {
|
||||||
|
matrix = append(matrix, row)
|
||||||
|
row = make([]T, 0)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cell := factory()
|
||||||
|
|
||||||
|
if err := cell.Decode(data); err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
row = append(row, cell)
|
||||||
|
}
|
||||||
|
|
||||||
|
return matrix, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package bitcointree_test
|
package bitcointree_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -85,6 +87,31 @@ func TestRoundTripSignTree(t *testing.T) {
|
|||||||
aspNonces, err := aspSession.GetNonces()
|
aspNonces, err := aspSession.GetNonces()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
s := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
err = aspNonces[0][0].Encode(s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
bitcointreeNonce := new(bitcointree.Musig2Nonce)
|
||||||
|
err = bitcointreeNonce.Decode(s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, aspNonces[0][0], bitcointreeNonce)
|
||||||
|
|
||||||
|
var serializedNonces bytes.Buffer
|
||||||
|
|
||||||
|
err = aspNonces.Encode(&serializedNonces)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
decodedNonces, err := bitcointree.DecodeNonces(&serializedNonces)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for i, nonces := range aspNonces {
|
||||||
|
for j, nonce := range nonces {
|
||||||
|
require.Equal(t, nonce.PubNonce, decodedNonces[i][j].PubNonce, fmt.Sprintf("matrix nonce not equal at index i: %d, j: %d", i, j))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = aspCoordinator.AddNonce(alice.PubKey(), aliceNonces)
|
err = aspCoordinator.AddNonce(alice.PubKey(), aliceNonces)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -101,18 +128,30 @@ func TestRoundTripSignTree(t *testing.T) {
|
|||||||
|
|
||||||
err = aliceSession.SetKeys(
|
err = aliceSession.SetKeys(
|
||||||
cosigners,
|
cosigners,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = aliceSession.SetAggregatedNonces(
|
||||||
aggregatedNonce,
|
aggregatedNonce,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = bobSession.SetKeys(
|
err = bobSession.SetKeys(
|
||||||
cosigners,
|
cosigners,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = bobSession.SetAggregatedNonces(
|
||||||
aggregatedNonce,
|
aggregatedNonce,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = aspSession.SetKeys(
|
err = aspSession.SetKeys(
|
||||||
cosigners,
|
cosigners,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = aspSession.SetAggregatedNonces(
|
||||||
aggregatedNonce,
|
aggregatedNonce,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -126,6 +165,22 @@ func TestRoundTripSignTree(t *testing.T) {
|
|||||||
aspSig, err := aspSession.Sign()
|
aspSig, err := aspSession.Sign()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// check that the sigs are serializable
|
||||||
|
|
||||||
|
serializedSigs := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
err = aspSig.Encode(serializedSigs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
decodedSigs, err := bitcointree.DecodeSignatures(serializedSigs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for i, sigs := range aspSig {
|
||||||
|
for j, sig := range sigs {
|
||||||
|
require.Equal(t, sig.S, decodedSigs[i][j].S, fmt.Sprintf("matrix sig not equal at index i: %d, j: %d", i, j))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// coordinator receives the signatures and combines them
|
// coordinator receives the signatures and combines them
|
||||||
err = aspCoordinator.AddSig(alice.PubKey(), aliceSig)
|
err = aspCoordinator.AddSig(alice.PubKey(), aliceSig)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
## genrest: compiles rest client from stub with https://github.com/go-swagger/go-swagger
|
## genrest: compiles rest client from stub with https://github.com/go-swagger/go-swagger
|
||||||
genrest:
|
genrest:
|
||||||
@echo "Generating rest client from stub..."
|
@echo "Generating rest client from stub..."
|
||||||
@swagger generate client -f ../../server/api-spec/openapi/swagger/ark/v1/service.swagger.json -t ./client/rest/service --client-package=arkservice
|
@swagger generate client -f ../../api-spec/openapi/swagger/ark/v1/service.swagger.json -t ./client/rest/service --client-package=arkservice
|
||||||
|
|
||||||
## test: runs unit tests
|
## test: runs unit tests
|
||||||
test:
|
test:
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ark-network/ark/common/bitcointree"
|
||||||
"github.com/ark-network/ark/common/tree"
|
"github.com/ark-network/ark/common/tree"
|
||||||
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -25,7 +27,7 @@ type ASPClient interface {
|
|||||||
ctx context.Context, tx, userPubkey string, congestionTree tree.CongestionTree,
|
ctx context.Context, tx, userPubkey string, congestionTree tree.CongestionTree,
|
||||||
) error
|
) error
|
||||||
RegisterPayment(
|
RegisterPayment(
|
||||||
ctx context.Context, inputs []VtxoKey,
|
ctx context.Context, inputs []VtxoKey, ephemeralPublicKey string,
|
||||||
) (string, error)
|
) (string, error)
|
||||||
ClaimPayment(
|
ClaimPayment(
|
||||||
ctx context.Context, paymentID string, outputs []Output,
|
ctx context.Context, paymentID string, outputs []Output,
|
||||||
@@ -33,7 +35,7 @@ type ASPClient interface {
|
|||||||
GetEventStream(
|
GetEventStream(
|
||||||
ctx context.Context, paymentID string,
|
ctx context.Context, paymentID string,
|
||||||
) (<-chan RoundEventChannel, error)
|
) (<-chan RoundEventChannel, error)
|
||||||
Ping(ctx context.Context, paymentID string) (*RoundFinalizationEvent, error)
|
Ping(ctx context.Context, paymentID string) (RoundEvent, error)
|
||||||
FinalizePayment(
|
FinalizePayment(
|
||||||
ctx context.Context, signedForfeitTxs []string,
|
ctx context.Context, signedForfeitTxs []string,
|
||||||
) error
|
) error
|
||||||
@@ -43,6 +45,12 @@ type ASPClient interface {
|
|||||||
CompletePayment(
|
CompletePayment(
|
||||||
ctx context.Context, signedRedeemTx string, signedUnconditionalForfeitTxs []string,
|
ctx context.Context, signedRedeemTx string, signedUnconditionalForfeitTxs []string,
|
||||||
) error
|
) error
|
||||||
|
SendTreeNonces(
|
||||||
|
ctx context.Context, roundID, cosignerPubkey string, nonces bitcointree.TreeNonces,
|
||||||
|
) error
|
||||||
|
SendTreeSignatures(
|
||||||
|
ctx context.Context, roundID, cosignerPubkey string, signatures bitcointree.TreePartialSigs,
|
||||||
|
) error
|
||||||
Close()
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,3 +147,18 @@ type RoundFailedEvent struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e RoundFailedEvent) isRoundEvent() {}
|
func (e RoundFailedEvent) isRoundEvent() {}
|
||||||
|
|
||||||
|
type RoundSigningStartedEvent struct {
|
||||||
|
ID string
|
||||||
|
UnsignedTree tree.CongestionTree
|
||||||
|
CosignersPublicKeys []*secp256k1.PublicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e RoundSigningStartedEvent) isRoundEvent() {}
|
||||||
|
|
||||||
|
type RoundSigningNoncesGeneratedEvent struct {
|
||||||
|
ID string
|
||||||
|
Nonces bitcointree.TreeNonces
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e RoundSigningNoncesGeneratedEvent) isRoundEvent() {}
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
package grpcclient
|
package grpcclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
||||||
|
"github.com/ark-network/ark/common/bitcointree"
|
||||||
"github.com/ark-network/ark/common/tree"
|
"github.com/ark-network/ark/common/tree"
|
||||||
"github.com/ark-network/ark/pkg/client-sdk/client"
|
"github.com/ark-network/ark/pkg/client-sdk/client"
|
||||||
"github.com/ark-network/ark/pkg/client-sdk/internal/utils"
|
"github.com/ark-network/ark/pkg/client-sdk/internal/utils"
|
||||||
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
@@ -73,7 +77,13 @@ func (a *grpcClient) GetEventStream(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
a.eventsCh <- client.RoundEventChannel{Event: event{resp}.toRoundEvent()}
|
ev, err := event{resp}.toRoundEvent()
|
||||||
|
if err != nil {
|
||||||
|
a.eventsCh <- client.RoundEventChannel{Err: err}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
a.eventsCh <- client.RoundEventChannel{Event: ev}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -146,11 +156,15 @@ func (a *grpcClient) Onboard(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *grpcClient) RegisterPayment(
|
func (a *grpcClient) RegisterPayment(
|
||||||
ctx context.Context, inputs []client.VtxoKey,
|
ctx context.Context, inputs []client.VtxoKey, ephemeralPublicKey string,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
req := &arkv1.RegisterPaymentRequest{
|
req := &arkv1.RegisterPaymentRequest{
|
||||||
Inputs: ins(inputs).toProto(),
|
Inputs: ins(inputs).toProto(),
|
||||||
}
|
}
|
||||||
|
if len(ephemeralPublicKey) > 0 {
|
||||||
|
req.EphemeralPubkey = &ephemeralPublicKey
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := a.svc.RegisterPayment(ctx, req)
|
resp, err := a.svc.RegisterPayment(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -171,7 +185,7 @@ func (a *grpcClient) ClaimPayment(
|
|||||||
|
|
||||||
func (a *grpcClient) Ping(
|
func (a *grpcClient) Ping(
|
||||||
ctx context.Context, paymentID string,
|
ctx context.Context, paymentID string,
|
||||||
) (*client.RoundFinalizationEvent, error) {
|
) (client.RoundEvent, error) {
|
||||||
req := &arkv1.PingRequest{
|
req := &arkv1.PingRequest{
|
||||||
PaymentId: paymentID,
|
PaymentId: paymentID,
|
||||||
}
|
}
|
||||||
@@ -179,14 +193,8 @@ func (a *grpcClient) Ping(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
event := resp.GetEvent()
|
|
||||||
return &client.RoundFinalizationEvent{
|
return event{resp}.toRoundEvent()
|
||||||
ID: event.GetId(),
|
|
||||||
Tx: event.GetPoolTx(),
|
|
||||||
ForfeitTxs: event.GetForfeitTxs(),
|
|
||||||
Tree: treeFromProto{event.GetCongestionTree()}.parse(),
|
|
||||||
Connectors: event.GetConnectors(),
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *grpcClient) FinalizePayment(
|
func (a *grpcClient) FinalizePayment(
|
||||||
@@ -252,6 +260,54 @@ func (a *grpcClient) GetRoundByID(
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *grpcClient) SendTreeNonces(
|
||||||
|
ctx context.Context, roundID, cosignerPubkey string, nonces bitcointree.TreeNonces,
|
||||||
|
) error {
|
||||||
|
var nonceBuffer bytes.Buffer
|
||||||
|
|
||||||
|
if err := nonces.Encode(&nonceBuffer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedNonces := hex.EncodeToString(nonceBuffer.Bytes())
|
||||||
|
|
||||||
|
req := &arkv1.SendTreeNoncesRequest{
|
||||||
|
RoundId: roundID,
|
||||||
|
PublicKey: cosignerPubkey,
|
||||||
|
TreeNonces: serializedNonces,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := a.svc.SendTreeNonces(ctx, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *grpcClient) SendTreeSignatures(
|
||||||
|
ctx context.Context, roundID, cosignerPubkey string, signatures bitcointree.TreePartialSigs,
|
||||||
|
) error {
|
||||||
|
var sigsBuffer bytes.Buffer
|
||||||
|
|
||||||
|
if err := signatures.Encode(&sigsBuffer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedSigs := hex.EncodeToString(sigsBuffer.Bytes())
|
||||||
|
|
||||||
|
req := &arkv1.SendTreeSignaturesRequest{
|
||||||
|
RoundId: roundID,
|
||||||
|
PublicKey: cosignerPubkey,
|
||||||
|
TreeSignatures: serializedSigs,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := a.svc.SendTreeSignatures(ctx, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type out client.Output
|
type out client.Output
|
||||||
|
|
||||||
func (o out) toProto() *arkv1.Output {
|
func (o out) toProto() *arkv1.Output {
|
||||||
@@ -271,16 +327,25 @@ func (o outs) toProto() []*arkv1.Output {
|
|||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
type event struct {
|
// wrapper for GetEventStreamResponse and PingResponse
|
||||||
*arkv1.GetEventStreamResponse
|
type eventResponse interface {
|
||||||
|
GetRoundFailed() *arkv1.RoundFailed
|
||||||
|
GetRoundFinalization() *arkv1.RoundFinalizationEvent
|
||||||
|
GetRoundFinalized() *arkv1.RoundFinalizedEvent
|
||||||
|
GetRoundSigning() *arkv1.RoundSigningEvent
|
||||||
|
GetRoundSigningNoncesGenerated() *arkv1.RoundSigningNoncesGeneratedEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e event) toRoundEvent() client.RoundEvent {
|
type event struct {
|
||||||
|
eventResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e event) toRoundEvent() (client.RoundEvent, error) {
|
||||||
if ee := e.GetRoundFailed(); ee != nil {
|
if ee := e.GetRoundFailed(); ee != nil {
|
||||||
return client.RoundFailedEvent{
|
return client.RoundFailedEvent{
|
||||||
ID: ee.GetId(),
|
ID: ee.GetId(),
|
||||||
Reason: ee.GetReason(),
|
Reason: ee.GetReason(),
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
if ee := e.GetRoundFinalization(); ee != nil {
|
if ee := e.GetRoundFinalization(); ee != nil {
|
||||||
tree := treeFromProto{ee.GetCongestionTree()}.parse()
|
tree := treeFromProto{ee.GetCongestionTree()}.parse()
|
||||||
@@ -290,13 +355,49 @@ func (e event) toRoundEvent() client.RoundEvent {
|
|||||||
ForfeitTxs: ee.GetForfeitTxs(),
|
ForfeitTxs: ee.GetForfeitTxs(),
|
||||||
Tree: tree,
|
Tree: tree,
|
||||||
Connectors: ee.GetConnectors(),
|
Connectors: ee.GetConnectors(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ee := e.GetRoundFinalized(); ee != nil {
|
||||||
|
return client.RoundFinalizedEvent{
|
||||||
|
ID: ee.GetId(),
|
||||||
|
Txid: ee.GetPoolTxid(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ee := e.GetRoundSigning(); ee != nil {
|
||||||
|
pubkeys := make([]*secp256k1.PublicKey, 0, len(ee.GetCosignersPubkeys()))
|
||||||
|
for _, pubkey := range ee.GetCosignersPubkeys() {
|
||||||
|
p, err := hex.DecodeString(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pk, err := secp256k1.ParsePubKey(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pubkeys = append(pubkeys, pk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return client.RoundSigningStartedEvent{
|
||||||
|
ID: ee.GetId(),
|
||||||
|
UnsignedTree: treeFromProto{ee.GetUnsignedTree()}.parse(),
|
||||||
|
CosignersPublicKeys: pubkeys,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
ee := e.GetRoundFinalized()
|
|
||||||
return client.RoundFinalizedEvent{
|
if ee := e.GetRoundSigningNoncesGenerated(); ee != nil {
|
||||||
ID: ee.GetId(),
|
nonces, err := bitcointree.DecodeNonces(hex.NewDecoder(strings.NewReader(ee.GetTreeNonces())))
|
||||||
Txid: ee.GetPoolTxid(),
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return client.RoundSigningNoncesGeneratedEvent{
|
||||||
|
ID: ee.GetId(),
|
||||||
|
Nonces: nonces,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("unknown event")
|
||||||
}
|
}
|
||||||
|
|
||||||
type vtxo struct {
|
type vtxo struct {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package restclient
|
package restclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -9,16 +11,16 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
||||||
|
"github.com/ark-network/ark/common/bitcointree"
|
||||||
"github.com/ark-network/ark/common/tree"
|
"github.com/ark-network/ark/common/tree"
|
||||||
"github.com/ark-network/ark/pkg/client-sdk/client"
|
"github.com/ark-network/ark/pkg/client-sdk/client"
|
||||||
"github.com/ark-network/ark/pkg/client-sdk/client/rest/service/arkservice"
|
"github.com/ark-network/ark/pkg/client-sdk/client/rest/service/arkservice"
|
||||||
"github.com/ark-network/ark/pkg/client-sdk/client/rest/service/arkservice/ark_service"
|
"github.com/ark-network/ark/pkg/client-sdk/client/rest/service/arkservice/ark_service"
|
||||||
"github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models"
|
"github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models"
|
||||||
"github.com/ark-network/ark/pkg/client-sdk/internal/utils"
|
"github.com/ark-network/ark/pkg/client-sdk/internal/utils"
|
||||||
"github.com/btcsuite/btcd/btcutil/psbt"
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
httptransport "github.com/go-openapi/runtime/client"
|
httptransport "github.com/go-openapi/runtime/client"
|
||||||
"github.com/go-openapi/strfmt"
|
"github.com/go-openapi/strfmt"
|
||||||
"github.com/vulpemventures/go-elements/psetv2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type restClient struct {
|
type restClient struct {
|
||||||
@@ -71,39 +73,7 @@ func (a *restClient) GetEventStream(
|
|||||||
|
|
||||||
if event != nil {
|
if event != nil {
|
||||||
a.eventsCh <- client.RoundEventChannel{
|
a.eventsCh <- client.RoundEventChannel{
|
||||||
Event: *event,
|
Event: event,
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
roundID := event.ID
|
|
||||||
round, err := a.GetRoundByID(ctx, roundID)
|
|
||||||
if err != nil {
|
|
||||||
a.eventsCh <- client.RoundEventChannel{
|
|
||||||
Err: err,
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if round.Stage == client.RoundStageFinalized {
|
|
||||||
a.eventsCh <- client.RoundEventChannel{
|
|
||||||
Event: client.RoundFinalizedEvent{
|
|
||||||
ID: roundID,
|
|
||||||
Txid: getTxid(round.Tx),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if round.Stage == client.RoundStageFailed {
|
|
||||||
a.eventsCh <- client.RoundEventChannel{
|
|
||||||
Event: client.RoundFailedEvent{
|
|
||||||
ID: roundID,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +256,7 @@ func (a *restClient) Onboard(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *restClient) RegisterPayment(
|
func (a *restClient) RegisterPayment(
|
||||||
ctx context.Context, inputs []client.VtxoKey,
|
ctx context.Context, inputs []client.VtxoKey, ephemeralPublicKey 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 {
|
||||||
@@ -295,11 +265,15 @@ func (a *restClient) RegisterPayment(
|
|||||||
Vout: int64(i.VOut),
|
Vout: int64(i.VOut),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
body := models.V1RegisterPaymentRequest{
|
body := &models.V1RegisterPaymentRequest{
|
||||||
Inputs: ins,
|
Inputs: ins,
|
||||||
}
|
}
|
||||||
|
if len(ephemeralPublicKey) > 0 {
|
||||||
|
body.EphemeralPubkey = ephemeralPublicKey
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := a.svc.ArkServiceRegisterPayment(
|
resp, err := a.svc.ArkServiceRegisterPayment(
|
||||||
ark_service.NewArkServiceRegisterPaymentParams().WithBody(&body),
|
ark_service.NewArkServiceRegisterPaymentParams().WithBody(body),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -331,7 +305,7 @@ func (a *restClient) ClaimPayment(
|
|||||||
|
|
||||||
func (a *restClient) Ping(
|
func (a *restClient) Ping(
|
||||||
ctx context.Context, paymentID string,
|
ctx context.Context, paymentID string,
|
||||||
) (*client.RoundFinalizationEvent, error) {
|
) (client.RoundEvent, error) {
|
||||||
r := ark_service.NewArkServicePingParams()
|
r := ark_service.NewArkServicePingParams()
|
||||||
r.SetPaymentID(paymentID)
|
r.SetPaymentID(paymentID)
|
||||||
resp, err := a.svc.ArkServicePing(r)
|
resp, err := a.svc.ArkServicePing(r)
|
||||||
@@ -339,18 +313,65 @@ func (a *restClient) Ping(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var event *client.RoundFinalizationEvent
|
payload := resp.Payload
|
||||||
if resp.Payload.Event != nil {
|
|
||||||
event = &client.RoundFinalizationEvent{
|
if e := payload.RoundFailed; e != nil {
|
||||||
ID: resp.Payload.Event.ID,
|
return client.RoundFailedEvent{
|
||||||
Tx: resp.Payload.Event.PoolTx,
|
ID: e.ID,
|
||||||
ForfeitTxs: resp.Payload.Event.ForfeitTxs,
|
Reason: e.Reason,
|
||||||
Tree: treeFromProto{resp.Payload.Event.CongestionTree}.parse(),
|
}, nil
|
||||||
Connectors: resp.Payload.Event.Connectors,
|
}
|
||||||
}
|
if e := payload.RoundFinalization; e != nil {
|
||||||
|
tree := treeFromProto{e.CongestionTree}.parse()
|
||||||
|
return client.RoundFinalizationEvent{
|
||||||
|
ID: e.ID,
|
||||||
|
Tx: e.PoolTx,
|
||||||
|
ForfeitTxs: e.ForfeitTxs,
|
||||||
|
Tree: tree,
|
||||||
|
Connectors: e.Connectors,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return event, nil
|
if e := payload.RoundFinalized; e != nil {
|
||||||
|
return client.RoundFinalizedEvent{
|
||||||
|
ID: e.ID,
|
||||||
|
Txid: e.PoolTxid,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if e := payload.RoundSigning; e != nil {
|
||||||
|
pubkeys := make([]*secp256k1.PublicKey, 0, len(e.CosignersPubkeys))
|
||||||
|
for _, pubkey := range e.CosignersPubkeys {
|
||||||
|
p, err := hex.DecodeString(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pk, err := secp256k1.ParsePubKey(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pubkeys = append(pubkeys, pk)
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.RoundSigningStartedEvent{
|
||||||
|
ID: e.ID,
|
||||||
|
UnsignedTree: treeFromProto{e.UnsignedTree}.parse(),
|
||||||
|
CosignersPublicKeys: pubkeys,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if e := payload.RoundSigningNoncesGenerated; e != nil {
|
||||||
|
nonces, err := bitcointree.DecodeNonces(hex.NewDecoder(strings.NewReader(e.TreeNonces)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return client.RoundSigningNoncesGeneratedEvent{
|
||||||
|
ID: e.ID,
|
||||||
|
Nonces: nonces,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *restClient) FinalizePayment(
|
func (a *restClient) FinalizePayment(
|
||||||
@@ -454,6 +475,58 @@ func (a *restClient) GetRoundByID(
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *restClient) SendTreeNonces(
|
||||||
|
ctx context.Context, roundID, cosignerPubkey string, nonces bitcointree.TreeNonces,
|
||||||
|
) error {
|
||||||
|
var nonceBuffer bytes.Buffer
|
||||||
|
|
||||||
|
if err := nonces.Encode(&nonceBuffer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedNonces := hex.EncodeToString(nonceBuffer.Bytes())
|
||||||
|
|
||||||
|
body := &models.V1SendTreeNoncesRequest{
|
||||||
|
RoundID: roundID,
|
||||||
|
PublicKey: cosignerPubkey,
|
||||||
|
TreeNonces: serializedNonces,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := a.svc.ArkServiceSendTreeNonces(
|
||||||
|
ark_service.NewArkServiceSendTreeNoncesParams().WithBody(body),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *restClient) SendTreeSignatures(
|
||||||
|
ctx context.Context, roundID, cosignerPubkey string, signatures bitcointree.TreePartialSigs,
|
||||||
|
) error {
|
||||||
|
var sigsBuffer bytes.Buffer
|
||||||
|
|
||||||
|
if err := signatures.Encode(&sigsBuffer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedSigs := hex.EncodeToString(sigsBuffer.Bytes())
|
||||||
|
|
||||||
|
body := &models.V1SendTreeSignaturesRequest{
|
||||||
|
RoundID: roundID,
|
||||||
|
PublicKey: cosignerPubkey,
|
||||||
|
TreeSignatures: serializedSigs,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := a.svc.ArkServiceSendTreeSignatures(
|
||||||
|
ark_service.NewArkServiceSendTreeSignaturesParams().WithBody(body),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func newRestClient(
|
func newRestClient(
|
||||||
serviceURL string,
|
serviceURL string,
|
||||||
) (ark_service.ClientService, error) {
|
) (ark_service.ClientService, error) {
|
||||||
@@ -551,13 +624,3 @@ func (t treeToProto) parse() *models.V1Tree {
|
|||||||
Levels: levels,
|
Levels: levels,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTxid(tx string) string {
|
|
||||||
if ptx, _ := psetv2.NewPsetFromBase64(tx); ptx != nil {
|
|
||||||
utx, _ := ptx.UnsignedTx()
|
|
||||||
return utx.TxHash().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
ptx, _ := psbt.NewFromRawBytes(strings.NewReader(tx), true)
|
|
||||||
return ptx.UnsignedTx.TxID()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ type ClientService interface {
|
|||||||
|
|
||||||
ArkServiceRegisterPayment(params *ArkServiceRegisterPaymentParams, opts ...ClientOption) (*ArkServiceRegisterPaymentOK, error)
|
ArkServiceRegisterPayment(params *ArkServiceRegisterPaymentParams, opts ...ClientOption) (*ArkServiceRegisterPaymentOK, error)
|
||||||
|
|
||||||
|
ArkServiceSendTreeNonces(params *ArkServiceSendTreeNoncesParams, opts ...ClientOption) (*ArkServiceSendTreeNoncesOK, error)
|
||||||
|
|
||||||
|
ArkServiceSendTreeSignatures(params *ArkServiceSendTreeSignaturesParams, opts ...ClientOption) (*ArkServiceSendTreeSignaturesOK, error)
|
||||||
|
|
||||||
SetTransport(transport runtime.ClientTransport)
|
SetTransport(transport runtime.ClientTransport)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +308,7 @@ func (a *Client) ArkServiceGetInfo(params *ArkServiceGetInfoParams, opts ...Clie
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ArkServiceGetRound ts o d o b t c sign tree rpc
|
ArkServiceGetRound ark service get round API
|
||||||
*/
|
*/
|
||||||
func (a *Client) ArkServiceGetRound(params *ArkServiceGetRoundParams, opts ...ClientOption) (*ArkServiceGetRoundOK, error) {
|
func (a *Client) ArkServiceGetRound(params *ArkServiceGetRoundParams, opts ...ClientOption) (*ArkServiceGetRoundOK, error) {
|
||||||
// TODO: Validate the params before sending
|
// TODO: Validate the params before sending
|
||||||
@@ -525,6 +529,80 @@ func (a *Client) ArkServiceRegisterPayment(params *ArkServiceRegisterPaymentPara
|
|||||||
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
|
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ArkServiceSendTreeNonces ark service send tree nonces API
|
||||||
|
*/
|
||||||
|
func (a *Client) ArkServiceSendTreeNonces(params *ArkServiceSendTreeNoncesParams, opts ...ClientOption) (*ArkServiceSendTreeNoncesOK, error) {
|
||||||
|
// TODO: Validate the params before sending
|
||||||
|
if params == nil {
|
||||||
|
params = NewArkServiceSendTreeNoncesParams()
|
||||||
|
}
|
||||||
|
op := &runtime.ClientOperation{
|
||||||
|
ID: "ArkService_SendTreeNonces",
|
||||||
|
Method: "POST",
|
||||||
|
PathPattern: "/v1/payment/tree/nonces",
|
||||||
|
ProducesMediaTypes: []string{"application/json"},
|
||||||
|
ConsumesMediaTypes: []string{"application/json"},
|
||||||
|
Schemes: []string{"http"},
|
||||||
|
Params: params,
|
||||||
|
Reader: &ArkServiceSendTreeNoncesReader{formats: a.formats},
|
||||||
|
Context: params.Context,
|
||||||
|
Client: params.HTTPClient,
|
||||||
|
}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(op)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.transport.Submit(op)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
success, ok := result.(*ArkServiceSendTreeNoncesOK)
|
||||||
|
if ok {
|
||||||
|
return success, nil
|
||||||
|
}
|
||||||
|
// unexpected success response
|
||||||
|
unexpectedSuccess := result.(*ArkServiceSendTreeNoncesDefault)
|
||||||
|
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ArkServiceSendTreeSignatures ark service send tree signatures API
|
||||||
|
*/
|
||||||
|
func (a *Client) ArkServiceSendTreeSignatures(params *ArkServiceSendTreeSignaturesParams, opts ...ClientOption) (*ArkServiceSendTreeSignaturesOK, error) {
|
||||||
|
// TODO: Validate the params before sending
|
||||||
|
if params == nil {
|
||||||
|
params = NewArkServiceSendTreeSignaturesParams()
|
||||||
|
}
|
||||||
|
op := &runtime.ClientOperation{
|
||||||
|
ID: "ArkService_SendTreeSignatures",
|
||||||
|
Method: "POST",
|
||||||
|
PathPattern: "/v1/payment/tree/signatures",
|
||||||
|
ProducesMediaTypes: []string{"application/json"},
|
||||||
|
ConsumesMediaTypes: []string{"application/json"},
|
||||||
|
Schemes: []string{"http"},
|
||||||
|
Params: params,
|
||||||
|
Reader: &ArkServiceSendTreeSignaturesReader{formats: a.formats},
|
||||||
|
Context: params.Context,
|
||||||
|
Client: params.HTTPClient,
|
||||||
|
}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(op)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.transport.Submit(op)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
success, ok := result.(*ArkServiceSendTreeSignaturesOK)
|
||||||
|
if ok {
|
||||||
|
return success, nil
|
||||||
|
}
|
||||||
|
// unexpected success response
|
||||||
|
unexpectedSuccess := result.(*ArkServiceSendTreeSignaturesDefault)
|
||||||
|
return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code())
|
||||||
|
}
|
||||||
|
|
||||||
// SetTransport changes the transport on the client
|
// SetTransport changes the transport on the client
|
||||||
func (a *Client) SetTransport(transport runtime.ClientTransport) {
|
func (a *Client) SetTransport(transport runtime.ClientTransport) {
|
||||||
a.transport = transport
|
a.transport = transport
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
package ark_service
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-openapi/errors"
|
||||||
|
"github.com/go-openapi/runtime"
|
||||||
|
cr "github.com/go-openapi/runtime/client"
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
|
||||||
|
"github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewArkServiceSendTreeNoncesParams creates a new ArkServiceSendTreeNoncesParams object,
|
||||||
|
// with the default timeout for this client.
|
||||||
|
//
|
||||||
|
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||||
|
//
|
||||||
|
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||||
|
func NewArkServiceSendTreeNoncesParams() *ArkServiceSendTreeNoncesParams {
|
||||||
|
return &ArkServiceSendTreeNoncesParams{
|
||||||
|
timeout: cr.DefaultTimeout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewArkServiceSendTreeNoncesParamsWithTimeout creates a new ArkServiceSendTreeNoncesParams object
|
||||||
|
// with the ability to set a timeout on a request.
|
||||||
|
func NewArkServiceSendTreeNoncesParamsWithTimeout(timeout time.Duration) *ArkServiceSendTreeNoncesParams {
|
||||||
|
return &ArkServiceSendTreeNoncesParams{
|
||||||
|
timeout: timeout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewArkServiceSendTreeNoncesParamsWithContext creates a new ArkServiceSendTreeNoncesParams object
|
||||||
|
// with the ability to set a context for a request.
|
||||||
|
func NewArkServiceSendTreeNoncesParamsWithContext(ctx context.Context) *ArkServiceSendTreeNoncesParams {
|
||||||
|
return &ArkServiceSendTreeNoncesParams{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewArkServiceSendTreeNoncesParamsWithHTTPClient creates a new ArkServiceSendTreeNoncesParams object
|
||||||
|
// with the ability to set a custom HTTPClient for a request.
|
||||||
|
func NewArkServiceSendTreeNoncesParamsWithHTTPClient(client *http.Client) *ArkServiceSendTreeNoncesParams {
|
||||||
|
return &ArkServiceSendTreeNoncesParams{
|
||||||
|
HTTPClient: client,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ArkServiceSendTreeNoncesParams contains all the parameters to send to the API endpoint
|
||||||
|
|
||||||
|
for the ark service send tree nonces operation.
|
||||||
|
|
||||||
|
Typically these are written to a http.Request.
|
||||||
|
*/
|
||||||
|
type ArkServiceSendTreeNoncesParams struct {
|
||||||
|
|
||||||
|
// Body.
|
||||||
|
Body *models.V1SendTreeNoncesRequest
|
||||||
|
|
||||||
|
timeout time.Duration
|
||||||
|
Context context.Context
|
||||||
|
HTTPClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDefaults hydrates default values in the ark service send tree nonces params (not the query body).
|
||||||
|
//
|
||||||
|
// All values with no default are reset to their zero value.
|
||||||
|
func (o *ArkServiceSendTreeNoncesParams) WithDefaults() *ArkServiceSendTreeNoncesParams {
|
||||||
|
o.SetDefaults()
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaults hydrates default values in the ark service send tree nonces params (not the query body).
|
||||||
|
//
|
||||||
|
// All values with no default are reset to their zero value.
|
||||||
|
func (o *ArkServiceSendTreeNoncesParams) SetDefaults() {
|
||||||
|
// no default values defined for this parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTimeout adds the timeout to the ark service send tree nonces params
|
||||||
|
func (o *ArkServiceSendTreeNoncesParams) WithTimeout(timeout time.Duration) *ArkServiceSendTreeNoncesParams {
|
||||||
|
o.SetTimeout(timeout)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTimeout adds the timeout to the ark service send tree nonces params
|
||||||
|
func (o *ArkServiceSendTreeNoncesParams) SetTimeout(timeout time.Duration) {
|
||||||
|
o.timeout = timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithContext adds the context to the ark service send tree nonces params
|
||||||
|
func (o *ArkServiceSendTreeNoncesParams) WithContext(ctx context.Context) *ArkServiceSendTreeNoncesParams {
|
||||||
|
o.SetContext(ctx)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContext adds the context to the ark service send tree nonces params
|
||||||
|
func (o *ArkServiceSendTreeNoncesParams) SetContext(ctx context.Context) {
|
||||||
|
o.Context = ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHTTPClient adds the HTTPClient to the ark service send tree nonces params
|
||||||
|
func (o *ArkServiceSendTreeNoncesParams) WithHTTPClient(client *http.Client) *ArkServiceSendTreeNoncesParams {
|
||||||
|
o.SetHTTPClient(client)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHTTPClient adds the HTTPClient to the ark service send tree nonces params
|
||||||
|
func (o *ArkServiceSendTreeNoncesParams) SetHTTPClient(client *http.Client) {
|
||||||
|
o.HTTPClient = client
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBody adds the body to the ark service send tree nonces params
|
||||||
|
func (o *ArkServiceSendTreeNoncesParams) WithBody(body *models.V1SendTreeNoncesRequest) *ArkServiceSendTreeNoncesParams {
|
||||||
|
o.SetBody(body)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBody adds the body to the ark service send tree nonces params
|
||||||
|
func (o *ArkServiceSendTreeNoncesParams) SetBody(body *models.V1SendTreeNoncesRequest) {
|
||||||
|
o.Body = body
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteToRequest writes these params to a swagger request
|
||||||
|
func (o *ArkServiceSendTreeNoncesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
|
||||||
|
|
||||||
|
if err := r.SetTimeout(o.timeout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var res []error
|
||||||
|
if o.Body != nil {
|
||||||
|
if err := r.SetBodyParam(o.Body); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) > 0 {
|
||||||
|
return errors.CompositeValidationError(res...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
package ark_service
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/go-openapi/runtime"
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
|
||||||
|
"github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ArkServiceSendTreeNoncesReader is a Reader for the ArkServiceSendTreeNonces structure.
|
||||||
|
type ArkServiceSendTreeNoncesReader struct {
|
||||||
|
formats strfmt.Registry
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadResponse reads a server response into the received o.
|
||||||
|
func (o *ArkServiceSendTreeNoncesReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||||
|
switch response.Code() {
|
||||||
|
case 200:
|
||||||
|
result := NewArkServiceSendTreeNoncesOK()
|
||||||
|
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
default:
|
||||||
|
result := NewArkServiceSendTreeNoncesDefault(response.Code())
|
||||||
|
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if response.Code()/100 == 2 {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
return nil, result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewArkServiceSendTreeNoncesOK creates a ArkServiceSendTreeNoncesOK with default headers values
|
||||||
|
func NewArkServiceSendTreeNoncesOK() *ArkServiceSendTreeNoncesOK {
|
||||||
|
return &ArkServiceSendTreeNoncesOK{}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ArkServiceSendTreeNoncesOK describes a response with status code 200, with default header values.
|
||||||
|
|
||||||
|
A successful response.
|
||||||
|
*/
|
||||||
|
type ArkServiceSendTreeNoncesOK struct {
|
||||||
|
Payload models.V1SendTreeNoncesResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSuccess returns true when this ark service send tree nonces o k response has a 2xx status code
|
||||||
|
func (o *ArkServiceSendTreeNoncesOK) IsSuccess() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsRedirect returns true when this ark service send tree nonces o k response has a 3xx status code
|
||||||
|
func (o *ArkServiceSendTreeNoncesOK) IsRedirect() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsClientError returns true when this ark service send tree nonces o k response has a 4xx status code
|
||||||
|
func (o *ArkServiceSendTreeNoncesOK) IsClientError() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsServerError returns true when this ark service send tree nonces o k response has a 5xx status code
|
||||||
|
func (o *ArkServiceSendTreeNoncesOK) IsServerError() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCode returns true when this ark service send tree nonces o k response a status code equal to that given
|
||||||
|
func (o *ArkServiceSendTreeNoncesOK) IsCode(code int) bool {
|
||||||
|
return code == 200
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code gets the status code for the ark service send tree nonces o k response
|
||||||
|
func (o *ArkServiceSendTreeNoncesOK) Code() int {
|
||||||
|
return 200
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeNoncesOK) Error() string {
|
||||||
|
payload, _ := json.Marshal(o.Payload)
|
||||||
|
return fmt.Sprintf("[POST /v1/payment/tree/nonces][%d] arkServiceSendTreeNoncesOK %s", 200, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeNoncesOK) String() string {
|
||||||
|
payload, _ := json.Marshal(o.Payload)
|
||||||
|
return fmt.Sprintf("[POST /v1/payment/tree/nonces][%d] arkServiceSendTreeNoncesOK %s", 200, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeNoncesOK) GetPayload() models.V1SendTreeNoncesResponse {
|
||||||
|
return o.Payload
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeNoncesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
// response payload
|
||||||
|
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewArkServiceSendTreeNoncesDefault creates a ArkServiceSendTreeNoncesDefault with default headers values
|
||||||
|
func NewArkServiceSendTreeNoncesDefault(code int) *ArkServiceSendTreeNoncesDefault {
|
||||||
|
return &ArkServiceSendTreeNoncesDefault{
|
||||||
|
_statusCode: code,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ArkServiceSendTreeNoncesDefault describes a response with status code -1, with default header values.
|
||||||
|
|
||||||
|
An unexpected error response.
|
||||||
|
*/
|
||||||
|
type ArkServiceSendTreeNoncesDefault struct {
|
||||||
|
_statusCode int
|
||||||
|
|
||||||
|
Payload *models.RPCStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSuccess returns true when this ark service send tree nonces default response has a 2xx status code
|
||||||
|
func (o *ArkServiceSendTreeNoncesDefault) IsSuccess() bool {
|
||||||
|
return o._statusCode/100 == 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsRedirect returns true when this ark service send tree nonces default response has a 3xx status code
|
||||||
|
func (o *ArkServiceSendTreeNoncesDefault) IsRedirect() bool {
|
||||||
|
return o._statusCode/100 == 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsClientError returns true when this ark service send tree nonces default response has a 4xx status code
|
||||||
|
func (o *ArkServiceSendTreeNoncesDefault) IsClientError() bool {
|
||||||
|
return o._statusCode/100 == 4
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsServerError returns true when this ark service send tree nonces default response has a 5xx status code
|
||||||
|
func (o *ArkServiceSendTreeNoncesDefault) IsServerError() bool {
|
||||||
|
return o._statusCode/100 == 5
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCode returns true when this ark service send tree nonces default response a status code equal to that given
|
||||||
|
func (o *ArkServiceSendTreeNoncesDefault) IsCode(code int) bool {
|
||||||
|
return o._statusCode == code
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code gets the status code for the ark service send tree nonces default response
|
||||||
|
func (o *ArkServiceSendTreeNoncesDefault) Code() int {
|
||||||
|
return o._statusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeNoncesDefault) Error() string {
|
||||||
|
payload, _ := json.Marshal(o.Payload)
|
||||||
|
return fmt.Sprintf("[POST /v1/payment/tree/nonces][%d] ArkService_SendTreeNonces default %s", o._statusCode, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeNoncesDefault) String() string {
|
||||||
|
payload, _ := json.Marshal(o.Payload)
|
||||||
|
return fmt.Sprintf("[POST /v1/payment/tree/nonces][%d] ArkService_SendTreeNonces default %s", o._statusCode, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeNoncesDefault) GetPayload() *models.RPCStatus {
|
||||||
|
return o.Payload
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeNoncesDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
o.Payload = new(models.RPCStatus)
|
||||||
|
|
||||||
|
// response payload
|
||||||
|
if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
package ark_service
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-openapi/errors"
|
||||||
|
"github.com/go-openapi/runtime"
|
||||||
|
cr "github.com/go-openapi/runtime/client"
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
|
||||||
|
"github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewArkServiceSendTreeSignaturesParams creates a new ArkServiceSendTreeSignaturesParams object,
|
||||||
|
// with the default timeout for this client.
|
||||||
|
//
|
||||||
|
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||||
|
//
|
||||||
|
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||||
|
func NewArkServiceSendTreeSignaturesParams() *ArkServiceSendTreeSignaturesParams {
|
||||||
|
return &ArkServiceSendTreeSignaturesParams{
|
||||||
|
timeout: cr.DefaultTimeout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewArkServiceSendTreeSignaturesParamsWithTimeout creates a new ArkServiceSendTreeSignaturesParams object
|
||||||
|
// with the ability to set a timeout on a request.
|
||||||
|
func NewArkServiceSendTreeSignaturesParamsWithTimeout(timeout time.Duration) *ArkServiceSendTreeSignaturesParams {
|
||||||
|
return &ArkServiceSendTreeSignaturesParams{
|
||||||
|
timeout: timeout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewArkServiceSendTreeSignaturesParamsWithContext creates a new ArkServiceSendTreeSignaturesParams object
|
||||||
|
// with the ability to set a context for a request.
|
||||||
|
func NewArkServiceSendTreeSignaturesParamsWithContext(ctx context.Context) *ArkServiceSendTreeSignaturesParams {
|
||||||
|
return &ArkServiceSendTreeSignaturesParams{
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewArkServiceSendTreeSignaturesParamsWithHTTPClient creates a new ArkServiceSendTreeSignaturesParams object
|
||||||
|
// with the ability to set a custom HTTPClient for a request.
|
||||||
|
func NewArkServiceSendTreeSignaturesParamsWithHTTPClient(client *http.Client) *ArkServiceSendTreeSignaturesParams {
|
||||||
|
return &ArkServiceSendTreeSignaturesParams{
|
||||||
|
HTTPClient: client,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ArkServiceSendTreeSignaturesParams contains all the parameters to send to the API endpoint
|
||||||
|
|
||||||
|
for the ark service send tree signatures operation.
|
||||||
|
|
||||||
|
Typically these are written to a http.Request.
|
||||||
|
*/
|
||||||
|
type ArkServiceSendTreeSignaturesParams struct {
|
||||||
|
|
||||||
|
// Body.
|
||||||
|
Body *models.V1SendTreeSignaturesRequest
|
||||||
|
|
||||||
|
timeout time.Duration
|
||||||
|
Context context.Context
|
||||||
|
HTTPClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDefaults hydrates default values in the ark service send tree signatures params (not the query body).
|
||||||
|
//
|
||||||
|
// All values with no default are reset to their zero value.
|
||||||
|
func (o *ArkServiceSendTreeSignaturesParams) WithDefaults() *ArkServiceSendTreeSignaturesParams {
|
||||||
|
o.SetDefaults()
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaults hydrates default values in the ark service send tree signatures params (not the query body).
|
||||||
|
//
|
||||||
|
// All values with no default are reset to their zero value.
|
||||||
|
func (o *ArkServiceSendTreeSignaturesParams) SetDefaults() {
|
||||||
|
// no default values defined for this parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTimeout adds the timeout to the ark service send tree signatures params
|
||||||
|
func (o *ArkServiceSendTreeSignaturesParams) WithTimeout(timeout time.Duration) *ArkServiceSendTreeSignaturesParams {
|
||||||
|
o.SetTimeout(timeout)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTimeout adds the timeout to the ark service send tree signatures params
|
||||||
|
func (o *ArkServiceSendTreeSignaturesParams) SetTimeout(timeout time.Duration) {
|
||||||
|
o.timeout = timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithContext adds the context to the ark service send tree signatures params
|
||||||
|
func (o *ArkServiceSendTreeSignaturesParams) WithContext(ctx context.Context) *ArkServiceSendTreeSignaturesParams {
|
||||||
|
o.SetContext(ctx)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContext adds the context to the ark service send tree signatures params
|
||||||
|
func (o *ArkServiceSendTreeSignaturesParams) SetContext(ctx context.Context) {
|
||||||
|
o.Context = ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHTTPClient adds the HTTPClient to the ark service send tree signatures params
|
||||||
|
func (o *ArkServiceSendTreeSignaturesParams) WithHTTPClient(client *http.Client) *ArkServiceSendTreeSignaturesParams {
|
||||||
|
o.SetHTTPClient(client)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHTTPClient adds the HTTPClient to the ark service send tree signatures params
|
||||||
|
func (o *ArkServiceSendTreeSignaturesParams) SetHTTPClient(client *http.Client) {
|
||||||
|
o.HTTPClient = client
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBody adds the body to the ark service send tree signatures params
|
||||||
|
func (o *ArkServiceSendTreeSignaturesParams) WithBody(body *models.V1SendTreeSignaturesRequest) *ArkServiceSendTreeSignaturesParams {
|
||||||
|
o.SetBody(body)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBody adds the body to the ark service send tree signatures params
|
||||||
|
func (o *ArkServiceSendTreeSignaturesParams) SetBody(body *models.V1SendTreeSignaturesRequest) {
|
||||||
|
o.Body = body
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteToRequest writes these params to a swagger request
|
||||||
|
func (o *ArkServiceSendTreeSignaturesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
|
||||||
|
|
||||||
|
if err := r.SetTimeout(o.timeout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var res []error
|
||||||
|
if o.Body != nil {
|
||||||
|
if err := r.SetBodyParam(o.Body); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) > 0 {
|
||||||
|
return errors.CompositeValidationError(res...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
package ark_service
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/go-openapi/runtime"
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
|
||||||
|
"github.com/ark-network/ark/pkg/client-sdk/client/rest/service/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ArkServiceSendTreeSignaturesReader is a Reader for the ArkServiceSendTreeSignatures structure.
|
||||||
|
type ArkServiceSendTreeSignaturesReader struct {
|
||||||
|
formats strfmt.Registry
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadResponse reads a server response into the received o.
|
||||||
|
func (o *ArkServiceSendTreeSignaturesReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||||
|
switch response.Code() {
|
||||||
|
case 200:
|
||||||
|
result := NewArkServiceSendTreeSignaturesOK()
|
||||||
|
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
default:
|
||||||
|
result := NewArkServiceSendTreeSignaturesDefault(response.Code())
|
||||||
|
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if response.Code()/100 == 2 {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
return nil, result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewArkServiceSendTreeSignaturesOK creates a ArkServiceSendTreeSignaturesOK with default headers values
|
||||||
|
func NewArkServiceSendTreeSignaturesOK() *ArkServiceSendTreeSignaturesOK {
|
||||||
|
return &ArkServiceSendTreeSignaturesOK{}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ArkServiceSendTreeSignaturesOK describes a response with status code 200, with default header values.
|
||||||
|
|
||||||
|
A successful response.
|
||||||
|
*/
|
||||||
|
type ArkServiceSendTreeSignaturesOK struct {
|
||||||
|
Payload models.V1SendTreeSignaturesResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSuccess returns true when this ark service send tree signatures o k response has a 2xx status code
|
||||||
|
func (o *ArkServiceSendTreeSignaturesOK) IsSuccess() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsRedirect returns true when this ark service send tree signatures o k response has a 3xx status code
|
||||||
|
func (o *ArkServiceSendTreeSignaturesOK) IsRedirect() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsClientError returns true when this ark service send tree signatures o k response has a 4xx status code
|
||||||
|
func (o *ArkServiceSendTreeSignaturesOK) IsClientError() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsServerError returns true when this ark service send tree signatures o k response has a 5xx status code
|
||||||
|
func (o *ArkServiceSendTreeSignaturesOK) IsServerError() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCode returns true when this ark service send tree signatures o k response a status code equal to that given
|
||||||
|
func (o *ArkServiceSendTreeSignaturesOK) IsCode(code int) bool {
|
||||||
|
return code == 200
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code gets the status code for the ark service send tree signatures o k response
|
||||||
|
func (o *ArkServiceSendTreeSignaturesOK) Code() int {
|
||||||
|
return 200
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeSignaturesOK) Error() string {
|
||||||
|
payload, _ := json.Marshal(o.Payload)
|
||||||
|
return fmt.Sprintf("[POST /v1/payment/tree/signatures][%d] arkServiceSendTreeSignaturesOK %s", 200, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeSignaturesOK) String() string {
|
||||||
|
payload, _ := json.Marshal(o.Payload)
|
||||||
|
return fmt.Sprintf("[POST /v1/payment/tree/signatures][%d] arkServiceSendTreeSignaturesOK %s", 200, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeSignaturesOK) GetPayload() models.V1SendTreeSignaturesResponse {
|
||||||
|
return o.Payload
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeSignaturesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
// response payload
|
||||||
|
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewArkServiceSendTreeSignaturesDefault creates a ArkServiceSendTreeSignaturesDefault with default headers values
|
||||||
|
func NewArkServiceSendTreeSignaturesDefault(code int) *ArkServiceSendTreeSignaturesDefault {
|
||||||
|
return &ArkServiceSendTreeSignaturesDefault{
|
||||||
|
_statusCode: code,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ArkServiceSendTreeSignaturesDefault describes a response with status code -1, with default header values.
|
||||||
|
|
||||||
|
An unexpected error response.
|
||||||
|
*/
|
||||||
|
type ArkServiceSendTreeSignaturesDefault struct {
|
||||||
|
_statusCode int
|
||||||
|
|
||||||
|
Payload *models.RPCStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSuccess returns true when this ark service send tree signatures default response has a 2xx status code
|
||||||
|
func (o *ArkServiceSendTreeSignaturesDefault) IsSuccess() bool {
|
||||||
|
return o._statusCode/100 == 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsRedirect returns true when this ark service send tree signatures default response has a 3xx status code
|
||||||
|
func (o *ArkServiceSendTreeSignaturesDefault) IsRedirect() bool {
|
||||||
|
return o._statusCode/100 == 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsClientError returns true when this ark service send tree signatures default response has a 4xx status code
|
||||||
|
func (o *ArkServiceSendTreeSignaturesDefault) IsClientError() bool {
|
||||||
|
return o._statusCode/100 == 4
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsServerError returns true when this ark service send tree signatures default response has a 5xx status code
|
||||||
|
func (o *ArkServiceSendTreeSignaturesDefault) IsServerError() bool {
|
||||||
|
return o._statusCode/100 == 5
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCode returns true when this ark service send tree signatures default response a status code equal to that given
|
||||||
|
func (o *ArkServiceSendTreeSignaturesDefault) IsCode(code int) bool {
|
||||||
|
return o._statusCode == code
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code gets the status code for the ark service send tree signatures default response
|
||||||
|
func (o *ArkServiceSendTreeSignaturesDefault) Code() int {
|
||||||
|
return o._statusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeSignaturesDefault) Error() string {
|
||||||
|
payload, _ := json.Marshal(o.Payload)
|
||||||
|
return fmt.Sprintf("[POST /v1/payment/tree/signatures][%d] ArkService_SendTreeSignatures default %s", o._statusCode, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeSignaturesDefault) String() string {
|
||||||
|
payload, _ := json.Marshal(o.Payload)
|
||||||
|
return fmt.Sprintf("[POST /v1/payment/tree/signatures][%d] ArkService_SendTreeSignatures default %s", o._statusCode, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeSignaturesDefault) GetPayload() *models.RPCStatus {
|
||||||
|
return o.Payload
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ArkServiceSendTreeSignaturesDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
o.Payload = new(models.RPCStatus)
|
||||||
|
|
||||||
|
// response payload
|
||||||
|
if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -21,11 +21,17 @@ type V1GetEventStreamResponse struct {
|
|||||||
// round failed
|
// round failed
|
||||||
RoundFailed *V1RoundFailed `json:"roundFailed,omitempty"`
|
RoundFailed *V1RoundFailed `json:"roundFailed,omitempty"`
|
||||||
|
|
||||||
// TODO: BTC add "signTree" event
|
// round finalization
|
||||||
RoundFinalization *V1RoundFinalizationEvent `json:"roundFinalization,omitempty"`
|
RoundFinalization *V1RoundFinalizationEvent `json:"roundFinalization,omitempty"`
|
||||||
|
|
||||||
// round finalized
|
// round finalized
|
||||||
RoundFinalized *V1RoundFinalizedEvent `json:"roundFinalized,omitempty"`
|
RoundFinalized *V1RoundFinalizedEvent `json:"roundFinalized,omitempty"`
|
||||||
|
|
||||||
|
// round signing
|
||||||
|
RoundSigning *V1RoundSigningEvent `json:"roundSigning,omitempty"`
|
||||||
|
|
||||||
|
// round signing nonces generated
|
||||||
|
RoundSigningNoncesGenerated *V1RoundSigningNoncesGeneratedEvent `json:"roundSigningNoncesGenerated,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates this v1 get event stream response
|
// Validate validates this v1 get event stream response
|
||||||
@@ -44,6 +50,14 @@ func (m *V1GetEventStreamResponse) Validate(formats strfmt.Registry) error {
|
|||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := m.validateRoundSigning(formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.validateRoundSigningNoncesGenerated(formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
if len(res) > 0 {
|
if len(res) > 0 {
|
||||||
return errors.CompositeValidationError(res...)
|
return errors.CompositeValidationError(res...)
|
||||||
}
|
}
|
||||||
@@ -107,6 +121,44 @@ func (m *V1GetEventStreamResponse) validateRoundFinalized(formats strfmt.Registr
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *V1GetEventStreamResponse) validateRoundSigning(formats strfmt.Registry) error {
|
||||||
|
if swag.IsZero(m.RoundSigning) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.RoundSigning != nil {
|
||||||
|
if err := m.RoundSigning.Validate(formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("roundSigning")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("roundSigning")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *V1GetEventStreamResponse) validateRoundSigningNoncesGenerated(formats strfmt.Registry) error {
|
||||||
|
if swag.IsZero(m.RoundSigningNoncesGenerated) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.RoundSigningNoncesGenerated != nil {
|
||||||
|
if err := m.RoundSigningNoncesGenerated.Validate(formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("roundSigningNoncesGenerated")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("roundSigningNoncesGenerated")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ContextValidate validate this v1 get event stream response based on the context it is used
|
// ContextValidate validate this v1 get event stream response based on the context it is used
|
||||||
func (m *V1GetEventStreamResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
func (m *V1GetEventStreamResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||||
var res []error
|
var res []error
|
||||||
@@ -123,6 +175,14 @@ func (m *V1GetEventStreamResponse) ContextValidate(ctx context.Context, formats
|
|||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := m.contextValidateRoundSigning(ctx, formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.contextValidateRoundSigningNoncesGenerated(ctx, formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
if len(res) > 0 {
|
if len(res) > 0 {
|
||||||
return errors.CompositeValidationError(res...)
|
return errors.CompositeValidationError(res...)
|
||||||
}
|
}
|
||||||
@@ -192,6 +252,48 @@ func (m *V1GetEventStreamResponse) contextValidateRoundFinalized(ctx context.Con
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *V1GetEventStreamResponse) contextValidateRoundSigning(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
if m.RoundSigning != nil {
|
||||||
|
|
||||||
|
if swag.IsZero(m.RoundSigning) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.RoundSigning.ContextValidate(ctx, formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("roundSigning")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("roundSigning")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *V1GetEventStreamResponse) contextValidateRoundSigningNoncesGenerated(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
if m.RoundSigningNoncesGenerated != nil {
|
||||||
|
|
||||||
|
if swag.IsZero(m.RoundSigningNoncesGenerated) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.RoundSigningNoncesGenerated.ContextValidate(ctx, formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("roundSigningNoncesGenerated")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("roundSigningNoncesGenerated")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalBinary interface implementation
|
// MarshalBinary interface implementation
|
||||||
func (m *V1GetEventStreamResponse) MarshalBinary() ([]byte, error) {
|
func (m *V1GetEventStreamResponse) MarshalBinary() ([]byte, error) {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
|
|||||||
@@ -18,18 +18,43 @@ import (
|
|||||||
// swagger:model v1PingResponse
|
// swagger:model v1PingResponse
|
||||||
type V1PingResponse struct {
|
type V1PingResponse struct {
|
||||||
|
|
||||||
// event
|
// round failed
|
||||||
Event *V1RoundFinalizationEvent `json:"event,omitempty"`
|
RoundFailed *V1RoundFailed `json:"roundFailed,omitempty"`
|
||||||
|
|
||||||
// forfeit txs
|
// round finalization
|
||||||
ForfeitTxs []string `json:"forfeitTxs"`
|
RoundFinalization *V1RoundFinalizationEvent `json:"roundFinalization,omitempty"`
|
||||||
|
|
||||||
|
// round finalized
|
||||||
|
RoundFinalized *V1RoundFinalizedEvent `json:"roundFinalized,omitempty"`
|
||||||
|
|
||||||
|
// round signing
|
||||||
|
RoundSigning *V1RoundSigningEvent `json:"roundSigning,omitempty"`
|
||||||
|
|
||||||
|
// round signing nonces generated
|
||||||
|
RoundSigningNoncesGenerated *V1RoundSigningNoncesGeneratedEvent `json:"roundSigningNoncesGenerated,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates this v1 ping response
|
// Validate validates this v1 ping response
|
||||||
func (m *V1PingResponse) Validate(formats strfmt.Registry) error {
|
func (m *V1PingResponse) Validate(formats strfmt.Registry) error {
|
||||||
var res []error
|
var res []error
|
||||||
|
|
||||||
if err := m.validateEvent(formats); err != nil {
|
if err := m.validateRoundFailed(formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.validateRoundFinalization(formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.validateRoundFinalized(formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.validateRoundSigning(formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.validateRoundSigningNoncesGenerated(formats); err != nil {
|
||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,17 +64,93 @@ func (m *V1PingResponse) Validate(formats strfmt.Registry) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *V1PingResponse) validateEvent(formats strfmt.Registry) error {
|
func (m *V1PingResponse) validateRoundFailed(formats strfmt.Registry) error {
|
||||||
if swag.IsZero(m.Event) { // not required
|
if swag.IsZero(m.RoundFailed) { // not required
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.Event != nil {
|
if m.RoundFailed != nil {
|
||||||
if err := m.Event.Validate(formats); err != nil {
|
if err := m.RoundFailed.Validate(formats); err != nil {
|
||||||
if ve, ok := err.(*errors.Validation); ok {
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
return ve.ValidateName("event")
|
return ve.ValidateName("roundFailed")
|
||||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
return ce.ValidateName("event")
|
return ce.ValidateName("roundFailed")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *V1PingResponse) validateRoundFinalization(formats strfmt.Registry) error {
|
||||||
|
if swag.IsZero(m.RoundFinalization) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.RoundFinalization != nil {
|
||||||
|
if err := m.RoundFinalization.Validate(formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("roundFinalization")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("roundFinalization")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *V1PingResponse) validateRoundFinalized(formats strfmt.Registry) error {
|
||||||
|
if swag.IsZero(m.RoundFinalized) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.RoundFinalized != nil {
|
||||||
|
if err := m.RoundFinalized.Validate(formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("roundFinalized")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("roundFinalized")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *V1PingResponse) validateRoundSigning(formats strfmt.Registry) error {
|
||||||
|
if swag.IsZero(m.RoundSigning) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.RoundSigning != nil {
|
||||||
|
if err := m.RoundSigning.Validate(formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("roundSigning")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("roundSigning")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *V1PingResponse) validateRoundSigningNoncesGenerated(formats strfmt.Registry) error {
|
||||||
|
if swag.IsZero(m.RoundSigningNoncesGenerated) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.RoundSigningNoncesGenerated != nil {
|
||||||
|
if err := m.RoundSigningNoncesGenerated.Validate(formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("roundSigningNoncesGenerated")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("roundSigningNoncesGenerated")
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -62,7 +163,23 @@ func (m *V1PingResponse) validateEvent(formats strfmt.Registry) error {
|
|||||||
func (m *V1PingResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
func (m *V1PingResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||||
var res []error
|
var res []error
|
||||||
|
|
||||||
if err := m.contextValidateEvent(ctx, formats); err != nil {
|
if err := m.contextValidateRoundFailed(ctx, formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.contextValidateRoundFinalization(ctx, formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.contextValidateRoundFinalized(ctx, formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.contextValidateRoundSigning(ctx, formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.contextValidateRoundSigningNoncesGenerated(ctx, formats); err != nil {
|
||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,19 +189,103 @@ func (m *V1PingResponse) ContextValidate(ctx context.Context, formats strfmt.Reg
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *V1PingResponse) contextValidateEvent(ctx context.Context, formats strfmt.Registry) error {
|
func (m *V1PingResponse) contextValidateRoundFailed(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
|
||||||
if m.Event != nil {
|
if m.RoundFailed != nil {
|
||||||
|
|
||||||
if swag.IsZero(m.Event) { // not required
|
if swag.IsZero(m.RoundFailed) { // not required
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := m.Event.ContextValidate(ctx, formats); err != nil {
|
if err := m.RoundFailed.ContextValidate(ctx, formats); err != nil {
|
||||||
if ve, ok := err.(*errors.Validation); ok {
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
return ve.ValidateName("event")
|
return ve.ValidateName("roundFailed")
|
||||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
return ce.ValidateName("event")
|
return ce.ValidateName("roundFailed")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *V1PingResponse) contextValidateRoundFinalization(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
if m.RoundFinalization != nil {
|
||||||
|
|
||||||
|
if swag.IsZero(m.RoundFinalization) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.RoundFinalization.ContextValidate(ctx, formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("roundFinalization")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("roundFinalization")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *V1PingResponse) contextValidateRoundFinalized(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
if m.RoundFinalized != nil {
|
||||||
|
|
||||||
|
if swag.IsZero(m.RoundFinalized) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.RoundFinalized.ContextValidate(ctx, formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("roundFinalized")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("roundFinalized")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *V1PingResponse) contextValidateRoundSigning(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
if m.RoundSigning != nil {
|
||||||
|
|
||||||
|
if swag.IsZero(m.RoundSigning) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.RoundSigning.ContextValidate(ctx, formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("roundSigning")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("roundSigning")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *V1PingResponse) contextValidateRoundSigningNoncesGenerated(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
if m.RoundSigningNoncesGenerated != nil {
|
||||||
|
|
||||||
|
if swag.IsZero(m.RoundSigningNoncesGenerated) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.RoundSigningNoncesGenerated.ContextValidate(ctx, formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("roundSigningNoncesGenerated")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("roundSigningNoncesGenerated")
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ import (
|
|||||||
// swagger:model v1RegisterPaymentRequest
|
// swagger:model v1RegisterPaymentRequest
|
||||||
type V1RegisterPaymentRequest struct {
|
type V1RegisterPaymentRequest struct {
|
||||||
|
|
||||||
|
// ephemeral pubkey
|
||||||
|
EphemeralPubkey string `json:"ephemeralPubkey,omitempty"`
|
||||||
|
|
||||||
// inputs
|
// inputs
|
||||||
Inputs []*V1Input `json:"inputs"`
|
Inputs []*V1Input `json:"inputs"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/go-openapi/errors"
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// V1RoundSigningEvent v1 round signing event
|
||||||
|
//
|
||||||
|
// swagger:model v1RoundSigningEvent
|
||||||
|
type V1RoundSigningEvent struct {
|
||||||
|
|
||||||
|
// cosigners pubkeys
|
||||||
|
CosignersPubkeys []string `json:"cosignersPubkeys"`
|
||||||
|
|
||||||
|
// id
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
|
||||||
|
// unsigned tree
|
||||||
|
UnsignedTree *V1Tree `json:"unsignedTree,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates this v1 round signing event
|
||||||
|
func (m *V1RoundSigningEvent) Validate(formats strfmt.Registry) error {
|
||||||
|
var res []error
|
||||||
|
|
||||||
|
if err := m.validateUnsignedTree(formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) > 0 {
|
||||||
|
return errors.CompositeValidationError(res...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *V1RoundSigningEvent) validateUnsignedTree(formats strfmt.Registry) error {
|
||||||
|
if swag.IsZero(m.UnsignedTree) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.UnsignedTree != nil {
|
||||||
|
if err := m.UnsignedTree.Validate(formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("unsignedTree")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("unsignedTree")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContextValidate validate this v1 round signing event based on the context it is used
|
||||||
|
func (m *V1RoundSigningEvent) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
var res []error
|
||||||
|
|
||||||
|
if err := m.contextValidateUnsignedTree(ctx, formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) > 0 {
|
||||||
|
return errors.CompositeValidationError(res...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *V1RoundSigningEvent) contextValidateUnsignedTree(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
if m.UnsignedTree != nil {
|
||||||
|
|
||||||
|
if swag.IsZero(m.UnsignedTree) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.UnsignedTree.ContextValidate(ctx, formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("unsignedTree")
|
||||||
|
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||||
|
return ce.ValidateName("unsignedTree")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary interface implementation
|
||||||
|
func (m *V1RoundSigningEvent) MarshalBinary() ([]byte, error) {
|
||||||
|
if m == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return swag.WriteJSON(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary interface implementation
|
||||||
|
func (m *V1RoundSigningEvent) UnmarshalBinary(b []byte) error {
|
||||||
|
var res V1RoundSigningEvent
|
||||||
|
if err := swag.ReadJSON(b, &res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*m = res
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// V1RoundSigningNoncesGeneratedEvent v1 round signing nonces generated event
|
||||||
|
//
|
||||||
|
// swagger:model v1RoundSigningNoncesGeneratedEvent
|
||||||
|
type V1RoundSigningNoncesGeneratedEvent struct {
|
||||||
|
|
||||||
|
// id
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
|
||||||
|
// tree nonces
|
||||||
|
TreeNonces string `json:"treeNonces,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates this v1 round signing nonces generated event
|
||||||
|
func (m *V1RoundSigningNoncesGeneratedEvent) Validate(formats strfmt.Registry) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContextValidate validates this v1 round signing nonces generated event based on context it is used
|
||||||
|
func (m *V1RoundSigningNoncesGeneratedEvent) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary interface implementation
|
||||||
|
func (m *V1RoundSigningNoncesGeneratedEvent) MarshalBinary() ([]byte, error) {
|
||||||
|
if m == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return swag.WriteJSON(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary interface implementation
|
||||||
|
func (m *V1RoundSigningNoncesGeneratedEvent) UnmarshalBinary(b []byte) error {
|
||||||
|
var res V1RoundSigningNoncesGeneratedEvent
|
||||||
|
if err := swag.ReadJSON(b, &res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*m = res
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// V1SendTreeNoncesRequest v1 send tree nonces request
|
||||||
|
//
|
||||||
|
// swagger:model v1SendTreeNoncesRequest
|
||||||
|
type V1SendTreeNoncesRequest struct {
|
||||||
|
|
||||||
|
// public key
|
||||||
|
PublicKey string `json:"publicKey,omitempty"`
|
||||||
|
|
||||||
|
// round Id
|
||||||
|
RoundID string `json:"roundId,omitempty"`
|
||||||
|
|
||||||
|
// tree nonces
|
||||||
|
TreeNonces string `json:"treeNonces,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates this v1 send tree nonces request
|
||||||
|
func (m *V1SendTreeNoncesRequest) Validate(formats strfmt.Registry) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContextValidate validates this v1 send tree nonces request based on context it is used
|
||||||
|
func (m *V1SendTreeNoncesRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary interface implementation
|
||||||
|
func (m *V1SendTreeNoncesRequest) MarshalBinary() ([]byte, error) {
|
||||||
|
if m == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return swag.WriteJSON(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary interface implementation
|
||||||
|
func (m *V1SendTreeNoncesRequest) UnmarshalBinary(b []byte) error {
|
||||||
|
var res V1SendTreeNoncesRequest
|
||||||
|
if err := swag.ReadJSON(b, &res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*m = res
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
// V1SendTreeNoncesResponse v1 send tree nonces response
|
||||||
|
//
|
||||||
|
// swagger:model v1SendTreeNoncesResponse
|
||||||
|
type V1SendTreeNoncesResponse interface{}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// V1SendTreeSignaturesRequest v1 send tree signatures request
|
||||||
|
//
|
||||||
|
// swagger:model v1SendTreeSignaturesRequest
|
||||||
|
type V1SendTreeSignaturesRequest struct {
|
||||||
|
|
||||||
|
// public key
|
||||||
|
PublicKey string `json:"publicKey,omitempty"`
|
||||||
|
|
||||||
|
// round Id
|
||||||
|
RoundID string `json:"roundId,omitempty"`
|
||||||
|
|
||||||
|
// tree signatures
|
||||||
|
TreeSignatures string `json:"treeSignatures,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates this v1 send tree signatures request
|
||||||
|
func (m *V1SendTreeSignaturesRequest) Validate(formats strfmt.Registry) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContextValidate validates this v1 send tree signatures request based on context it is used
|
||||||
|
func (m *V1SendTreeSignaturesRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary interface implementation
|
||||||
|
func (m *V1SendTreeSignaturesRequest) MarshalBinary() ([]byte, error) {
|
||||||
|
if m == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return swag.WriteJSON(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary interface implementation
|
||||||
|
func (m *V1SendTreeSignaturesRequest) UnmarshalBinary(b []byte) error {
|
||||||
|
var res V1SendTreeSignaturesRequest
|
||||||
|
if err := swag.ReadJSON(b, &res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*m = res
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
// V1SendTreeSignaturesResponse v1 send tree signatures response
|
||||||
|
//
|
||||||
|
// swagger:model v1SendTreeSignaturesResponse
|
||||||
|
type V1SendTreeSignaturesResponse interface{}
|
||||||
@@ -528,7 +528,7 @@ func (a *covenantArkClient) CollaborativeRedeem(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
paymentID, err := a.client.RegisterPayment(ctx, inputs)
|
paymentID, err := a.client.RegisterPayment(ctx, inputs, "") // ephemeralPublicKey is not required for covenant
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -796,7 +796,7 @@ func (a *covenantArkClient) sendOffchain(
|
|||||||
}
|
}
|
||||||
|
|
||||||
paymentID, err := a.client.RegisterPayment(
|
paymentID, err := a.client.RegisterPayment(
|
||||||
ctx, inputs,
|
ctx, inputs, "", // ephemeralPublicKey is not required for covenant
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|||||||
@@ -262,7 +262,11 @@ func (a *covenantlessArkClient) Onboard(
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := signer.SetKeys(cosigners, aggregatedNonces); err != nil {
|
if err := signer.SetKeys(cosigners); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := signer.SetAggregatedNonces(aggregatedNonces); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,7 +612,16 @@ func (a *covenantlessArkClient) CollaborativeRedeem(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
paymentID, err := a.client.RegisterPayment(ctx, inputs)
|
roundEphemeralKey, err := secp256k1.GeneratePrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
paymentID, err := a.client.RegisterPayment(
|
||||||
|
ctx,
|
||||||
|
inputs,
|
||||||
|
hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -618,7 +631,7 @@ func (a *covenantlessArkClient) CollaborativeRedeem(
|
|||||||
}
|
}
|
||||||
|
|
||||||
poolTxID, err := a.handleRoundStream(
|
poolTxID, err := a.handleRoundStream(
|
||||||
ctx, paymentID, selectedCoins, receivers,
|
ctx, paymentID, selectedCoins, receivers, roundEphemeralKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -990,8 +1003,13 @@ func (a *covenantlessArkClient) sendOffchain(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
roundEphemeralKey, err := secp256k1.GeneratePrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
paymentID, err := a.client.RegisterPayment(
|
paymentID, err := a.client.RegisterPayment(
|
||||||
ctx, inputs,
|
ctx, inputs, hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -1006,7 +1024,7 @@ func (a *covenantlessArkClient) sendOffchain(
|
|||||||
log.Infof("payment registered with id: %s", paymentID)
|
log.Infof("payment registered with id: %s", paymentID)
|
||||||
|
|
||||||
poolTxID, err := a.handleRoundStream(
|
poolTxID, err := a.handleRoundStream(
|
||||||
ctx, paymentID, selectedCoins, receiversOutput,
|
ctx, paymentID, selectedCoins, receiversOutput, roundEphemeralKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -1144,7 +1162,10 @@ func (a *covenantlessArkClient) addVtxoInput(
|
|||||||
|
|
||||||
func (a *covenantlessArkClient) handleRoundStream(
|
func (a *covenantlessArkClient) handleRoundStream(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
paymentID string, vtxosToSign []client.Vtxo, receivers []client.Output,
|
paymentID string,
|
||||||
|
vtxosToSign []client.Vtxo,
|
||||||
|
receivers []client.Output,
|
||||||
|
roundEphemeralKey *secp256k1.PrivateKey,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
eventsCh, err := a.client.GetEventStream(ctx, paymentID)
|
eventsCh, err := a.client.GetEventStream(ctx, paymentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1158,6 +1179,8 @@ func (a *covenantlessArkClient) handleRoundStream(
|
|||||||
|
|
||||||
defer pingStop()
|
defer pingStop()
|
||||||
|
|
||||||
|
var signerSession bitcointree.SignerSession
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
@@ -1172,6 +1195,25 @@ func (a *covenantlessArkClient) handleRoundStream(
|
|||||||
return event.(client.RoundFinalizedEvent).Txid, nil
|
return event.(client.RoundFinalizedEvent).Txid, nil
|
||||||
case client.RoundFailedEvent:
|
case client.RoundFailedEvent:
|
||||||
return "", fmt.Errorf("round failed: %s", event.(client.RoundFailedEvent).Reason)
|
return "", fmt.Errorf("round failed: %s", event.(client.RoundFailedEvent).Reason)
|
||||||
|
case client.RoundSigningStartedEvent:
|
||||||
|
pingStop()
|
||||||
|
log.Info("a round signing started")
|
||||||
|
signerSession, err = a.handleRoundSigningStarted(
|
||||||
|
ctx, roundEphemeralKey, event.(client.RoundSigningStartedEvent),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
case client.RoundSigningNoncesGeneratedEvent:
|
||||||
|
pingStop()
|
||||||
|
log.Info("round combined nonces generated")
|
||||||
|
if err := a.handleRoundSigningNoncesGenerated(
|
||||||
|
ctx, event.(client.RoundSigningNoncesGeneratedEvent), roundEphemeralKey, signerSession,
|
||||||
|
); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
continue
|
||||||
case client.RoundFinalizationEvent:
|
case client.RoundFinalizationEvent:
|
||||||
pingStop()
|
pingStop()
|
||||||
log.Info("a round finalization started")
|
log.Info("a round finalization started")
|
||||||
@@ -1200,6 +1242,73 @@ func (a *covenantlessArkClient) handleRoundStream(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *covenantlessArkClient) handleRoundSigningStarted(
|
||||||
|
ctx context.Context, ephemeralKey *secp256k1.PrivateKey, event client.RoundSigningStartedEvent,
|
||||||
|
) (signerSession bitcointree.SignerSession, err error) {
|
||||||
|
sweepClosure := bitcointree.CSVSigClosure{
|
||||||
|
Pubkey: a.AspPubkey,
|
||||||
|
Seconds: uint(a.RoundLifetime),
|
||||||
|
}
|
||||||
|
|
||||||
|
sweepTapLeaf, err := sweepClosure.Leaf()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sweepTapTree := txscript.AssembleTaprootScriptTree(*sweepTapLeaf)
|
||||||
|
root := sweepTapTree.RootNode.TapHash()
|
||||||
|
|
||||||
|
signerSession = bitcointree.NewTreeSignerSession(
|
||||||
|
ephemeralKey, event.UnsignedTree, int64(a.MinRelayFee), root.CloneBytes(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if err = signerSession.SetKeys(event.CosignersPublicKeys); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nonces, err := signerSession.GetNonces()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
myPubKey := hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed())
|
||||||
|
|
||||||
|
err = a.arkClient.client.SendTreeNonces(ctx, event.ID, myPubKey, nonces)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *covenantlessArkClient) handleRoundSigningNoncesGenerated(
|
||||||
|
ctx context.Context,
|
||||||
|
event client.RoundSigningNoncesGeneratedEvent,
|
||||||
|
ephemeralKey *secp256k1.PrivateKey,
|
||||||
|
signerSession bitcointree.SignerSession,
|
||||||
|
) error {
|
||||||
|
if signerSession == nil {
|
||||||
|
return fmt.Errorf("tree signer session not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := signerSession.SetAggregatedNonces(event.Nonces); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sigs, err := signerSession.Sign()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.arkClient.client.SendTreeSignatures(
|
||||||
|
ctx,
|
||||||
|
event.ID,
|
||||||
|
hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed()),
|
||||||
|
sigs,
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *covenantlessArkClient) handleRoundFinalization(
|
func (a *covenantlessArkClient) handleRoundFinalization(
|
||||||
ctx context.Context, event client.RoundFinalizationEvent,
|
ctx context.Context, event client.RoundFinalizationEvent,
|
||||||
vtxos []client.Vtxo, receivers []client.Output,
|
vtxos []client.Vtxo, receivers []client.Output,
|
||||||
@@ -1619,7 +1728,16 @@ func (a *covenantlessArkClient) selfTransferAllPendingPayments(
|
|||||||
|
|
||||||
outputs := []client.Output{myself}
|
outputs := []client.Output{myself}
|
||||||
|
|
||||||
paymentID, err := a.client.RegisterPayment(ctx, inputs)
|
roundEphemeralKey, err := secp256k1.GeneratePrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
paymentID, err := a.client.RegisterPayment(
|
||||||
|
ctx,
|
||||||
|
inputs,
|
||||||
|
hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -1629,7 +1747,7 @@ func (a *covenantlessArkClient) selfTransferAllPendingPayments(
|
|||||||
}
|
}
|
||||||
|
|
||||||
roundTxid, err := a.handleRoundStream(
|
roundTxid, err := a.handleRoundStream(
|
||||||
ctx, paymentID, pendingVtxos, outputs,
|
ctx, paymentID, pendingVtxos, outputs, roundEphemeralKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ import (
|
|||||||
"github.com/vulpemventures/go-elements/psetv2"
|
"github.com/vulpemventures/go-elements/psetv2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrTreeSigningNotRequired = fmt.Errorf("tree signing is not required on this ark (covenant)")
|
||||||
|
)
|
||||||
|
|
||||||
type covenantService struct {
|
type covenantService struct {
|
||||||
network common.Network
|
network common.Network
|
||||||
pubkey *secp256k1.PublicKey
|
pubkey *secp256k1.PublicKey
|
||||||
@@ -40,6 +44,7 @@ type covenantService struct {
|
|||||||
eventsCh chan domain.RoundEvent
|
eventsCh chan domain.RoundEvent
|
||||||
onboardingCh chan onboarding
|
onboardingCh chan onboarding
|
||||||
|
|
||||||
|
lastEvent domain.RoundEvent
|
||||||
currentRound *domain.Round
|
currentRound *domain.Round
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +71,7 @@ func NewCovenantService(
|
|||||||
network, pubkey,
|
network, pubkey,
|
||||||
roundLifetime, roundInterval, unilateralExitDelay, minRelayFee,
|
roundLifetime, roundInterval, unilateralExitDelay, minRelayFee,
|
||||||
walletSvc, repoManager, builder, scanner, sweeper,
|
walletSvc, repoManager, builder, scanner, sweeper,
|
||||||
paymentRequests, forfeitTxs, eventsCh, onboardingCh, nil,
|
paymentRequests, forfeitTxs, eventsCh, onboardingCh, nil, nil,
|
||||||
}
|
}
|
||||||
repoManager.RegisterEventsHandler(
|
repoManager.RegisterEventsHandler(
|
||||||
func(round *domain.Round) {
|
func(round *domain.Round) {
|
||||||
@@ -148,17 +153,17 @@ func (s *covenantService) ClaimVtxos(ctx context.Context, creds string, receiver
|
|||||||
return s.paymentRequests.update(*payment)
|
return s.paymentRequests.update(*payment)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantService) UpdatePaymentStatus(_ context.Context, id string) ([]string, *domain.Round, error) {
|
func (s *covenantService) UpdatePaymentStatus(_ context.Context, id string) (domain.RoundEvent, error) {
|
||||||
err := s.paymentRequests.updatePingTimestamp(id)
|
err := s.paymentRequests.updatePingTimestamp(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(errPaymentNotFound); ok {
|
if _, ok := err.(errPaymentNotFound); ok {
|
||||||
return s.forfeitTxs.view(), s.currentRound, nil
|
return s.lastEvent, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, nil
|
return s.lastEvent, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantService) CompleteAsyncPayment(ctx context.Context, redeemTx string, unconditionalForfeitTxs []string) error {
|
func (s *covenantService) CompleteAsyncPayment(ctx context.Context, redeemTx string, unconditionalForfeitTxs []string) error {
|
||||||
@@ -248,6 +253,24 @@ func (s *covenantService) Onboard(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *covenantService) RegisterCosignerPubkey(ctx context.Context, paymentId string, _ string) error {
|
||||||
|
// if the user sends an ephemeral pubkey, something is going wrong client-side
|
||||||
|
// we should delete the associated payment
|
||||||
|
if err := s.paymentRequests.delete(paymentId); err != nil {
|
||||||
|
log.WithError(err).Warn("failed to delete payment")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrTreeSigningNotRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *covenantService) RegisterCosignerNonces(context.Context, string, *secp256k1.PublicKey, string) error {
|
||||||
|
return ErrTreeSigningNotRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *covenantService) RegisterCosignerSignatures(context.Context, string, *secp256k1.PublicKey, string) error {
|
||||||
|
return ErrTreeSigningNotRequired
|
||||||
|
}
|
||||||
|
|
||||||
func (s *covenantService) start() {
|
func (s *covenantService) start() {
|
||||||
s.startRound()
|
s.startRound()
|
||||||
}
|
}
|
||||||
@@ -256,6 +279,7 @@ func (s *covenantService) startRound() {
|
|||||||
round := domain.NewRound(dustAmount)
|
round := domain.NewRound(dustAmount)
|
||||||
//nolint:all
|
//nolint:all
|
||||||
round.StartRegistration()
|
round.StartRegistration()
|
||||||
|
s.lastEvent = nil
|
||||||
s.currentRound = round
|
s.currentRound = round
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -305,7 +329,7 @@ func (s *covenantService) startFinalization() {
|
|||||||
if num > paymentsThreshold {
|
if num > paymentsThreshold {
|
||||||
num = paymentsThreshold
|
num = paymentsThreshold
|
||||||
}
|
}
|
||||||
payments := s.paymentRequests.pop(num)
|
payments, _ := s.paymentRequests.pop(num)
|
||||||
if _, err := round.RegisterPayments(payments); err != nil {
|
if _, err := round.RegisterPayments(payments); err != nil {
|
||||||
round.Fail(fmt.Errorf("failed to register payments: %s", err))
|
round.Fail(fmt.Errorf("failed to register payments: %s", err))
|
||||||
log.WithError(err).Warn("failed to register payments")
|
log.WithError(err).Warn("failed to register payments")
|
||||||
@@ -670,14 +694,17 @@ func (s *covenantService) propagateEvents(round *domain.Round) {
|
|||||||
switch e := lastEvent.(type) {
|
switch e := lastEvent.(type) {
|
||||||
case domain.RoundFinalizationStarted:
|
case domain.RoundFinalizationStarted:
|
||||||
forfeitTxs := s.forfeitTxs.view()
|
forfeitTxs := s.forfeitTxs.view()
|
||||||
s.eventsCh <- domain.RoundFinalizationStarted{
|
ev := domain.RoundFinalizationStarted{
|
||||||
Id: e.Id,
|
Id: e.Id,
|
||||||
CongestionTree: e.CongestionTree,
|
CongestionTree: e.CongestionTree,
|
||||||
Connectors: e.Connectors,
|
Connectors: e.Connectors,
|
||||||
PoolTx: e.PoolTx,
|
PoolTx: e.PoolTx,
|
||||||
UnsignedForfeitTxs: forfeitTxs,
|
UnsignedForfeitTxs: forfeitTxs,
|
||||||
}
|
}
|
||||||
|
s.lastEvent = ev
|
||||||
|
s.eventsCh <- ev
|
||||||
case domain.RoundFinalized, domain.RoundFailed:
|
case domain.RoundFinalized, domain.RoundFailed:
|
||||||
|
s.lastEvent = e
|
||||||
s.eventsCh <- e
|
s.eventsCh <- e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,9 +41,11 @@ type covenantlessService struct {
|
|||||||
eventsCh chan domain.RoundEvent
|
eventsCh chan domain.RoundEvent
|
||||||
onboardingCh chan onboarding
|
onboardingCh chan onboarding
|
||||||
|
|
||||||
currentRound *domain.Round
|
// cached data for the current round
|
||||||
|
lastEvent domain.RoundEvent
|
||||||
asyncPaymentsCache map[domain.VtxoKey]struct {
|
currentRound *domain.Round
|
||||||
|
treeSigningSessions map[string]*musigSigningSession
|
||||||
|
asyncPaymentsCache map[domain.VtxoKey]struct {
|
||||||
receivers []domain.Receiver
|
receivers []domain.Receiver
|
||||||
expireAt int64
|
expireAt int64
|
||||||
}
|
}
|
||||||
@@ -89,6 +91,7 @@ func NewCovenantlessService(
|
|||||||
eventsCh: eventsCh,
|
eventsCh: eventsCh,
|
||||||
onboardingCh: onboardingCh,
|
onboardingCh: onboardingCh,
|
||||||
asyncPaymentsCache: asyncPaymentsCache,
|
asyncPaymentsCache: asyncPaymentsCache,
|
||||||
|
treeSigningSessions: make(map[string]*musigSigningSession),
|
||||||
}
|
}
|
||||||
|
|
||||||
repoManager.RegisterEventsHandler(
|
repoManager.RegisterEventsHandler(
|
||||||
@@ -273,17 +276,17 @@ func (s *covenantlessService) ClaimVtxos(ctx context.Context, creds string, rece
|
|||||||
return s.paymentRequests.update(*payment)
|
return s.paymentRequests.update(*payment)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantlessService) UpdatePaymentStatus(_ context.Context, id string) ([]string, *domain.Round, error) {
|
func (s *covenantlessService) UpdatePaymentStatus(_ context.Context, id string) (domain.RoundEvent, error) {
|
||||||
err := s.paymentRequests.updatePingTimestamp(id)
|
err := s.paymentRequests.updatePingTimestamp(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(errPaymentNotFound); ok {
|
if _, ok := err.(errPaymentNotFound); ok {
|
||||||
return s.forfeitTxs.view(), s.currentRound, nil
|
return s.lastEvent, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, nil
|
return s.lastEvent, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *covenantlessService) SignVtxos(ctx context.Context, forfeitTxs []string) error {
|
func (s *covenantlessService) SignVtxos(ctx context.Context, forfeitTxs []string) error {
|
||||||
@@ -367,6 +370,78 @@ func (s *covenantlessService) Onboard(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *covenantlessService) RegisterCosignerPubkey(ctx context.Context, paymentId string, pubkey string) error {
|
||||||
|
pubkeyBytes, err := hex.DecodeString(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decode hex pubkey: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ephemeralPublicKey, err := secp256k1.ParsePubKey(pubkeyBytes)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse pubkey: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.paymentRequests.pushEphemeralKey(paymentId, ephemeralPublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *covenantlessService) RegisterCosignerNonces(
|
||||||
|
ctx context.Context, roundID string, pubkey *secp256k1.PublicKey, encodedNonces string,
|
||||||
|
) error {
|
||||||
|
session, ok := s.treeSigningSessions[roundID]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf(`signing session not found for round "%s"`, roundID)
|
||||||
|
}
|
||||||
|
|
||||||
|
nonces, err := bitcointree.DecodeNonces(hex.NewDecoder(strings.NewReader(encodedNonces)))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decode nonces: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
session.lock.Lock()
|
||||||
|
defer session.lock.Unlock()
|
||||||
|
|
||||||
|
if _, ok := session.nonces[pubkey]; ok {
|
||||||
|
return nil // skip if we already have nonces for this pubkey
|
||||||
|
}
|
||||||
|
|
||||||
|
session.nonces[pubkey] = nonces
|
||||||
|
|
||||||
|
if len(session.nonces) == session.nbCosigners-1 { // exclude the ASP
|
||||||
|
session.nonceDoneC <- struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *covenantlessService) RegisterCosignerSignatures(
|
||||||
|
ctx context.Context, roundID string, pubkey *secp256k1.PublicKey, encodedSignatures string,
|
||||||
|
) error {
|
||||||
|
session, ok := s.treeSigningSessions[roundID]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf(`signing session not found for round "%s"`, roundID)
|
||||||
|
}
|
||||||
|
|
||||||
|
signatures, err := bitcointree.DecodeSignatures(hex.NewDecoder(strings.NewReader(encodedSignatures)))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decode signatures: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
session.lock.Lock()
|
||||||
|
defer session.lock.Unlock()
|
||||||
|
|
||||||
|
if _, ok := session.signatures[pubkey]; ok {
|
||||||
|
return nil // skip if we already have signatures for this pubkey
|
||||||
|
}
|
||||||
|
|
||||||
|
session.signatures[pubkey] = signatures
|
||||||
|
|
||||||
|
if len(session.signatures) == session.nbCosigners-1 { // exclude the ASP
|
||||||
|
session.sigDoneC <- struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *covenantlessService) start() {
|
func (s *covenantlessService) start() {
|
||||||
s.startRound()
|
s.startRound()
|
||||||
}
|
}
|
||||||
@@ -375,6 +450,7 @@ func (s *covenantlessService) startRound() {
|
|||||||
round := domain.NewRound(dustAmount) // TODO dynamic dust amount?
|
round := domain.NewRound(dustAmount) // TODO dynamic dust amount?
|
||||||
//nolint:all
|
//nolint:all
|
||||||
round.StartRegistration()
|
round.StartRegistration()
|
||||||
|
s.lastEvent = nil
|
||||||
s.currentRound = round
|
s.currentRound = round
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -389,8 +465,12 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
round := s.currentRound
|
round := s.currentRound
|
||||||
|
|
||||||
|
roundRemainingDuration := time.Duration(s.roundInterval/2-1) * time.Second
|
||||||
|
thirdOfRemainingDuration := time.Duration(roundRemainingDuration / 3)
|
||||||
|
|
||||||
var roundAborted bool
|
var roundAborted bool
|
||||||
defer func() {
|
defer func() {
|
||||||
|
delete(s.treeSigningSessions, round.Id)
|
||||||
if roundAborted {
|
if roundAborted {
|
||||||
s.startRound()
|
s.startRound()
|
||||||
return
|
return
|
||||||
@@ -404,7 +484,7 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
s.startRound()
|
s.startRound()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
time.Sleep(time.Duration((s.roundInterval/2)-1) * time.Second)
|
time.Sleep(thirdOfRemainingDuration)
|
||||||
s.finalizeRound()
|
s.finalizeRound()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -424,7 +504,14 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
if num > paymentsThreshold {
|
if num > paymentsThreshold {
|
||||||
num = paymentsThreshold
|
num = paymentsThreshold
|
||||||
}
|
}
|
||||||
payments := s.paymentRequests.pop(num)
|
payments, cosigners := s.paymentRequests.pop(num)
|
||||||
|
if len(payments) > len(cosigners) {
|
||||||
|
err := fmt.Errorf("missing ephemeral key for payments")
|
||||||
|
round.Fail(fmt.Errorf("round aborted: %s", err))
|
||||||
|
log.WithError(err).Debugf("round %s aborted", round.Id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := round.RegisterPayments(payments); err != nil {
|
if _, err := round.RegisterPayments(payments); err != nil {
|
||||||
round.Fail(fmt.Errorf("failed to register payments: %s", err))
|
round.Fail(fmt.Errorf("failed to register payments: %s", err))
|
||||||
log.WithError(err).Warn("failed to register payments")
|
log.WithError(err).Warn("failed to register payments")
|
||||||
@@ -438,32 +525,16 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cosigners := make([]*secp256k1.PrivateKey, 0)
|
ephemeralKey, err := secp256k1.GeneratePrivateKey()
|
||||||
cosignersPubKeys := make([]*secp256k1.PublicKey, 0, len(cosigners))
|
|
||||||
for range payments {
|
|
||||||
// TODO sender should provide the ephemeral *public* key
|
|
||||||
ephemeralKey, err := secp256k1.GeneratePrivateKey()
|
|
||||||
if err != nil {
|
|
||||||
round.Fail(fmt.Errorf("failed to generate ephemeral key: %s", err))
|
|
||||||
log.WithError(err).Warn("failed to generate ephemeral key")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cosigners = append(cosigners, ephemeralKey)
|
|
||||||
cosignersPubKeys = append(cosignersPubKeys, ephemeralKey.PubKey())
|
|
||||||
}
|
|
||||||
|
|
||||||
aspSigningKey, err := secp256k1.GeneratePrivateKey()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
round.Fail(fmt.Errorf("failed to generate asp signing key: %s", err))
|
round.Fail(fmt.Errorf("failed to generate ephemeral key: %s", err))
|
||||||
log.WithError(err).Warn("failed to generate asp signing key")
|
log.WithError(err).Warn("failed to generate ephemeral key")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cosigners = append(cosigners, aspSigningKey)
|
cosigners = append(cosigners, ephemeralKey.PubKey())
|
||||||
cosignersPubKeys = append(cosignersPubKeys, aspSigningKey.PubKey())
|
|
||||||
|
|
||||||
unsignedPoolTx, tree, connectorAddress, err := s.builder.BuildPoolTx(s.pubkey, payments, s.minRelayFee, sweptRounds, cosignersPubKeys...)
|
unsignedPoolTx, tree, connectorAddress, err := s.builder.BuildPoolTx(s.pubkey, payments, s.minRelayFee, sweptRounds, cosigners...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
round.Fail(fmt.Errorf("failed to create pool tx: %s", err))
|
round.Fail(fmt.Errorf("failed to create pool tx: %s", err))
|
||||||
log.WithError(err).Warn("failed to create pool tx")
|
log.WithError(err).Warn("failed to create pool tx")
|
||||||
@@ -472,6 +543,16 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
log.Debugf("pool tx created for round %s", round.Id)
|
log.Debugf("pool tx created for round %s", round.Id)
|
||||||
|
|
||||||
if len(tree) > 0 {
|
if len(tree) > 0 {
|
||||||
|
log.Debugf("signing congestion tree for round %s", round.Id)
|
||||||
|
|
||||||
|
signingSession := newMusigSigningSession(len(cosigners))
|
||||||
|
s.treeSigningSessions[round.Id] = signingSession
|
||||||
|
|
||||||
|
log.Debugf("signing session created for round %s", round.Id)
|
||||||
|
|
||||||
|
// send back the unsigned tree & all cosigners pubkeys
|
||||||
|
s.propagateRoundSigningStartedEvent(tree, cosigners)
|
||||||
|
|
||||||
sweepClosure := bitcointree.CSVSigClosure{
|
sweepClosure := bitcointree.CSVSigClosure{
|
||||||
Pubkey: s.pubkey,
|
Pubkey: s.pubkey,
|
||||||
Seconds: uint(s.roundLifetime),
|
Seconds: uint(s.roundLifetime),
|
||||||
@@ -485,37 +566,50 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
sweepTapTree := txscript.AssembleTaprootScriptTree(*sweepTapLeaf)
|
sweepTapTree := txscript.AssembleTaprootScriptTree(*sweepTapLeaf)
|
||||||
root := sweepTapTree.RootNode.TapHash()
|
root := sweepTapTree.RootNode.TapHash()
|
||||||
|
|
||||||
coordinator, err := s.createTreeCoordinatorSession(tree, cosignersPubKeys, root)
|
coordinator, err := s.createTreeCoordinatorSession(tree, cosigners, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
round.Fail(fmt.Errorf("failed to create tree coordinator: %s", err))
|
round.Fail(fmt.Errorf("failed to create tree coordinator: %s", err))
|
||||||
log.WithError(err).Warn("failed to create tree coordinator")
|
log.WithError(err).Warn("failed to create tree coordinator")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
signers := make([]bitcointree.SignerSession, 0)
|
aspSignerSession := bitcointree.NewTreeSignerSession(
|
||||||
|
ephemeralKey, tree, int64(s.minRelayFee), root.CloneBytes(),
|
||||||
|
)
|
||||||
|
|
||||||
for _, seckey := range cosigners {
|
nonces, err := aspSignerSession.GetNonces()
|
||||||
signer := bitcointree.NewTreeSignerSession(
|
if err != nil {
|
||||||
seckey, tree, int64(s.minRelayFee), root.CloneBytes(),
|
round.Fail(fmt.Errorf("failed to get nonces: %s", err))
|
||||||
)
|
log.WithError(err).Warn("failed to get nonces")
|
||||||
|
return
|
||||||
// TODO nonces should be sent by the sender
|
|
||||||
nonces, err := signer.GetNonces()
|
|
||||||
if err != nil {
|
|
||||||
round.Fail(fmt.Errorf("failed to get nonces: %s", err))
|
|
||||||
log.WithError(err).Warn("failed to get nonces")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := coordinator.AddNonce(seckey.PubKey(), nonces); err != nil {
|
|
||||||
round.Fail(fmt.Errorf("failed to add nonce: %s", err))
|
|
||||||
log.WithError(err).Warn("failed to add nonce")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
signers = append(signers, signer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := coordinator.AddNonce(ephemeralKey.PubKey(), nonces); err != nil {
|
||||||
|
round.Fail(fmt.Errorf("failed to add nonce: %s", err))
|
||||||
|
log.WithError(err).Warn("failed to add nonce")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
noncesTimer := time.NewTimer(thirdOfRemainingDuration)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-noncesTimer.C:
|
||||||
|
round.Fail(fmt.Errorf("musig2 signing session timed out (nonce collection)"))
|
||||||
|
log.Warn("musig2 signing session timed out (nonce collection)")
|
||||||
|
return
|
||||||
|
case <-signingSession.nonceDoneC:
|
||||||
|
noncesTimer.Stop()
|
||||||
|
for pubkey, nonce := range signingSession.nonces {
|
||||||
|
if err := coordinator.AddNonce(pubkey, nonce); err != nil {
|
||||||
|
round.Fail(fmt.Errorf("failed to add nonce: %s", err))
|
||||||
|
log.WithError(err).Warn("failed to add nonce")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("nonces collected for round %s", round.Id)
|
||||||
|
|
||||||
aggragatedNonces, err := coordinator.AggregateNonces()
|
aggragatedNonces, err := coordinator.AggregateNonces()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
round.Fail(fmt.Errorf("failed to aggregate nonces: %s", err))
|
round.Fail(fmt.Errorf("failed to aggregate nonces: %s", err))
|
||||||
@@ -523,36 +617,69 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO aggragated nonces and public keys should be sent back to signer
|
log.Debugf("nonces aggregated for round %s", round.Id)
|
||||||
// TODO signing should be done client-side (except for the ASP)
|
|
||||||
for i, signer := range signers {
|
|
||||||
if err := signer.SetKeys(cosignersPubKeys, aggragatedNonces); err != nil {
|
|
||||||
round.Fail(fmt.Errorf("failed to set keys: %s", err))
|
|
||||||
log.WithError(err).Warn("failed to set keys")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
sig, err := signer.Sign()
|
s.propagateRoundSigningNoncesGeneratedEvent(aggragatedNonces)
|
||||||
if err != nil {
|
|
||||||
round.Fail(fmt.Errorf("failed to sign: %s", err))
|
|
||||||
log.WithError(err).Warn("failed to sign")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := coordinator.AddSig(cosignersPubKeys[i], sig); err != nil {
|
if err := aspSignerSession.SetKeys(cosigners); err != nil {
|
||||||
round.Fail(fmt.Errorf("failed to add sig: %s", err))
|
round.Fail(fmt.Errorf("failed to set keys: %s", err))
|
||||||
log.WithError(err).Warn("failed to add sig")
|
log.WithError(err).Warn("failed to set keys")
|
||||||
return
|
return
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
signedTree, err := coordinator.SignTree()
|
if err := aspSignerSession.SetAggregatedNonces(aggragatedNonces); err != nil {
|
||||||
|
round.Fail(fmt.Errorf("failed to set aggregated nonces: %s", err))
|
||||||
|
log.WithError(err).Warn("failed to set aggregated nonces")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// sign the tree as ASP
|
||||||
|
aspTreeSigs, err := aspSignerSession.Sign()
|
||||||
if err != nil {
|
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 {
|
||||||
|
round.Fail(fmt.Errorf("failed to add signature: %s", err))
|
||||||
|
log.WithError(err).Warn("failed to add signature")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("ASP tree signed for round %s", round.Id)
|
||||||
|
|
||||||
|
signaturesTimer := time.NewTimer(thirdOfRemainingDuration)
|
||||||
|
|
||||||
|
log.Debugf("waiting for cosigners to sign the tree")
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-signaturesTimer.C:
|
||||||
|
round.Fail(fmt.Errorf("musig2 signing session timed out (signatures)"))
|
||||||
|
log.Warn("musig2 signing session timed out (signatures)")
|
||||||
|
return
|
||||||
|
case <-signingSession.sigDoneC:
|
||||||
|
signaturesTimer.Stop()
|
||||||
|
for pubkey, sig := range signingSession.signatures {
|
||||||
|
if err := coordinator.AddSig(pubkey, sig); err != nil {
|
||||||
|
round.Fail(fmt.Errorf("failed to add signature: %s", err))
|
||||||
|
log.WithError(err).Warn("failed to add signature")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("signatures collected for round %s", round.Id)
|
||||||
|
|
||||||
|
signedTree, err := coordinator.SignTree()
|
||||||
|
if err != nil {
|
||||||
|
round.Fail(fmt.Errorf("failed to aggragate tree signatures: %s", err))
|
||||||
|
log.WithError(err).Warn("failed aggragate tree signatures")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("congestion tree signed for round %s", round.Id)
|
||||||
|
|
||||||
tree = signedTree
|
tree = signedTree
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,6 +705,29 @@ func (s *covenantlessService) startFinalization() {
|
|||||||
log.Debugf("started finalization stage for round: %s", round.Id)
|
log.Debugf("started finalization stage for round: %s", round.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *covenantlessService) propagateRoundSigningStartedEvent(
|
||||||
|
unsignedCongestionTree tree.CongestionTree, cosigners []*secp256k1.PublicKey,
|
||||||
|
) {
|
||||||
|
ev := RoundSigningStarted{
|
||||||
|
Id: s.currentRound.Id,
|
||||||
|
UnsignedVtxoTree: unsignedCongestionTree,
|
||||||
|
Cosigners: cosigners,
|
||||||
|
}
|
||||||
|
|
||||||
|
s.lastEvent = ev
|
||||||
|
s.eventsCh <- ev
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *covenantlessService) propagateRoundSigningNoncesGeneratedEvent(combinedNonces bitcointree.TreeNonces) {
|
||||||
|
ev := RoundSigningNoncesGenerated{
|
||||||
|
Id: s.currentRound.Id,
|
||||||
|
Nonces: combinedNonces,
|
||||||
|
}
|
||||||
|
|
||||||
|
s.lastEvent = ev
|
||||||
|
s.eventsCh <- ev
|
||||||
|
}
|
||||||
|
|
||||||
func (s *covenantlessService) createTreeCoordinatorSession(
|
func (s *covenantlessService) createTreeCoordinatorSession(
|
||||||
congestionTree tree.CongestionTree, cosigners []*secp256k1.PublicKey, root chainhash.Hash,
|
congestionTree tree.CongestionTree, cosigners []*secp256k1.PublicKey, root chainhash.Hash,
|
||||||
) (bitcointree.CoordinatorSession, error) {
|
) (bitcointree.CoordinatorSession, error) {
|
||||||
@@ -900,14 +1050,17 @@ func (s *covenantlessService) propagateEvents(round *domain.Round) {
|
|||||||
switch e := lastEvent.(type) {
|
switch e := lastEvent.(type) {
|
||||||
case domain.RoundFinalizationStarted:
|
case domain.RoundFinalizationStarted:
|
||||||
forfeitTxs := s.forfeitTxs.view()
|
forfeitTxs := s.forfeitTxs.view()
|
||||||
s.eventsCh <- domain.RoundFinalizationStarted{
|
ev := domain.RoundFinalizationStarted{
|
||||||
Id: e.Id,
|
Id: e.Id,
|
||||||
CongestionTree: e.CongestionTree,
|
CongestionTree: e.CongestionTree,
|
||||||
Connectors: e.Connectors,
|
Connectors: e.Connectors,
|
||||||
PoolTx: e.PoolTx,
|
PoolTx: e.PoolTx,
|
||||||
UnsignedForfeitTxs: forfeitTxs,
|
UnsignedForfeitTxs: forfeitTxs,
|
||||||
}
|
}
|
||||||
|
s.lastEvent = ev
|
||||||
|
s.eventsCh <- ev
|
||||||
case domain.RoundFinalized, domain.RoundFailed:
|
case domain.RoundFinalized, domain.RoundFailed:
|
||||||
|
s.lastEvent = e
|
||||||
s.eventsCh <- e
|
s.eventsCh <- e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1118,3 +1271,26 @@ func findForfeitTxBitcoin(
|
|||||||
|
|
||||||
return "", fmt.Errorf("forfeit tx not found")
|
return "", fmt.Errorf("forfeit tx not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// musigSigningSession holds the state of ephemeral nonces and signatures in order to coordinate the signing of the tree
|
||||||
|
type musigSigningSession struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
nbCosigners int
|
||||||
|
nonces map[*secp256k1.PublicKey]bitcointree.TreeNonces
|
||||||
|
nonceDoneC chan struct{}
|
||||||
|
|
||||||
|
signatures map[*secp256k1.PublicKey]bitcointree.TreePartialSigs
|
||||||
|
sigDoneC chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMusigSigningSession(nbCosigners int) *musigSigningSession {
|
||||||
|
return &musigSigningSession{
|
||||||
|
nonces: make(map[*secp256k1.PublicKey]bitcointree.TreeNonces),
|
||||||
|
nonceDoneC: make(chan struct{}),
|
||||||
|
|
||||||
|
signatures: make(map[*secp256k1.PublicKey]bitcointree.TreePartialSigs),
|
||||||
|
sigDoneC: make(chan struct{}),
|
||||||
|
lock: sync.Mutex{},
|
||||||
|
nbCosigners: nbCosigners,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
43
server/internal/core/application/covenantless_event.go
Normal file
43
server/internal/core/application/covenantless_event.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* This package contains intermediary events that are used only by the covenantless version
|
||||||
|
* they let to sign the congestion tree using musig2 algorithm
|
||||||
|
* they are not included in domain because they don't mutate the Round state and should not be persisted
|
||||||
|
*/
|
||||||
|
package application
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
|
||||||
|
"github.com/ark-network/ark/common/bitcointree"
|
||||||
|
"github.com/ark-network/ark/common/tree"
|
||||||
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// signer should react to this event by generating a musig2 nonce for each transaction in the tree
|
||||||
|
type RoundSigningStarted struct {
|
||||||
|
Id string
|
||||||
|
UnsignedVtxoTree tree.CongestionTree
|
||||||
|
Cosigners []*secp256k1.PublicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// signer should react to this event by partially signing the vtxo tree transactions
|
||||||
|
// then, delete its ephemeral key
|
||||||
|
type RoundSigningNoncesGenerated struct {
|
||||||
|
Id string
|
||||||
|
Nonces bitcointree.TreeNonces // aggregated nonces
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e RoundSigningNoncesGenerated) SerializeNonces() (string, error) {
|
||||||
|
var serialized bytes.Buffer
|
||||||
|
|
||||||
|
if err := e.Nonces.Encode(&serialized); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex.EncodeToString(serialized.Bytes()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// implement domain.RoundEvent interface
|
||||||
|
func (r RoundSigningStarted) IsEvent() {}
|
||||||
|
func (r RoundSigningNoncesGenerated) IsEvent() {}
|
||||||
@@ -149,7 +149,6 @@ func (s *sweeper) createTask(
|
|||||||
for _, input := range inputs {
|
for _, input := range inputs {
|
||||||
// sweepableVtxos related to the sweep input
|
// sweepableVtxos related to the sweep input
|
||||||
sweepableVtxos := make([]domain.VtxoKey, 0)
|
sweepableVtxos := make([]domain.VtxoKey, 0)
|
||||||
fmt.Println("input", input.GetHash().String(), input.GetIndex())
|
|
||||||
|
|
||||||
// check if input is the vtxo itself
|
// check if input is the vtxo itself
|
||||||
vtxos, _ := s.repoManager.Vtxos().GetVtxos(
|
vtxos, _ := s.repoManager.Vtxos().GetVtxos(
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ type Service interface {
|
|||||||
GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent
|
GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent
|
||||||
UpdatePaymentStatus(
|
UpdatePaymentStatus(
|
||||||
ctx context.Context, paymentId string,
|
ctx context.Context, paymentId string,
|
||||||
) (unsignedForfeitTxs []string, currentRound *domain.Round, err error)
|
) (lastEvent domain.RoundEvent, err error)
|
||||||
ListVtxos(
|
ListVtxos(
|
||||||
ctx context.Context, pubkey *secp256k1.PublicKey,
|
ctx context.Context, pubkey *secp256k1.PublicKey,
|
||||||
) (spendableVtxos, spentVtxos []domain.Vtxo, err error)
|
) (spendableVtxos, spentVtxos []domain.Vtxo, err error)
|
||||||
@@ -41,6 +41,16 @@ type Service interface {
|
|||||||
CompleteAsyncPayment(
|
CompleteAsyncPayment(
|
||||||
ctx context.Context, redeemTx string, unconditionalForfeitTxs []string,
|
ctx context.Context, redeemTx string, unconditionalForfeitTxs []string,
|
||||||
) error
|
) error
|
||||||
|
// Tree signing methods
|
||||||
|
RegisterCosignerPubkey(ctx context.Context, paymentId string, ephemeralPublicKey string) error
|
||||||
|
RegisterCosignerNonces(
|
||||||
|
ctx context.Context, roundID string,
|
||||||
|
pubkey *secp256k1.PublicKey, nonces string,
|
||||||
|
) error
|
||||||
|
RegisterCosignerSignatures(
|
||||||
|
ctx context.Context, roundID string,
|
||||||
|
pubkey *secp256k1.PublicKey, signatures string,
|
||||||
|
) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceInfo struct {
|
type ServiceInfo struct {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/ark-network/ark/common/tree"
|
"github.com/ark-network/ark/common/tree"
|
||||||
"github.com/ark-network/ark/server/internal/core/domain"
|
"github.com/ark-network/ark/server/internal/core/domain"
|
||||||
"github.com/ark-network/ark/server/internal/core/ports"
|
"github.com/ark-network/ark/server/internal/core/ports"
|
||||||
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,8 +21,9 @@ type timedPayment struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type paymentsMap struct {
|
type paymentsMap struct {
|
||||||
lock *sync.RWMutex
|
lock *sync.RWMutex
|
||||||
payments map[string]*timedPayment
|
payments map[string]*timedPayment
|
||||||
|
ephemeralKeys map[string]*secp256k1.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPaymentsMap(payments []domain.Payment) *paymentsMap {
|
func newPaymentsMap(payments []domain.Payment) *paymentsMap {
|
||||||
@@ -30,7 +32,7 @@ func newPaymentsMap(payments []domain.Payment) *paymentsMap {
|
|||||||
paymentsById[p.Id] = &timedPayment{p, time.Now(), time.Time{}}
|
paymentsById[p.Id] = &timedPayment{p, time.Now(), time.Time{}}
|
||||||
}
|
}
|
||||||
lock := &sync.RWMutex{}
|
lock := &sync.RWMutex{}
|
||||||
return &paymentsMap{lock, paymentsById}
|
return &paymentsMap{lock, paymentsById, make(map[string]*secp256k1.PublicKey)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *paymentsMap) len() int64 {
|
func (m *paymentsMap) len() int64 {
|
||||||
@@ -46,6 +48,18 @@ func (m *paymentsMap) len() int64 {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *paymentsMap) delete(id string) error {
|
||||||
|
m.lock.Lock()
|
||||||
|
defer m.lock.Unlock()
|
||||||
|
|
||||||
|
if _, ok := m.payments[id]; !ok {
|
||||||
|
return errPaymentNotFound{id}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(m.payments, id)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *paymentsMap) push(payment domain.Payment) error {
|
func (m *paymentsMap) push(payment domain.Payment) error {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
@@ -58,7 +72,19 @@ func (m *paymentsMap) push(payment domain.Payment) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *paymentsMap) pop(num int64) []domain.Payment {
|
func (m *paymentsMap) pushEphemeralKey(paymentId string, pubkey *secp256k1.PublicKey) error {
|
||||||
|
m.lock.Lock()
|
||||||
|
defer m.lock.Unlock()
|
||||||
|
|
||||||
|
if _, ok := m.payments[paymentId]; !ok {
|
||||||
|
return fmt.Errorf("payment %s not found, cannot register signing ephemeral public key", paymentId)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.ephemeralKeys[paymentId] = pubkey
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *paymentsMap) pop(num int64) ([]domain.Payment, []*secp256k1.PublicKey) {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
|
|
||||||
@@ -83,11 +109,16 @@ func (m *paymentsMap) pop(num int64) []domain.Payment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
payments := make([]domain.Payment, 0, num)
|
payments := make([]domain.Payment, 0, num)
|
||||||
|
cosigners := make([]*secp256k1.PublicKey, 0, num)
|
||||||
for _, p := range paymentsByTime[:num] {
|
for _, p := range paymentsByTime[:num] {
|
||||||
payments = append(payments, p.Payment)
|
payments = append(payments, p.Payment)
|
||||||
|
if pubkey, ok := m.ephemeralKeys[p.Payment.Id]; ok {
|
||||||
|
cosigners = append(cosigners, pubkey)
|
||||||
|
delete(m.ephemeralKeys, p.Payment.Id)
|
||||||
|
}
|
||||||
delete(m.payments, p.Id)
|
delete(m.payments, p.Id)
|
||||||
}
|
}
|
||||||
return payments
|
return payments, cosigners
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *paymentsMap) update(payment domain.Payment) error {
|
func (m *paymentsMap) update(payment domain.Payment) error {
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ package domain
|
|||||||
import "github.com/ark-network/ark/common/tree"
|
import "github.com/ark-network/ark/common/tree"
|
||||||
|
|
||||||
type RoundEvent interface {
|
type RoundEvent interface {
|
||||||
isEvent()
|
IsEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r RoundStarted) isEvent() {}
|
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 PaymentsRegistered) IsEvent() {}
|
||||||
|
|
||||||
type RoundStarted struct {
|
type RoundStarted struct {
|
||||||
Id string
|
Id string
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/ark-network/ark/server/internal/core/domain"
|
"github.com/ark-network/ark/server/internal/core/domain"
|
||||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
@@ -118,25 +119,77 @@ func (h *handler) Ping(ctx context.Context, req *arkv1.PingRequest) (*arkv1.Ping
|
|||||||
return nil, status.Error(codes.InvalidArgument, "missing payment id")
|
return nil, status.Error(codes.InvalidArgument, "missing payment id")
|
||||||
}
|
}
|
||||||
|
|
||||||
forfeits, round, err := h.svc.UpdatePaymentStatus(ctx, req.GetPaymentId())
|
lastEvent, err := h.svc.UpdatePaymentStatus(ctx, req.GetPaymentId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var event *arkv1.RoundFinalizationEvent
|
var resp *arkv1.PingResponse
|
||||||
if round != nil {
|
|
||||||
event = &arkv1.RoundFinalizationEvent{
|
switch e := lastEvent.(type) {
|
||||||
Id: round.Id,
|
case domain.RoundFinalizationStarted:
|
||||||
PoolTx: round.UnsignedTx,
|
resp = &arkv1.PingResponse{
|
||||||
ForfeitTxs: forfeits,
|
Event: &arkv1.PingResponse_RoundFinalization{
|
||||||
CongestionTree: castCongestionTree(round.CongestionTree),
|
RoundFinalization: &arkv1.RoundFinalizationEvent{
|
||||||
Connectors: round.Connectors,
|
Id: e.Id,
|
||||||
|
PoolTx: e.PoolTx,
|
||||||
|
CongestionTree: castCongestionTree(e.CongestionTree),
|
||||||
|
ForfeitTxs: e.UnsignedForfeitTxs,
|
||||||
|
Connectors: e.Connectors,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
case domain.RoundFinalized:
|
||||||
|
resp = &arkv1.PingResponse{
|
||||||
|
Event: &arkv1.PingResponse_RoundFinalized{
|
||||||
|
RoundFinalized: &arkv1.RoundFinalizedEvent{
|
||||||
|
Id: e.Id,
|
||||||
|
PoolTxid: e.Txid,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
case domain.RoundFailed:
|
||||||
|
resp = &arkv1.PingResponse{
|
||||||
|
Event: &arkv1.PingResponse_RoundFailed{
|
||||||
|
RoundFailed: &arkv1.RoundFailed{
|
||||||
|
Id: e.Id,
|
||||||
|
Reason: e.Err,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
case application.RoundSigningStarted:
|
||||||
|
cosignersKeys := make([]string, 0, len(e.Cosigners))
|
||||||
|
for _, key := range e.Cosigners {
|
||||||
|
cosignersKeys = append(cosignersKeys, hex.EncodeToString(key.SerializeCompressed()))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = &arkv1.PingResponse{
|
||||||
|
Event: &arkv1.PingResponse_RoundSigning{
|
||||||
|
RoundSigning: &arkv1.RoundSigningEvent{
|
||||||
|
Id: e.Id,
|
||||||
|
CosignersPubkeys: cosignersKeys,
|
||||||
|
UnsignedTree: castCongestionTree(e.UnsignedVtxoTree),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
case application.RoundSigningNoncesGenerated:
|
||||||
|
serialized, err := e.SerializeNonces()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("failed to serialize nonces")
|
||||||
|
return nil, status.Error(codes.Internal, "failed to serialize nonces")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = &arkv1.PingResponse{
|
||||||
|
Event: &arkv1.PingResponse_RoundSigningNoncesGenerated{
|
||||||
|
RoundSigningNoncesGenerated: &arkv1.RoundSigningNoncesGeneratedEvent{
|
||||||
|
Id: e.Id,
|
||||||
|
TreeNonces: serialized,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &arkv1.PingResponse{
|
|
||||||
ForfeitTxs: forfeits,
|
return resp, nil
|
||||||
Event: event,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) RegisterPayment(ctx context.Context, req *arkv1.RegisterPaymentRequest) (*arkv1.RegisterPaymentResponse, error) {
|
func (h *handler) RegisterPayment(ctx context.Context, req *arkv1.RegisterPaymentRequest) (*arkv1.RegisterPaymentResponse, error) {
|
||||||
@@ -150,6 +203,13 @@ func (h *handler) RegisterPayment(ctx context.Context, req *arkv1.RegisterPaymen
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pubkey := req.GetEphemeralPubkey()
|
||||||
|
if len(pubkey) > 0 {
|
||||||
|
if err := h.svc.RegisterCosignerPubkey(ctx, id, pubkey); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &arkv1.RegisterPaymentResponse{
|
return &arkv1.RegisterPaymentResponse{
|
||||||
Id: id,
|
Id: id,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -267,14 +327,6 @@ func (h *handler) GetEventStream(_ *arkv1.GetEventStreamRequest, stream arkv1.Ar
|
|||||||
if err := stream.Send(ev); err != nil {
|
if err := stream.Send(ev); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ev.Event.(type) {
|
|
||||||
case *arkv1.GetEventStreamResponse_RoundFinalized, *arkv1.GetEventStreamResponse_RoundFailed:
|
|
||||||
if err := stream.Send(ev); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -312,6 +364,74 @@ func (h *handler) GetInfo(ctx context.Context, req *arkv1.GetInfoRequest) (*arkv
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *handler) SendTreeNonces(ctx context.Context, req *arkv1.SendTreeNoncesRequest) (*arkv1.SendTreeNoncesResponse, error) {
|
||||||
|
pubkey := req.GetPublicKey()
|
||||||
|
encodedNonces := req.GetTreeNonces()
|
||||||
|
roundID := req.GetRoundId()
|
||||||
|
|
||||||
|
if len(pubkey) <= 0 {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "missing cosigner public key")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(encodedNonces) <= 0 {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "missing tree nonces")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(roundID) <= 0 {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "missing round id")
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkeyBytes, err := hex.DecodeString(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key")
|
||||||
|
}
|
||||||
|
|
||||||
|
cosignerPublicKey, err := secp256k1.ParsePubKey(pubkeyBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.svc.RegisterCosignerNonces(ctx, roundID, cosignerPublicKey, encodedNonces); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &arkv1.SendTreeNoncesResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) SendTreeSignatures(ctx context.Context, req *arkv1.SendTreeSignaturesRequest) (*arkv1.SendTreeSignaturesResponse, error) {
|
||||||
|
roundID := req.GetRoundId()
|
||||||
|
pubkey := req.GetPublicKey()
|
||||||
|
encodedSignatures := req.GetTreeSignatures()
|
||||||
|
|
||||||
|
if len(pubkey) <= 0 {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "missing cosigner public key")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(encodedSignatures) <= 0 {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "missing tree signatures")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(roundID) <= 0 {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "missing round id")
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkeyBytes, err := hex.DecodeString(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key")
|
||||||
|
}
|
||||||
|
|
||||||
|
cosignerPublicKey, err := secp256k1.ParsePubKey(pubkeyBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.svc.RegisterCosignerSignatures(ctx, roundID, cosignerPublicKey, encodedSignatures); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &arkv1.SendTreeSignaturesResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (h *handler) pushListener(l *listener) {
|
func (h *handler) pushListener(l *listener) {
|
||||||
h.listenersLock.Lock()
|
h.listenersLock.Lock()
|
||||||
defer h.listenersLock.Unlock()
|
defer h.listenersLock.Unlock()
|
||||||
@@ -368,6 +488,36 @@ func (h *handler) listenToEvents() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
case application.RoundSigningStarted:
|
||||||
|
cosignersKeys := make([]string, 0, len(e.Cosigners))
|
||||||
|
for _, key := range e.Cosigners {
|
||||||
|
cosignersKeys = append(cosignersKeys, hex.EncodeToString(key.SerializeCompressed()))
|
||||||
|
}
|
||||||
|
|
||||||
|
ev = &arkv1.GetEventStreamResponse{
|
||||||
|
Event: &arkv1.GetEventStreamResponse_RoundSigning{
|
||||||
|
RoundSigning: &arkv1.RoundSigningEvent{
|
||||||
|
Id: e.Id,
|
||||||
|
CosignersPubkeys: cosignersKeys,
|
||||||
|
UnsignedTree: castCongestionTree(e.UnsignedVtxoTree),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
case application.RoundSigningNoncesGenerated:
|
||||||
|
serialized, err := e.SerializeNonces()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("failed to serialize nonces")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ev = &arkv1.GetEventStreamResponse{
|
||||||
|
Event: &arkv1.GetEventStreamResponse_RoundSigningNoncesGenerated{
|
||||||
|
RoundSigningNoncesGenerated: &arkv1.RoundSigningNoncesGeneratedEvent{
|
||||||
|
Id: e.Id,
|
||||||
|
TreeNonces: serialized,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ev != nil {
|
if ev != nil {
|
||||||
|
|||||||
@@ -161,6 +161,14 @@ func Whitelist() map[string][]bakery.Op {
|
|||||||
Entity: EntityHealth,
|
Entity: EntityHealth,
|
||||||
Action: "read",
|
Action: "read",
|
||||||
}},
|
}},
|
||||||
|
fmt.Sprintf("/%s/SendTreeNonces", arkv1.ArkService_ServiceDesc.ServiceName): {{
|
||||||
|
Entity: EntityArk,
|
||||||
|
Action: "write",
|
||||||
|
}},
|
||||||
|
fmt.Sprintf("/%s/SendTreeSignatures", arkv1.ArkService_ServiceDesc.ServiceName): {{
|
||||||
|
Entity: EntityArk,
|
||||||
|
Action: "write",
|
||||||
|
}},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user