mirror of
https://github.com/aljazceru/ark.git
synced 2025-12-18 12:44:19 +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:
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/ark-network/ark/server/internal/core/domain"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
@@ -118,25 +119,77 @@ func (h *handler) Ping(ctx context.Context, req *arkv1.PingRequest) (*arkv1.Ping
|
||||
return nil, status.Error(codes.InvalidArgument, "missing payment id")
|
||||
}
|
||||
|
||||
forfeits, round, err := h.svc.UpdatePaymentStatus(ctx, req.GetPaymentId())
|
||||
lastEvent, err := h.svc.UpdatePaymentStatus(ctx, req.GetPaymentId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var event *arkv1.RoundFinalizationEvent
|
||||
if round != nil {
|
||||
event = &arkv1.RoundFinalizationEvent{
|
||||
Id: round.Id,
|
||||
PoolTx: round.UnsignedTx,
|
||||
ForfeitTxs: forfeits,
|
||||
CongestionTree: castCongestionTree(round.CongestionTree),
|
||||
Connectors: round.Connectors,
|
||||
var resp *arkv1.PingResponse
|
||||
|
||||
switch e := lastEvent.(type) {
|
||||
case domain.RoundFinalizationStarted:
|
||||
resp = &arkv1.PingResponse{
|
||||
Event: &arkv1.PingResponse_RoundFinalization{
|
||||
RoundFinalization: &arkv1.RoundFinalizationEvent{
|
||||
Id: e.Id,
|
||||
PoolTx: e.PoolTx,
|
||||
CongestionTree: castCongestionTree(e.CongestionTree),
|
||||
ForfeitTxs: e.UnsignedForfeitTxs,
|
||||
Connectors: e.Connectors,
|
||||
},
|
||||
},
|
||||
}
|
||||
case domain.RoundFinalized:
|
||||
resp = &arkv1.PingResponse{
|
||||
Event: &arkv1.PingResponse_RoundFinalized{
|
||||
RoundFinalized: &arkv1.RoundFinalizedEvent{
|
||||
Id: e.Id,
|
||||
PoolTxid: e.Txid,
|
||||
},
|
||||
},
|
||||
}
|
||||
case domain.RoundFailed:
|
||||
resp = &arkv1.PingResponse{
|
||||
Event: &arkv1.PingResponse_RoundFailed{
|
||||
RoundFailed: &arkv1.RoundFailed{
|
||||
Id: e.Id,
|
||||
Reason: e.Err,
|
||||
},
|
||||
},
|
||||
}
|
||||
case application.RoundSigningStarted:
|
||||
cosignersKeys := make([]string, 0, len(e.Cosigners))
|
||||
for _, key := range e.Cosigners {
|
||||
cosignersKeys = append(cosignersKeys, hex.EncodeToString(key.SerializeCompressed()))
|
||||
}
|
||||
|
||||
resp = &arkv1.PingResponse{
|
||||
Event: &arkv1.PingResponse_RoundSigning{
|
||||
RoundSigning: &arkv1.RoundSigningEvent{
|
||||
Id: e.Id,
|
||||
CosignersPubkeys: cosignersKeys,
|
||||
UnsignedTree: castCongestionTree(e.UnsignedVtxoTree),
|
||||
},
|
||||
},
|
||||
}
|
||||
case application.RoundSigningNoncesGenerated:
|
||||
serialized, err := e.SerializeNonces()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("failed to serialize nonces")
|
||||
return nil, status.Error(codes.Internal, "failed to serialize nonces")
|
||||
}
|
||||
|
||||
resp = &arkv1.PingResponse{
|
||||
Event: &arkv1.PingResponse_RoundSigningNoncesGenerated{
|
||||
RoundSigningNoncesGenerated: &arkv1.RoundSigningNoncesGeneratedEvent{
|
||||
Id: e.Id,
|
||||
TreeNonces: serialized,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return &arkv1.PingResponse{
|
||||
ForfeitTxs: forfeits,
|
||||
Event: event,
|
||||
}, nil
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (h *handler) RegisterPayment(ctx context.Context, req *arkv1.RegisterPaymentRequest) (*arkv1.RegisterPaymentResponse, error) {
|
||||
@@ -150,6 +203,13 @@ func (h *handler) RegisterPayment(ctx context.Context, req *arkv1.RegisterPaymen
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pubkey := req.GetEphemeralPubkey()
|
||||
if len(pubkey) > 0 {
|
||||
if err := h.svc.RegisterCosignerPubkey(ctx, id, pubkey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &arkv1.RegisterPaymentResponse{
|
||||
Id: id,
|
||||
}, nil
|
||||
@@ -267,14 +327,6 @@ func (h *handler) GetEventStream(_ *arkv1.GetEventStreamRequest, stream arkv1.Ar
|
||||
if err := stream.Send(ev); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch ev.Event.(type) {
|
||||
case *arkv1.GetEventStreamResponse_RoundFinalized, *arkv1.GetEventStreamResponse_RoundFailed:
|
||||
if err := stream.Send(ev); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,6 +364,74 @@ func (h *handler) GetInfo(ctx context.Context, req *arkv1.GetInfoRequest) (*arkv
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *handler) SendTreeNonces(ctx context.Context, req *arkv1.SendTreeNoncesRequest) (*arkv1.SendTreeNoncesResponse, error) {
|
||||
pubkey := req.GetPublicKey()
|
||||
encodedNonces := req.GetTreeNonces()
|
||||
roundID := req.GetRoundId()
|
||||
|
||||
if len(pubkey) <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "missing cosigner public key")
|
||||
}
|
||||
|
||||
if len(encodedNonces) <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "missing tree nonces")
|
||||
}
|
||||
|
||||
if len(roundID) <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "missing round id")
|
||||
}
|
||||
|
||||
pubkeyBytes, err := hex.DecodeString(pubkey)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key")
|
||||
}
|
||||
|
||||
cosignerPublicKey, err := secp256k1.ParsePubKey(pubkeyBytes)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key")
|
||||
}
|
||||
|
||||
if err := h.svc.RegisterCosignerNonces(ctx, roundID, cosignerPublicKey, encodedNonces); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &arkv1.SendTreeNoncesResponse{}, nil
|
||||
}
|
||||
|
||||
func (h *handler) SendTreeSignatures(ctx context.Context, req *arkv1.SendTreeSignaturesRequest) (*arkv1.SendTreeSignaturesResponse, error) {
|
||||
roundID := req.GetRoundId()
|
||||
pubkey := req.GetPublicKey()
|
||||
encodedSignatures := req.GetTreeSignatures()
|
||||
|
||||
if len(pubkey) <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "missing cosigner public key")
|
||||
}
|
||||
|
||||
if len(encodedSignatures) <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "missing tree signatures")
|
||||
}
|
||||
|
||||
if len(roundID) <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "missing round id")
|
||||
}
|
||||
|
||||
pubkeyBytes, err := hex.DecodeString(pubkey)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key")
|
||||
}
|
||||
|
||||
cosignerPublicKey, err := secp256k1.ParsePubKey(pubkeyBytes)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "invalid cosigner public key")
|
||||
}
|
||||
|
||||
if err := h.svc.RegisterCosignerSignatures(ctx, roundID, cosignerPublicKey, encodedSignatures); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &arkv1.SendTreeSignaturesResponse{}, nil
|
||||
}
|
||||
|
||||
func (h *handler) pushListener(l *listener) {
|
||||
h.listenersLock.Lock()
|
||||
defer h.listenersLock.Unlock()
|
||||
@@ -368,6 +488,36 @@ func (h *handler) listenToEvents() {
|
||||
},
|
||||
},
|
||||
}
|
||||
case application.RoundSigningStarted:
|
||||
cosignersKeys := make([]string, 0, len(e.Cosigners))
|
||||
for _, key := range e.Cosigners {
|
||||
cosignersKeys = append(cosignersKeys, hex.EncodeToString(key.SerializeCompressed()))
|
||||
}
|
||||
|
||||
ev = &arkv1.GetEventStreamResponse{
|
||||
Event: &arkv1.GetEventStreamResponse_RoundSigning{
|
||||
RoundSigning: &arkv1.RoundSigningEvent{
|
||||
Id: e.Id,
|
||||
CosignersPubkeys: cosignersKeys,
|
||||
UnsignedTree: castCongestionTree(e.UnsignedVtxoTree),
|
||||
},
|
||||
},
|
||||
}
|
||||
case application.RoundSigningNoncesGenerated:
|
||||
serialized, err := e.SerializeNonces()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("failed to serialize nonces")
|
||||
continue
|
||||
}
|
||||
|
||||
ev = &arkv1.GetEventStreamResponse{
|
||||
Event: &arkv1.GetEventStreamResponse_RoundSigningNoncesGenerated{
|
||||
RoundSigningNoncesGenerated: &arkv1.RoundSigningNoncesGeneratedEvent{
|
||||
Id: e.Id,
|
||||
TreeNonces: serialized,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if ev != nil {
|
||||
|
||||
@@ -161,6 +161,14 @@ func Whitelist() map[string][]bakery.Op {
|
||||
Entity: EntityHealth,
|
||||
Action: "read",
|
||||
}},
|
||||
fmt.Sprintf("/%s/SendTreeNonces", arkv1.ArkService_ServiceDesc.ServiceName): {{
|
||||
Entity: EntityArk,
|
||||
Action: "write",
|
||||
}},
|
||||
fmt.Sprintf("/%s/SendTreeSignatures", arkv1.ArkService_ServiceDesc.ServiceName): {{
|
||||
Entity: EntityArk,
|
||||
Action: "write",
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user