Add interface layer (#23)

* implement grpc interface

* rework GetEventStream rpc

* implement Ping & GetEventStream

* remove dev_portal

* Compile protos

* Empty gitignore

---------

Co-authored-by: altafan <18440657+altafan@users.noreply.github.com>
This commit is contained in:
Louis Singer
2023-12-01 17:13:28 +01:00
committed by GitHub
parent 7c2a70db91
commit c8d9db89c5
13 changed files with 1519 additions and 516 deletions

0
asp/internal/interface/grpc/handlers/.gitkeep → .gitignore vendored Executable file → Normal file
View File

View File

@@ -16,6 +16,37 @@
"application/json"
],
"paths": {
"/v1/events": {
"get": {
"operationId": "ArkService_GetEventStream",
"responses": {
"200": {
"description": "A successful response.(streaming responses)",
"schema": {
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/v1GetEventStreamResponse"
},
"error": {
"$ref": "#/definitions/rpcStatus"
}
},
"title": "Stream result of v1GetEventStreamResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"tags": [
"ArkService"
]
}
},
"/v1/payment/claim": {
"post": {
"operationId": "ArkService_ClaimPayment",
@@ -112,6 +143,36 @@
]
}
},
"/v1/ping/{paymentId}": {
"get": {
"operationId": "ArkService_Ping",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1PingResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "paymentId",
"in": "path",
"required": true,
"type": "string"
}
],
"tags": [
"ArkService"
]
}
},
"/v1/round/{txid}": {
"get": {
"operationId": "ArkService_GetRound",
@@ -141,38 +202,6 @@
"ArkService"
]
}
},
"/v1/rounds": {
"post": {
"operationId": "ArkService_ListRounds",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1ListRoundsResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v1ListRoundsRequest"
}
}
],
"tags": [
"ArkService"
]
}
}
},
"definitions": {
@@ -225,15 +254,32 @@
"v1FinalizePaymentRequest": {
"type": "object",
"properties": {
"signedVtx": {
"type": "string",
"description": "Forfeit tx signed also by the user."
"signedForfeits": {
"type": "array",
"items": {
"type": "string"
},
"description": "Forfeit txs signed by the user."
}
}
},
"v1FinalizePaymentResponse": {
"type": "object"
},
"v1GetEventStreamResponse": {
"type": "object",
"properties": {
"roundFinalization": {
"$ref": "#/definitions/v1RoundFinalizationEvent"
},
"roundFinalized": {
"$ref": "#/definitions/v1RoundFinalizedEvent"
},
"roundFailed": {
"$ref": "#/definitions/v1RoundFailed"
}
}
},
"v1GetRoundResponse": {
"type": "object",
"properties": {
@@ -242,30 +288,18 @@
}
}
},
"v1ListRoundsRequest": {
"v1Input": {
"type": "object",
"properties": {
"start": {
"type": "string",
"format": "int64"
"txid": {
"type": "string"
},
"end": {
"type": "string",
"vout": {
"type": "integer",
"format": "int64"
}
}
},
"v1ListRoundsResponse": {
"type": "object",
"properties": {
"rounds": {
"type": "array",
"items": {
"$ref": "#/definitions/v1Round"
}
}
}
},
"v1Output": {
"type": "object",
"properties": {
@@ -278,12 +312,17 @@
}
}
},
"v1PingResponse": {
"type": "object"
},
"v1RegisterPaymentRequest": {
"type": "object",
"properties": {
"vtx": {
"type": "string",
"description": "Unsigned forfeit tx sending all funds back to the ASP."
"inputs": {
"type": "array",
"items": {
"$ref": "#/definitions/v1Input"
}
}
}
},
@@ -293,16 +332,15 @@
"id": {
"type": "string",
"description": "Mocks wabisabi's credentials."
},
"signedVtx": {
"type": "string",
"description": "Forfeit tx signed by the ASP."
}
}
},
"v1Round": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"start": {
"type": "string",
"format": "int64"
@@ -314,13 +352,58 @@
"txid": {
"type": "string"
},
"outputs": {
"congestionTree": {
"type": "array",
"items": {
"$ref": "#/definitions/v1Output"
"type": "string"
}
}
}
},
"v1RoundFailed": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"reason": {
"type": "string"
}
}
},
"v1RoundFinalizationEvent": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"poolPartialTx": {
"type": "string"
},
"forfeitTxs": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"congestionTree": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"v1RoundFinalizedEvent": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"poolTxid": {
"type": "string"
}
}
}
}
}

View File

@@ -23,28 +23,29 @@ service ArkService {
body: "*"
};
};
rpc ListRounds(ListRoundsRequest) returns (ListRoundsResponse) {
option (google.api.http) = {
post: "/v1/rounds"
body: "*"
};
};
rpc GetRound(GetRoundRequest) returns (GetRoundResponse) {
option (google.api.http) = {
get: "/v1/round/{txid}"
};
};
rpc GetEventStream(GetEventStreamRequest) returns (stream GetEventStreamResponse) {
option (google.api.http) = {
get: "/v1/events"
};
};
rpc Ping(PingRequest) returns (PingResponse) {
option (google.api.http) = {
get: "/v1/ping/{payment_id}"
};
};
}
message RegisterPaymentRequest {
// Unsigned forfeit tx sending all funds back to the ASP.
string vtx = 1;
repeated Input inputs = 1;
}
message RegisterPaymentResponse {
// Mocks wabisabi's credentials.
string id = 1;
// Forfeit tx signed by the ASP.
string signed_vtx = 2;
}
message ClaimPaymentRequest {
@@ -56,19 +57,11 @@ message ClaimPaymentRequest {
message ClaimPaymentResponse {}
message FinalizePaymentRequest {
// Forfeit tx signed also by the user.
string signed_vtx = 1;
// Forfeit txs signed by the user.
repeated string signed_forfeits = 1;
}
message FinalizePaymentResponse {}
message ListRoundsRequest {
int64 start = 1;
int64 end = 2;
}
message ListRoundsResponse {
repeated Round rounds = 1;
}
message GetRoundRequest {
string txid = 1;
}
@@ -77,13 +70,53 @@ message GetRoundResponse {
}
message Round {
int64 start = 1;
int64 end = 2;
string txid = 3;
repeated Output outputs = 4;
string id = 1;
int64 start = 2;
int64 end = 3;
string txid = 4;
repeated string congestion_tree = 5;
}
message Input {
string txid = 1;
uint32 vout = 2;
}
message Output {
string pubkey = 1;
uint64 amount = 2;
}
}
message RoundFinalizationEvent {
string id = 1;
string pool_partial_tx = 2;
map<string, string> forfeit_txs = 3;
repeated string congestion_tree = 4;
}
message RoundFinalizedEvent {
string id = 1;
string pool_txid = 2;
}
message RoundFailed {
string id = 1;
string reason = 2;
}
message GetEventStreamRequest {}
message GetEventStreamResponse {
oneof event {
RoundFinalizationEvent round_finalization = 1;
RoundFinalizedEvent round_finalized = 2;
RoundFailed round_failed = 3;
}
}
message PingRequest {
string payment_id = 1;
}
message PingResponse {}

File diff suppressed because it is too large Load Diff

View File

@@ -133,40 +133,6 @@ func local_request_ArkService_FinalizePayment_0(ctx context.Context, marshaler r
}
func request_ArkService_ListRounds_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListRoundsRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ListRounds(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ArkService_ListRounds_0(ctx context.Context, marshaler runtime.Marshaler, server ArkServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListRoundsRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ListRounds(ctx, &protoReq)
return msg, metadata, err
}
func request_ArkService_GetRound_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetRoundRequest
var metadata runtime.ServerMetadata
@@ -219,6 +185,75 @@ func local_request_ArkService_GetRound_0(ctx context.Context, marshaler runtime.
}
func request_ArkService_GetEventStream_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (ArkService_GetEventStreamClient, runtime.ServerMetadata, error) {
var protoReq GetEventStreamRequest
var metadata runtime.ServerMetadata
stream, err := client.GetEventStream(ctx, &protoReq)
if err != nil {
return nil, metadata, err
}
header, err := stream.Header()
if err != nil {
return nil, metadata, err
}
metadata.HeaderMD = header
return stream, metadata, nil
}
func request_ArkService_Ping_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq PingRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["payment_id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "payment_id")
}
protoReq.PaymentId, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "payment_id", err)
}
msg, err := client.Ping(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ArkService_Ping_0(ctx context.Context, marshaler runtime.Marshaler, server ArkServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq PingRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["payment_id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "payment_id")
}
protoReq.PaymentId, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "payment_id", err)
}
msg, err := server.Ping(ctx, &protoReq)
return msg, metadata, err
}
// RegisterArkServiceHandlerServer registers the http handlers for service ArkService to "mux".
// UnaryRPC :call ArkServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
@@ -294,29 +329,6 @@ func RegisterArkServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux,
})
mux.Handle("POST", pattern_ArkService_ListRounds_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)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/ark.v1.ArkService/ListRounds", runtime.WithHTTPPathPattern("/v1/rounds"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ArkService_ListRounds_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ArkService_ListRounds_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ArkService_GetRound_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -340,6 +352,36 @@ func RegisterArkServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux,
})
mux.Handle("GET", pattern_ArkService_GetEventStream_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport")
_, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
})
mux.Handle("GET", pattern_ArkService_Ping_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)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/ark.v1.ArkService/Ping", runtime.WithHTTPPathPattern("/v1/ping/{payment_id}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ArkService_Ping_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ArkService_Ping_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
@@ -441,26 +483,6 @@ func RegisterArkServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux,
})
mux.Handle("POST", pattern_ArkService_ListRounds_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)
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/ark.v1.ArkService/ListRounds", runtime.WithHTTPPathPattern("/v1/rounds"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ArkService_ListRounds_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ArkService_ListRounds_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ArkService_GetRound_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -481,6 +503,46 @@ func RegisterArkServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux,
})
mux.Handle("GET", pattern_ArkService_GetEventStream_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)
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/ark.v1.ArkService/GetEventStream", runtime.WithHTTPPathPattern("/v1/events"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ArkService_GetEventStream_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ArkService_GetEventStream_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ArkService_Ping_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)
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/ark.v1.ArkService/Ping", runtime.WithHTTPPathPattern("/v1/ping/{payment_id}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ArkService_Ping_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ArkService_Ping_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
@@ -491,9 +553,11 @@ var (
pattern_ArkService_FinalizePayment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "payment", "finalize"}, ""))
pattern_ArkService_ListRounds_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "rounds"}, ""))
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_GetEventStream_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "events"}, ""))
pattern_ArkService_Ping_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "ping", "payment_id"}, ""))
)
var (
@@ -503,7 +567,9 @@ var (
forward_ArkService_FinalizePayment_0 = runtime.ForwardResponseMessage
forward_ArkService_ListRounds_0 = runtime.ForwardResponseMessage
forward_ArkService_GetRound_0 = runtime.ForwardResponseMessage
forward_ArkService_GetEventStream_0 = runtime.ForwardResponseStream
forward_ArkService_Ping_0 = runtime.ForwardResponseMessage
)

View File

@@ -21,8 +21,9 @@ type ArkServiceClient interface {
RegisterPayment(ctx context.Context, in *RegisterPaymentRequest, opts ...grpc.CallOption) (*RegisterPaymentResponse, error)
ClaimPayment(ctx context.Context, in *ClaimPaymentRequest, opts ...grpc.CallOption) (*ClaimPaymentResponse, error)
FinalizePayment(ctx context.Context, in *FinalizePaymentRequest, opts ...grpc.CallOption) (*FinalizePaymentResponse, error)
ListRounds(ctx context.Context, in *ListRoundsRequest, opts ...grpc.CallOption) (*ListRoundsResponse, error)
GetRound(ctx context.Context, in *GetRoundRequest, opts ...grpc.CallOption) (*GetRoundResponse, error)
GetEventStream(ctx context.Context, in *GetEventStreamRequest, opts ...grpc.CallOption) (ArkService_GetEventStreamClient, error)
Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error)
}
type arkServiceClient struct {
@@ -60,18 +61,50 @@ func (c *arkServiceClient) FinalizePayment(ctx context.Context, in *FinalizePaym
return out, nil
}
func (c *arkServiceClient) ListRounds(ctx context.Context, in *ListRoundsRequest, opts ...grpc.CallOption) (*ListRoundsResponse, error) {
out := new(ListRoundsResponse)
err := c.cc.Invoke(ctx, "/ark.v1.ArkService/ListRounds", in, out, opts...)
func (c *arkServiceClient) GetRound(ctx context.Context, in *GetRoundRequest, opts ...grpc.CallOption) (*GetRoundResponse, error) {
out := new(GetRoundResponse)
err := c.cc.Invoke(ctx, "/ark.v1.ArkService/GetRound", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *arkServiceClient) GetRound(ctx context.Context, in *GetRoundRequest, opts ...grpc.CallOption) (*GetRoundResponse, error) {
out := new(GetRoundResponse)
err := c.cc.Invoke(ctx, "/ark.v1.ArkService/GetRound", in, out, opts...)
func (c *arkServiceClient) GetEventStream(ctx context.Context, in *GetEventStreamRequest, opts ...grpc.CallOption) (ArkService_GetEventStreamClient, error) {
stream, err := c.cc.NewStream(ctx, &ArkService_ServiceDesc.Streams[0], "/ark.v1.ArkService/GetEventStream", opts...)
if err != nil {
return nil, err
}
x := &arkServiceGetEventStreamClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type ArkService_GetEventStreamClient interface {
Recv() (*GetEventStreamResponse, error)
grpc.ClientStream
}
type arkServiceGetEventStreamClient struct {
grpc.ClientStream
}
func (x *arkServiceGetEventStreamClient) Recv() (*GetEventStreamResponse, error) {
m := new(GetEventStreamResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *arkServiceClient) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) {
out := new(PingResponse)
err := c.cc.Invoke(ctx, "/ark.v1.ArkService/Ping", in, out, opts...)
if err != nil {
return nil, err
}
@@ -85,8 +118,9 @@ type ArkServiceServer interface {
RegisterPayment(context.Context, *RegisterPaymentRequest) (*RegisterPaymentResponse, error)
ClaimPayment(context.Context, *ClaimPaymentRequest) (*ClaimPaymentResponse, error)
FinalizePayment(context.Context, *FinalizePaymentRequest) (*FinalizePaymentResponse, error)
ListRounds(context.Context, *ListRoundsRequest) (*ListRoundsResponse, error)
GetRound(context.Context, *GetRoundRequest) (*GetRoundResponse, error)
GetEventStream(*GetEventStreamRequest, ArkService_GetEventStreamServer) error
Ping(context.Context, *PingRequest) (*PingResponse, error)
}
// UnimplementedArkServiceServer should be embedded to have forward compatible implementations.
@@ -102,12 +136,15 @@ func (UnimplementedArkServiceServer) ClaimPayment(context.Context, *ClaimPayment
func (UnimplementedArkServiceServer) FinalizePayment(context.Context, *FinalizePaymentRequest) (*FinalizePaymentResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method FinalizePayment not implemented")
}
func (UnimplementedArkServiceServer) ListRounds(context.Context, *ListRoundsRequest) (*ListRoundsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListRounds not implemented")
}
func (UnimplementedArkServiceServer) GetRound(context.Context, *GetRoundRequest) (*GetRoundResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetRound not implemented")
}
func (UnimplementedArkServiceServer) GetEventStream(*GetEventStreamRequest, ArkService_GetEventStreamServer) error {
return status.Errorf(codes.Unimplemented, "method GetEventStream not implemented")
}
func (UnimplementedArkServiceServer) Ping(context.Context, *PingRequest) (*PingResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Ping not implemented")
}
// UnsafeArkServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ArkServiceServer will
@@ -174,24 +211,6 @@ func _ArkService_FinalizePayment_Handler(srv interface{}, ctx context.Context, d
return interceptor(ctx, in, info, handler)
}
func _ArkService_ListRounds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListRoundsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ArkServiceServer).ListRounds(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ark.v1.ArkService/ListRounds",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ArkServiceServer).ListRounds(ctx, req.(*ListRoundsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ArkService_GetRound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetRoundRequest)
if err := dec(in); err != nil {
@@ -210,6 +229,45 @@ func _ArkService_GetRound_Handler(srv interface{}, ctx context.Context, dec func
return interceptor(ctx, in, info, handler)
}
func _ArkService_GetEventStream_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(GetEventStreamRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(ArkServiceServer).GetEventStream(m, &arkServiceGetEventStreamServer{stream})
}
type ArkService_GetEventStreamServer interface {
Send(*GetEventStreamResponse) error
grpc.ServerStream
}
type arkServiceGetEventStreamServer struct {
grpc.ServerStream
}
func (x *arkServiceGetEventStreamServer) Send(m *GetEventStreamResponse) error {
return x.ServerStream.SendMsg(m)
}
func _ArkService_Ping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(PingRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ArkServiceServer).Ping(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ark.v1.ArkService/Ping",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ArkServiceServer).Ping(ctx, req.(*PingRequest))
}
return interceptor(ctx, in, info, handler)
}
// ArkService_ServiceDesc is the grpc.ServiceDesc for ArkService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -229,15 +287,21 @@ var ArkService_ServiceDesc = grpc.ServiceDesc{
MethodName: "FinalizePayment",
Handler: _ArkService_FinalizePayment_Handler,
},
{
MethodName: "ListRounds",
Handler: _ArkService_ListRounds_Handler,
},
{
MethodName: "GetRound",
Handler: _ArkService_GetRound_Handler,
},
{
MethodName: "Ping",
Handler: _ArkService_Ping_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "GetEventStream",
Handler: _ArkService_GetEventStream_Handler,
ServerStreams: true,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "ark/v1/service.proto",
}

View File

@@ -4,9 +4,9 @@ import (
"os"
"os/signal"
"syscall"
log "github.com/sirupsen/logrus"
service_interface "github.com/ark-network/ark/internal/interface"
log "github.com/sirupsen/logrus"
)
//nolint:all
@@ -16,15 +16,14 @@ var (
date = "unknown"
)
// TODO: Edit this file to something more meaningful for your application.
func main() {
svc, err := service_interface.NewService()
svc, err := service_interface.NewService(service_interface.Options{}) // TODO populate options
if err != nil {
log.Fatal(err)
}
log.RegisterExitHandler(svc.Stop)
log.Info("starting service...")
if err := svc.Start(); err != nil {
log.Fatal(err)
@@ -37,4 +36,3 @@ func main() {
log.Info("shutting down service...")
log.Exit(0)
}

View File

@@ -17,7 +17,6 @@ require (
github.com/stretchr/testify v1.8.4
github.com/timshannon/badgerhold/v4 v4.0.3
github.com/vulpemventures/go-elements v0.4.7
golang.org/x/crypto v0.14.0
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17
google.golang.org/grpc v1.59.0
google.golang.org/protobuf v1.31.0
@@ -36,7 +35,9 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 // indirect
)
require (

View File

@@ -656,6 +656,8 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@@ -21,6 +21,15 @@ import (
const paymentsThreshold = 128
type Service interface {
SpendVtxos(ctx context.Context, inputs []domain.VtxoKey) (string, error)
ClaimVtxos(ctx context.Context, creds string, receivers []domain.Receiver) error
SignVtxos(ctx context.Context, forfeitTxs map[string]string) error
GetRoundByTxid(ctx context.Context, poolTxid string) (*domain.Round, error)
GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent
UpdatePaymenStatus(ctx context.Context, id string) error
}
type service struct {
roundInterval int64
network common.Network
@@ -32,20 +41,28 @@ type service struct {
builder ports.TxBuilder
paymentRequests *paymentsMap
forfeitTxs *forfeitTxsMap
eventsCh chan domain.RoundEvent
}
func NewService(
interval int64, network common.Network, onchainNetwork network.Network,
walletSvc ports.WalletService, schedulerSvc ports.SchedulerService,
repoManager ports.RepoManager, builder ports.TxBuilder,
) *service {
) Service {
paymentRequests := newPaymentsMap(nil)
forfeitTxs := newForfeitTxsMap()
svc := &service{
interval, network, onchainNetwork,
walletSvc, schedulerSvc, repoManager, builder, paymentRequests, forfeitTxs,
make(chan domain.RoundEvent),
}
repoManager.RegisterEventsHandler(svc.updateProjectionStore)
repoManager.RegisterEventsHandler(
func(round *domain.Round) {
svc.updateProjectionStore(round)
svc.propagateEvents(round)
},
)
return svc
}
@@ -100,6 +117,14 @@ func (s *service) SignVtxos(ctx context.Context, forfeitTxs map[string]string) e
return nil
}
func (s *service) GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent {
return s.eventsCh
}
func (s *service) GetRoundByTxid(ctx context.Context, poolTxid string) (*domain.Round, error) {
return s.repoManager.Rounds().GetRoundWithTxid(ctx, poolTxid)
}
func (s *service) start() error {
startImmediately := true
finalizationInterval := int64(s.roundInterval / 2)
@@ -264,6 +289,14 @@ func (s *service) updateProjectionStore(round *domain.Round) {
}
}
func (s *service) propagateEvents(round *domain.Round) {
lastEvent := round.Events()[len(round.Events())-1]
switch e := lastEvent.(type) {
case domain.RoundFinalizationStarted, domain.RoundFinalized:
s.eventsCh <- e
}
}
func getNewVtxos(net network.Network, round *domain.Round) []domain.Vtxo {
treeDepth := math.Log2(float64(len(round.CongestionTree) + 1))
leaves := round.CongestionTree[int(math.Pow(2, treeDepth)-1):]

View File

@@ -0,0 +1,227 @@
package handlers
import (
"context"
"sync"
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
"github.com/ark-network/ark/internal/core/application"
"github.com/ark-network/ark/internal/core/domain"
"github.com/ark-network/ark/internal/core/ports"
"github.com/google/uuid"
"github.com/vulpemventures/go-elements/psetv2"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type listener struct {
id string
ch chan *arkv1.GetEventStreamResponse
}
type handler struct {
svc application.Service
listenersLock *sync.Mutex
listeners []*listener
}
func NewHandler(service application.Service, repoManager ports.RepoManager) arkv1.ArkServiceServer {
h := &handler{
svc: service,
listenersLock: &sync.Mutex{},
listeners: make([]*listener, 0),
}
go h.listenToEvents()
return h
}
func (h *handler) Ping(ctx context.Context, req *arkv1.PingRequest) (*arkv1.PingResponse, error) {
if req.GetPaymentId() == "" {
return nil, status.Error(codes.InvalidArgument, "missing payment id")
}
if err := h.svc.UpdatePaymenStatus(ctx, req.GetPaymentId()); err != nil {
return nil, err
}
return &arkv1.PingResponse{}, nil
}
func (h *handler) RegisterPayment(ctx context.Context, req *arkv1.RegisterPaymentRequest) (*arkv1.RegisterPaymentResponse, error) {
vtxosKeys := make([]domain.VtxoKey, 0, len(req.GetInputs()))
for _, input := range req.GetInputs() {
vtxosKeys = append(vtxosKeys, domain.VtxoKey{
Txid: input.GetTxid(),
VOut: input.GetVout(),
})
}
id, err := h.svc.SpendVtxos(ctx, vtxosKeys)
if err != nil {
return nil, err
}
return &arkv1.RegisterPaymentResponse{
Id: id,
}, nil
}
func (h *handler) ClaimPayment(ctx context.Context, req *arkv1.ClaimPaymentRequest) (*arkv1.ClaimPaymentResponse, error) {
receivers := make([]domain.Receiver, 0, len(req.GetOutputs()))
for _, output := range req.GetOutputs() {
receivers = append(receivers, domain.Receiver{
Pubkey: output.GetPubkey(),
Amount: output.GetAmount(),
})
}
err := h.svc.ClaimVtxos(ctx, req.GetId(), receivers)
if err != nil {
return nil, err
}
return &arkv1.ClaimPaymentResponse{}, nil
}
func (h *handler) FinalizePayment(ctx context.Context, req *arkv1.FinalizePaymentRequest) (*arkv1.FinalizePaymentResponse, error) {
forfeits := make(map[string]string)
for _, b64 := range req.GetSignedForfeits() {
pset, err := psetv2.NewPsetFromBase64(b64)
if err != nil {
return nil, err
}
unsignedTx, err := pset.UnsignedTx()
if err != nil {
return nil, err
}
forfeits[unsignedTx.TxHash().String()] = b64
}
err := h.svc.SignVtxos(ctx, forfeits)
if err != nil {
return nil, err
}
return &arkv1.FinalizePaymentResponse{}, nil
}
func (h *handler) GetRound(ctx context.Context, req *arkv1.GetRoundRequest) (*arkv1.GetRoundResponse, error) {
if req.GetTxid() != "" {
return nil, status.Error(codes.InvalidArgument, "missing pool txid")
}
round, err := h.svc.GetRoundByTxid(ctx, req.GetTxid())
if err != nil {
return nil, err
}
return &arkv1.GetRoundResponse{
Round: &arkv1.Round{
Id: round.Id,
Start: round.StartingTimestamp,
End: round.EndingTimestamp,
Txid: round.Txid,
CongestionTree: round.CongestionTree,
},
}, nil
}
func (h *handler) GetEventStream(_ *arkv1.GetEventStreamRequest, stream arkv1.ArkService_GetEventStreamServer) error {
listener := &listener{
id: uuid.NewString(),
ch: make(chan *arkv1.GetEventStreamResponse),
}
defer h.removeListener(listener.id)
defer close(listener.ch)
h.pushListener(listener)
for {
select {
case <-stream.Context().Done():
return nil
case ev := <-listener.ch:
if err := stream.Send(ev); err != nil {
return err
}
switch ev.Event.(type) {
case *arkv1.GetEventStreamResponse_RoundFinalized, *arkv1.GetEventStreamResponse_RoundFailed:
return nil
}
}
}
}
func (h *handler) pushListener(l *listener) {
h.listenersLock.Lock()
defer h.listenersLock.Unlock()
h.listeners = append(h.listeners, l)
}
func (h *handler) removeListener(id string) {
h.listenersLock.Lock()
defer h.listenersLock.Unlock()
for i, listener := range h.listeners {
if listener.id == id {
h.listeners = append(h.listeners[:i], h.listeners[i+1:]...)
return
}
}
}
// listenToEvents forwards events from the application layer to the set of listeners
func (h *handler) listenToEvents() {
channel := h.svc.GetEventsChannel(context.Background())
for event := range channel {
var ev *arkv1.GetEventStreamResponse
switch e := event.(type) {
case domain.RoundFinalizationStarted:
ev = &arkv1.GetEventStreamResponse{
Event: &arkv1.GetEventStreamResponse_RoundFinalization{
RoundFinalization: &arkv1.RoundFinalizationEvent{
Id: e.Id,
PoolPartialTx: e.PoolTx,
CongestionTree: e.CongestionTree,
ForfeitTxs: nil, // TODO: add forfeit txs
},
},
}
case domain.RoundFinalized:
ev = &arkv1.GetEventStreamResponse{
Event: &arkv1.GetEventStreamResponse_RoundFinalized{
RoundFinalized: &arkv1.RoundFinalizedEvent{
Id: e.Id,
PoolTxid: e.Txid,
},
},
}
case domain.RoundFailed:
ev = &arkv1.GetEventStreamResponse{
Event: &arkv1.GetEventStreamResponse_RoundFailed{
RoundFailed: &arkv1.RoundFailed{
Id: e.Id,
Reason: e.Err.Error(),
},
},
}
}
if ev != nil {
for _, listener := range h.listeners {
listener.ch <- ev
}
}
}
}

View File

@@ -1,22 +0,0 @@
package grpc_interface
import (
log "github.com/sirupsen/logrus"
)
// TODO: Edit this file to something more meaningful for your application.
type service struct {}
func NewService() (*service, error) {
return &service{}, nil
}
func (s *service) Start() error {
log.Debug("service is listening")
return nil
}
func (s *service) Stop() {
log.Debug("service stopped")
}

View File

@@ -1,7 +1,12 @@
package service_interface
package interfaces
import (
grpc_interface "github.com/ark-network/ark/internal/interface/grpc"
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
"github.com/ark-network/ark/internal/core/application"
"github.com/ark-network/ark/internal/core/ports"
"github.com/ark-network/ark/internal/interface/grpc/handlers"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
// TODO: Edit this file to something more meaningful for your application.
@@ -10,7 +15,35 @@ type Service interface {
Stop()
}
func NewService() (Service, error) {
return grpc_interface.NewService()
type service struct {
grpcService arkv1.ArkServiceServer
grpcServer *grpc.Server
}
type Options struct {
applicationService application.Service
repositoryManager ports.RepoManager
}
func NewService(opts Options) (Service, error) {
return &service{
grpcService: handlers.NewHandler(opts.applicationService, opts.repositoryManager),
}, nil
}
// Start implements Service.
func (s *service) Start() error {
creds := insecure.NewCredentials()
serverOpts := grpc.Creds(creds)
server := grpc.NewServer(serverOpts)
arkv1.RegisterArkServiceServer(server, s.grpcService)
s.grpcServer = server
return nil
}
// Stop implements Service.
func (s *service) Stop() {
s.grpcServer.Stop()
}