Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 42 additions & 6 deletions daemonrpc/daemon.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions daemonrpc/daemon.proto
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,14 @@ message InitWalletResponse {
// recovered_oor_events is the number of OOR recipient events processed
// during recovery.
uint32 recovered_oor_events = 7;

// recovered_vhtlcs is the number of indexed vHTLC recovery manifests
// matched during recovery.
uint32 recovered_vhtlcs = 8;

// recovered_vhtlc_refunds is the number of matched pay-side vHTLCs for
// which daemon-owned refund recovery is available.
uint32 recovered_vhtlc_refunds = 9;
}

message UnlockWalletRequest {
Expand Down Expand Up @@ -746,6 +754,13 @@ message Output {
// created output when the caller knows semantic ownership metadata
// that is not already carried by the destination itself.
bytes vtxo_policy_template = 5;

// receive_script_label, when set on an OOR output, asks the daemon to
// register the resolved recipient pk_script with the indexer before
// submitting the transfer. Swap recovery uses this to persist compact
// vHTLC restore metadata before later local swap DB state becomes
// required.
string receive_script_label = 6;
}

message SendVTXORequest {
Expand Down
52 changes: 52 additions & 0 deletions darepod/rpc_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ const (
// RPC handler resolves scripts and policy templates before handing
// work to that actor, so it needs its own cheap request-size guard.
maxOORRecipients = 256

// vhtlcRecoveryManifestRegistrationTTL keeps swap recovery manifests
// available across realistic offline restore windows. The signed
// registration proof itself remains short lived in the indexer client.
vhtlcRecoveryManifestRegistrationTTL = 365 * 24 * time.Hour
Comment on lines +79 to +82
)

// RPCServer implements the daemon's gRPC DaemonService interface.
Expand Down Expand Up @@ -460,6 +465,47 @@ func (r *RPCServer) buildSendOORRecipients(ctx context.Context,
return recipients, nil
}

// registerSendOORRecipientScripts stores caller-requested script labels with
// the indexer after recipient scripts are resolved but before OOR submission.
func (r *RPCServer) registerSendOORRecipientScripts(ctx context.Context,
requestRecipients []*daemonrpc.Output,
oorRecipients []oortx.RecipientOutput) error {

if len(requestRecipients) != len(oorRecipients) {
return status.Errorf(codes.Internal, "recipient count mismatch")
}

for i := range requestRecipients {
label := requestRecipients[i].GetReceiveScriptLabel()
if label == "" {
continue
}

if r.server.indexer == nil {
return status.Errorf(codes.Internal, "indexer client "+
"not initialized")
}

idx := r.server.indexer.WithSigner(
r.server.proofKeyBackend.ProofSigner(
r.server.clientKeyDesc,
),
)
expiresAt := r.server.clk.Now().Add(
vhtlcRecoveryManifestRegistrationTTL,
)
_, err := idx.RegisterReceiveScriptTaproot(
ctx, oorRecipients[i].PkScript, expiresAt, label,
)
if err != nil && status.Code(err) != codes.AlreadyExists {
return status.Errorf(codes.Internal, "register "+
"OOR recipient script %d: %v", i, err)
}
}
Comment on lines +484 to +504

return nil
}

// resolveOORRecipientOutpoints maps each requested recipient to the outpoint it
// occupies after the canonical OOR output ordering is applied.
func (r *RPCServer) resolveOORRecipientOutpoints(ctx context.Context,
Expand Down Expand Up @@ -2207,6 +2253,12 @@ func (r *RPCServer) SendOOR(ctx context.Context,
}, nil
}

if err := r.registerSendOORRecipientScripts(
ctx, requestRecipients, oorRecipients,
); err != nil {
return nil, err
}
Comment on lines +2256 to +2260

if r.server.actorSystem == nil {
return nil, status.Errorf(codes.Internal, "actor system not "+
"initialized")
Expand Down
Loading
Loading