diff --git a/cmd/wavecli/waveclicommands/devrpc/registry_generated.go b/cmd/wavecli/waveclicommands/devrpc/registry_generated.go index f22591390..ffd6d5992 100644 --- a/cmd/wavecli/waveclicommands/devrpc/registry_generated.go +++ b/cmd/wavecli/waveclicommands/devrpc/registry_generated.go @@ -184,6 +184,20 @@ func generatedRegistry() []serviceSpec { Output: "waverpc.SubmitForfeitParticipantSignaturesResponse", Comments: "SubmitForfeitParticipantSignatures supplies external participant\nsignatures for one pending connector-bound forfeit signing request. The\nrequest_id must be copied from the listed pending request; the daemon\nuses it to wake the blocked VTXO actor that is waiting for that exact\nround-assigned forfeit transaction. If the selected spend path requires\nno external participant keys after removing the local VTXO key and the\noperator key, callers may submit an empty signature set to acknowledge\nand unblock the request.", }, + { + Name: "ListPendingTreeSigningRequests", + Aliases: []string{"list-pending-tree-signing-requests"}, + Input: "waverpc.ListPendingTreeSigningRequestsRequest", + Output: "waverpc.ListPendingTreeSigningRequestsResponse", + Comments: "ListPendingTreeSigningRequests returns pending MuSig2 VTXO-tree signing\nrequests for cosigner keys marked as externally signed (for example an\naggregate FROST key the client controls off-box). Each request is one\nround of the two-round MuSig2 ceremony for one transaction session:\nround NONCE asks for a fresh public nonce, round PARTIAL_SIG asks for a\npartial signature over the given sighash under the operator-aggregated\ncombined nonce. Callers poll this endpoint and answer with\nSubmitTreeSignatures. The private key never enters the daemon.", + }, + { + Name: "SubmitTreeSignatures", + Aliases: []string{"submit-tree-signatures"}, + Input: "waverpc.SubmitTreeSignaturesRequest", + Output: "waverpc.SubmitTreeSignaturesResponse", + Comments: "SubmitTreeSignatures supplies the external cosigner's material for one\npending tree-signing request. The request_id must be copied from the\nlisted pending request; the daemon uses it to wake the blocked round FSM\nthat is waiting for that exact session's nonce or partial signature.", + }, { Name: "LeaveVTXOs", Aliases: []string{"leave-vtxos"}, diff --git a/db/migrations.go b/db/migrations.go index 66fd076c8..b9c7f13b7 100644 --- a/db/migrations.go +++ b/db/migrations.go @@ -10,7 +10,7 @@ const ( // daemon. // // NOTE: This MUST be updated when a new migration is added. - LatestMigrationVersion uint = 15 + LatestMigrationVersion uint = 16 ) // MigrationTarget is a functional option that can be passed to applyMigrations diff --git a/db/pending_intent_store.go b/db/pending_intent_store.go index 490b7b785..bd1a92143 100644 --- a/db/pending_intent_store.go +++ b/db/pending_intent_store.go @@ -153,10 +153,23 @@ func upsertPendingIntentDetail(ctx context.Context, q PendingIntentStore, switch p := intent.Payload.(type) { case *wallet.BoardIntentPayload: + // Store nil rather than a zero-length slice when there is no + // custom policy so the columns round-trip as NULL on Postgres + // (the x'' BYTEA pitfall) and the pk_script length CHECK holds. + var policyTemplate, pkScript []byte + if len(p.PolicyTemplate) > 0 { + policyTemplate = p.PolicyTemplate + } + if len(p.PkScript) > 0 { + pkScript = p.PkScript + } + err := q.UpsertPendingBoardIntent( ctx, sqlc.UpsertPendingBoardIntentParams{ - IntentID: intent.ID[:], - TargetVtxoCount: int32(p.TargetVTXOCount), + IntentID: intent.ID[:], + TargetVtxoCount: int32(p.TargetVTXOCount), + VtxoPolicyTemplate: policyTemplate, + PkScript: pkScript, }, ) if err != nil { @@ -315,6 +328,8 @@ func listPendingBoardIntents(ctx context.Context, q PendingIntentStore, ID: id, Payload: &wallet.BoardIntentPayload{ TargetVTXOCount: uint32(row.TargetVtxoCount), + PolicyTemplate: row.VtxoPolicyTemplate, + PkScript: row.PkScript, }, RequestedAt: row.RequestedAtUnix, Anchors: anchors[id], diff --git a/db/pending_intent_store_test.go b/db/pending_intent_store_test.go index b17040f5f..4372c7af9 100644 --- a/db/pending_intent_store_test.go +++ b/db/pending_intent_store_test.go @@ -121,6 +121,49 @@ func TestPendingIntentUpsertListRoundtrip(t *testing.T) { require.EqualValues(t, 150, gotBoard[0].RequestedAt) } +// TestPendingIntentBoardCustomPolicyRoundtrip verifies that a board intent's +// custom VTXO policy template and pinned pk_script persist to their typed +// columns and list back byte-for-byte, so restart replay recreates the same +// custom-owned output. This exercises the full persistence path: the +// 000016 migration columns, the sqlc upsert/list, and the store's nil-vs-empty +// handling. +func TestPendingIntentBoardCustomPolicyRoundtrip(t *testing.T) { + t.Parallel() + + ctx := t.Context() + h := newPendingIntentStoreForTest(t) + + opA := wire.OutPoint{Hash: chainhash.Hash{0xd1}, Index: 0} + + payload := &wallet.BoardIntentPayload{ + TargetVTXOCount: 4, + PolicyTemplate: []byte{ + 0x01, + 0xde, + 0xad, + 0xbe, + 0xef, + }, + PkScript: append( + []byte{0x51, 0x20}, make([]byte, 32)..., + ), + } + board := makePendingIntent(payload, 100, opA) + require.NoError(t, h.store.UpsertPendingIntent(ctx, board)) + + got, err := h.store.ListPendingIntents( + ctx, wallet.PendingIntentKindBoard, + ) + require.NoError(t, err) + require.Len(t, got, 1) + require.Equal(t, board.Payload, got[0].Payload) + + gotPayload, ok := got[0].Payload.(*wallet.BoardIntentPayload) + require.True(t, ok) + require.Equal(t, payload.PolicyTemplate, gotPayload.PolicyTemplate) + require.Equal(t, payload.PkScript, gotPayload.PkScript) +} + // TestPendingIntentAnchorRebindSweepsOrphan verifies that a newer intent // claiming an older intent's anchors rebinds them, and that an older parent // left with zero anchors is swept in the same transaction. diff --git a/db/sqlc/migrations/000016_board_intent_policy.down.sql b/db/sqlc/migrations/000016_board_intent_policy.down.sql new file mode 100644 index 000000000..d10084b07 --- /dev/null +++ b/db/sqlc/migrations/000016_board_intent_policy.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE pending_board_intents DROP COLUMN pk_script; + +ALTER TABLE pending_board_intents DROP COLUMN vtxo_policy_template; diff --git a/db/sqlc/migrations/000016_board_intent_policy.up.sql b/db/sqlc/migrations/000016_board_intent_policy.up.sql new file mode 100644 index 000000000..f148d1ac9 --- /dev/null +++ b/db/sqlc/migrations/000016_board_intent_policy.up.sql @@ -0,0 +1,15 @@ +-- Add the custom-policy replay parameters to the Board pending-intent detail +-- table. When a Board RPC pins a vtxo_policy_template (for example to board +-- directly into a VTXO owned by an external FROST aggregate key), the template +-- and its optional pinned pk_script must survive a restart so replay recreates +-- the same custom output instead of silently re-boarding into the standard +-- collaborative shape. Both columns are nullable (NULL for board intents +-- persisted before this migration and for the legacy standard-policy path); a +-- NULL template selects the standard collaborative policy with a freshly +-- derived owner key. +ALTER TABLE pending_board_intents + ADD COLUMN vtxo_policy_template BLOB; + +ALTER TABLE pending_board_intents + ADD COLUMN pk_script BLOB + CHECK (pk_script IS NULL OR length(pk_script) > 0); diff --git a/db/sqlc/models.go b/db/sqlc/models.go index f91f0705f..a62339113 100644 --- a/db/sqlc/models.go +++ b/db/sqlc/models.go @@ -268,8 +268,10 @@ type OwnedReceiveScriptSource struct { } type PendingBoardIntent struct { - IntentID []byte - TargetVtxoCount int32 + IntentID []byte + TargetVtxoCount int32 + VtxoPolicyTemplate []byte + PkScript []byte } type PendingIntent struct { diff --git a/db/sqlc/pending_intents.sql.go b/db/sqlc/pending_intents.sql.go index 9c0f3a47c..19141538a 100644 --- a/db/sqlc/pending_intents.sql.go +++ b/db/sqlc/pending_intents.sql.go @@ -208,7 +208,7 @@ func (q *Queries) GetPendingIntentByID(ctx context.Context, intentID []byte) (Ge const ListPendingBoardIntents = `-- name: ListPendingBoardIntents :many SELECT i.intent_id, i.requested_at_unix, - b.target_vtxo_count + b.target_vtxo_count, b.vtxo_policy_template, b.pk_script FROM pending_intents i JOIN pending_board_intents b ON b.intent_id = i.intent_id WHERE i.kind = 'board' AND i.status = 'pending' @@ -216,9 +216,11 @@ ORDER BY i.requested_at_unix ASC, i.intent_id ASC ` type ListPendingBoardIntentsRow struct { - IntentID []byte - RequestedAtUnix int64 - TargetVtxoCount int32 + IntentID []byte + RequestedAtUnix int64 + TargetVtxoCount int32 + VtxoPolicyTemplate []byte + PkScript []byte } // Only status = 'pending' rows replay; a 'failed' intent is terminally @@ -232,7 +234,13 @@ func (q *Queries) ListPendingBoardIntents(ctx context.Context) ([]ListPendingBoa var items []ListPendingBoardIntentsRow for rows.Next() { var i ListPendingBoardIntentsRow - if err := rows.Scan(&i.IntentID, &i.RequestedAtUnix, &i.TargetVtxoCount); err != nil { + if err := rows.Scan( + &i.IntentID, + &i.RequestedAtUnix, + &i.TargetVtxoCount, + &i.VtxoPolicyTemplate, + &i.PkScript, + ); err != nil { return nil, err } items = append(items, i) @@ -371,19 +379,30 @@ func (q *Queries) MarkPendingSendIntentFailedByOutpoint(ctx context.Context, arg const UpsertPendingBoardIntent = `-- name: UpsertPendingBoardIntent :exec INSERT INTO pending_board_intents ( intent_id, - target_vtxo_count -) VALUES ($1, $2) + target_vtxo_count, + vtxo_policy_template, + pk_script +) VALUES ($1, $2, $3, $4) ON CONFLICT (intent_id) DO UPDATE -SET target_vtxo_count = excluded.target_vtxo_count +SET target_vtxo_count = excluded.target_vtxo_count, + vtxo_policy_template = excluded.vtxo_policy_template, + pk_script = excluded.pk_script ` type UpsertPendingBoardIntentParams struct { - IntentID []byte - TargetVtxoCount int32 + IntentID []byte + TargetVtxoCount int32 + VtxoPolicyTemplate []byte + PkScript []byte } func (q *Queries) UpsertPendingBoardIntent(ctx context.Context, arg UpsertPendingBoardIntentParams) error { - _, err := q.db.ExecContext(ctx, UpsertPendingBoardIntent, arg.IntentID, arg.TargetVtxoCount) + _, err := q.db.ExecContext(ctx, UpsertPendingBoardIntent, + arg.IntentID, + arg.TargetVtxoCount, + arg.VtxoPolicyTemplate, + arg.PkScript, + ) return err } diff --git a/db/sqlc/queries/pending_intents.sql b/db/sqlc/queries/pending_intents.sql index 49d7f47e4..b334a2246 100644 --- a/db/sqlc/queries/pending_intents.sql +++ b/db/sqlc/queries/pending_intents.sql @@ -19,10 +19,14 @@ SET requested_at_unix = excluded.requested_at_unix, -- name: UpsertPendingBoardIntent :exec INSERT INTO pending_board_intents ( intent_id, - target_vtxo_count -) VALUES ($1, $2) + target_vtxo_count, + vtxo_policy_template, + pk_script +) VALUES ($1, $2, $3, $4) ON CONFLICT (intent_id) DO UPDATE -SET target_vtxo_count = excluded.target_vtxo_count; +SET target_vtxo_count = excluded.target_vtxo_count, + vtxo_policy_template = excluded.vtxo_policy_template, + pk_script = excluded.pk_script; -- name: UpsertPendingSendIntent :exec INSERT INTO pending_send_intents ( @@ -56,7 +60,7 @@ SET intent_id = excluded.intent_id; -- retired and must not be re-submitted on restart. SELECT i.intent_id, i.requested_at_unix, - b.target_vtxo_count + b.target_vtxo_count, b.vtxo_policy_template, b.pk_script FROM pending_intents i JOIN pending_board_intents b ON b.intent_id = i.intent_id WHERE i.kind = 'board' AND i.status = 'pending' diff --git a/db/sqlc/schemas/generated_schema.sql b/db/sqlc/schemas/generated_schema.sql index 42335cca2..25a7f0910 100644 --- a/db/sqlc/schemas/generated_schema.sql +++ b/db/sqlc/schemas/generated_schema.sql @@ -1058,7 +1058,8 @@ CREATE TABLE pending_board_intents ( -- the confirmed boarding balance into one VTXO, non-zero fans it out. target_vtxo_count INTEGER NOT NULL DEFAULT 0 CHECK (target_vtxo_count >= 0) -); +, vtxo_policy_template BLOB, pk_script BLOB + CHECK (pk_script IS NULL OR length(pk_script) > 0)); CREATE TABLE pending_intent_anchors ( -- The anchored outpoint. For kind='board' this is a confirmed boarding diff --git a/lib/actormsg/interfaces.go b/lib/actormsg/interfaces.go index e5903ef3b..040929ffe 100644 --- a/lib/actormsg/interfaces.go +++ b/lib/actormsg/interfaces.go @@ -127,6 +127,20 @@ type TriggerBoardMsg struct { // board later once headroom frees up. Nil when the full balance // boards. Change *types.LeaveRequest + + // PolicyTemplate optionally pins the serialized arkscript policy for + // every boarded VTXO output. Nil selects the standard collaborative + // policy with a freshly derived owner key (the legacy behavior); when + // set, the round actor builds each boarded output from this template + // verbatim instead of synthesizing one, letting a client board directly + // into a custom-owned VTXO (e.g. one owned by an external FROST + // aggregate key). + PolicyTemplate []byte + + // PkScript optionally pins the taproot output script for the boarded + // VTXOs. Only valid alongside PolicyTemplate; empty means derive it + // from the template. + PkScript []byte } // RoundReceivable implements the RoundReceivable marker interface. diff --git a/lib/types/boarding.go b/lib/types/boarding.go index f6104624f..eedf954b7 100644 --- a/lib/types/boarding.go +++ b/lib/types/boarding.go @@ -297,6 +297,15 @@ type VTXORequest struct { // need the key locator for signing operations. SigningKey keychain.KeyDescriptor + // ExternalTreeSigner marks this VTXO's tree-signing (MuSig2 cosigner) + // key as living outside this daemon: the round FSM must not derive a + // wallet key for it and must route its tree nonce and partial-signature + // production to an external party (e.g. an aggregate FROST key the + // client controls off-box) instead of the local wallet signer. When + // set, SigningKey.PubKey must be the external cosigner public key; the + // key locator is ignored because the key is not wallet-derivable. + ExternalTreeSigner bool + // Origin classifies how a locally-owned VTXO came into // existence (boarding, refresh, or participant transfer). It // is set by the wallet at intent-composition time and flows diff --git a/round/actor.go b/round/actor.go index 54608407e..1281ea918 100644 --- a/round/actor.go +++ b/round/actor.go @@ -281,6 +281,13 @@ type RoundClientConfig struct { // concurrency. If nil, the actor preserves serial behavior. SigningExecutor SigningExecutor + // ExternalTreeSigner, when non-nil, supplies MuSig2 tree-signing + // material for VTXO signing keys marked ExternalTreeSigner, routing + // them to an external party (e.g. an aggregate FROST key the client + // controls off-box) instead of the local wallet. Nil disables external + // tree signing. + ExternalTreeSigner ExternalTreeSignerBackend + // RoundStore persists round coordination and checkpointing. RoundStore RoundStore @@ -415,6 +422,7 @@ func NewRoundClientActor(cfg *RoundClientConfig) fn.Result[*RoundClientActor] { VTXOStore: cfg.VTXOStore, Wallet: cfg.Wallet, SigningExecutor: cfg.SigningExecutor, + ExternalTreeSigner: cfg.ExternalTreeSigner, OperatorTerms: cfg.OperatorTerms, ChainParams: cfg.ChainParams, MaxOperatorFee: cfg.MaxOperatorFee, @@ -826,6 +834,7 @@ func (a *RoundClientActor) createRoundFSMFromDB(ctx context.Context, VTXOStore: a.cfg.VTXOStore, Wallet: a.cfg.Wallet, SigningExecutor: a.env.SigningExecutor, + ExternalTreeSigner: a.env.ExternalTreeSigner, OperatorTerms: a.cfg.OperatorTerms, ChainParams: a.cfg.ChainParams, MaxOperatorFee: a.cfg.MaxOperatorFee, @@ -900,6 +909,7 @@ func (a *RoundClientActor) createNewRound(ctx context.Context) (*RoundFSM, VTXOStore: a.cfg.VTXOStore, Wallet: a.cfg.Wallet, SigningExecutor: a.env.SigningExecutor, + ExternalTreeSigner: a.env.ExternalTreeSigner, OperatorTerms: a.cfg.OperatorTerms, ChainParams: a.cfg.ChainParams, MaxOperatorFee: a.cfg.MaxOperatorFee, @@ -1800,6 +1810,27 @@ func (a *RoundClientActor) buildVTXORequest(ctx context.Context, return req, nil } +// buildCustomBoardVTXORequest constructs a boarded VTXO request from a +// caller-supplied arkscript policy template. Unlike buildVTXORequest it derives +// no owner key and registers no owned script: the policy's owner is external to +// this daemon (for example an aggregate FROST key the client controls off-box), +// so ClientKey/OwnerKey are intentionally left zero and the FSM still assigns +// the ephemeral MuSig2 tree-signing key at registration time. This mirrors the +// custom-refresh output construction so a custom-policy board and a +// custom-policy refresh produce structurally identical VTXO requests. The +// template and pkScript are validated at the RPC boundary before the board +// intent is admitted. +func buildCustomBoardVTXORequest(amount btcutil.Amount, policyTemplate, + pkScript []byte, origin types.VTXOOrigin) *types.VTXORequest { + + return &types.VTXORequest{ + PolicyTemplate: append([]byte(nil), policyTemplate...), + PkScript: append([]byte(nil), pkScript...), + Amount: amount, + Origin: origin, + } +} + // handleRoundJoined handles the RoundJoined event which requires special // re-keying logic. It matches the accepted outpoints to find the correct // pending round, then re-keys the round from its TempRoundKey to the @@ -3318,14 +3349,29 @@ func (a *RoundClientActor) handleTriggerBoard(ctx context.Context, // SourceRoundBoarding. Tag origin here so the // classification flows through the FSM to the // VTXOCreatedNotification dispatch. - req, err := a.buildVTXORequest( - ctx, amount, types.VTXOOriginRoundBoarding, - ) - if err != nil { - return fn.Err[actormsg.RoundActorResp]( - fmt.Errorf("build board VTXO request %d: %w", - i, err), + // + // When the board request pins a custom policy template, + // build the output from it verbatim (mirroring the + // custom-refresh path) instead of synthesizing the + // standard policy with a freshly derived owner key. This + // lets a client board straight into a custom-owned VTXO, + // e.g. one owned by an external FROST aggregate key. + var req *types.VTXORequest + if len(cmd.PolicyTemplate) > 0 { + req = buildCustomBoardVTXORequest( + amount, cmd.PolicyTemplate, cmd.PkScript, + types.VTXOOriginRoundBoarding, ) + } else { + req, err = a.buildVTXORequest( + ctx, amount, types.VTXOOriginRoundBoarding, + ) + if err != nil { + return fn.Err[actormsg.RoundActorResp]( + fmt.Errorf("build board VTXO request "+ + "%d: %w", i, err), + ) + } } requests = append(requests, *req) diff --git a/round/actor_test.go b/round/actor_test.go index 6f527f813..023a44a29 100644 --- a/round/actor_test.go +++ b/round/actor_test.go @@ -2485,6 +2485,81 @@ func TestHandleTriggerBoardMultipleVTXOs(t *testing.T) { ) } +// TestHandleTriggerBoardCustomPolicy verifies that when a board trigger pins a +// custom VTXO policy template, the round actor builds the boarded output from +// that template verbatim rather than synthesizing the standard policy: it +// derives no owner key (the policy's owner is external to this daemon, e.g. an +// aggregate FROST key the client controls off-box), leaves OwnerKey/ClientKey +// zero, and still assigns the ephemeral MuSig2 tree-signing key. This is the +// board-side mirror of the custom-refresh output path. +func TestHandleTriggerBoardCustomPolicy(t *testing.T) { + t.Parallel() + + h := newActorTestHarness(t) + h.setupMockRoundStoreForStart() + + err := h.start() + require.NoError(t, err) + + intent := h.newTestBoardingIntent() + h.walletActor.setConfirmedIntents(*intent) + + // Model an external FROST-owned VTXO: the owner key is a key the daemon + // never derives. The template is otherwise a standard Ark VTXO shape so + // the operator still co-signs the collab leaf. + _, frostOwnerKey := generateTestKeyPair(t) + policyTemplate, err := arkscript.EncodeStandardVTXOTemplate( + frostOwnerKey, h.operatorPubKey, testExitDelay, + ) + require.NoError(t, err) + + // The custom path must NOT derive an owner key. Only the ephemeral + // tree-signing key (family 45) is derived by the FSM at registration. + // Fail loudly if the owner-key family is ever requested. + h.wallet.On( + "DeriveNextKey", mock.Anything, types.VTXOOwnerKeyFamily, + ).Panic("owner key must not be derived on the custom-policy board path") + h.wallet.On( + "DeriveNextKey", mock.Anything, types.VTXOSigningKeyFamily, + ).Return(&keychain.KeyDescriptor{ + PubKey: h.clientPubKey, + KeyLocator: keychain.KeyLocator{ + Family: types.VTXOSigningKeyFamily, + Index: 7, + }, + }, nil).Once() + + result := h.receive(&actormsg.TriggerBoardMsg{ + Amounts: []btcutil.Amount{49_000}, + PolicyTemplate: policyTemplate, + }) + require.True(t, result.IsOk(), "expected Ok, got: %v", result.Err()) + + states := h.queryState() + tempState, exists := h.findTempState(states) + require.True(t, exists, "expected temp-keyed FSM state") + + regState, ok := tempState.State.(*IntentSentState) + require.True(t, ok, "expected IntentSentState, got %T", tempState.State) + require.Len(t, regState.Intents.VTXOs, 1) + + vtxoReq := regState.Intents.VTXOs[0] + + // The boarded output carries the pinned template verbatim. + require.Equal(t, policyTemplate, vtxoReq.PolicyTemplate) + require.Equal(t, btcutil.Amount(49_000), vtxoReq.Amount) + + // No owner key was derived: OwnerKey/ClientKey stay zero. + require.Zero(t, vtxoReq.OwnerKey.Family) + require.Nil(t, vtxoReq.OwnerKey.PubKey) + require.Nil(t, vtxoReq.ClientKey) + + // The ephemeral tree-signing key is still assigned. + require.Equal( + t, types.VTXOSigningKeyFamily, vtxoReq.SigningKey.Family, + ) +} + // TestHandleTriggerBoardFiltersToNamedOutpoints verifies that when a board // trigger names the boarding outpoints it sized its amounts over, the round // actor registers exactly those inputs and ignores other confirmed boarding diff --git a/round/external_tree_signer.go b/round/external_tree_signer.go new file mode 100644 index 000000000..ae5948bcd --- /dev/null +++ b/round/external_tree_signer.go @@ -0,0 +1,346 @@ +package round + +import ( + "context" + "crypto/sha256" + "encoding/binary" + "fmt" + "sync" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" + "github.com/lightninglabs/wavelength/lib/tree" + "github.com/lightninglabs/wavelength/lib/types" + "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" +) + +// TreeSigningSessionRequest identifies one blocking request for external +// tree-signing material for a single cosigner key and one transaction session +// on that cosigner's path through the VTXO tree. The same SessionID correlates +// the nonce request (round one) with the later partial-signature request +// (round two), so the external party can sign under the exact secret nonce it +// committed to. +type TreeSigningSessionRequest struct { + // RoundID is the round this signing material belongs to. + RoundID RoundID + + // CosignerKey is the public key of the external cosigner whose private + // key material lives outside this daemon (e.g. an aggregate FROST key). + CosignerKey *btcec.PublicKey + + // SessionID is the daemon-assigned, per-transaction MuSig2 session + // identifier. It is stable across the nonce and partial-signature + // rounds for one transaction session. + SessionID [32]byte + + // Cosigners is the full ordered MuSig2 participant set for this session + // (the client cosigner plus the operator), as supplied to + // MuSig2CreateSession. + Cosigners []*btcec.PublicKey + + // SweepTapscriptRoot is the taproot tweak applied to the aggregate key + // (the VTXO tree's sweep tapscript root). It is load-bearing: it + // changes the aggregate key and therefore the signature. + SweepTapscriptRoot []byte + + // SigHash is the 32-byte taproot sighash the partial signature must + // cover. It is set only on partial-signature requests. + SigHash [32]byte + + // AggNonce is the operator-aggregated combined nonce for this session. + // It is set only on partial-signature requests (round two). + AggNonce [musig2.PubNonceSize]byte +} + +// ExternalTreeSignerBackend fetches MuSig2 tree-signing material for a cosigner +// key whose private key lives outside this daemon (for example an aggregate +// FROST key the client controls off-box). Each method blocks until the external +// party supplies the requested material or the context is cancelled. All MuSig2 +// (or FROST) cryptography happens at the external party; this daemon only +// ferries the resulting nonce and partial-signature bytes. +type ExternalTreeSignerBackend interface { + // FetchTreeNonce blocks until the external party supplies a fresh + // public nonce for the given session (round one). + FetchTreeNonce(context.Context, + TreeSigningSessionRequest) (tree.Musig2PubNonce, error) + + // FetchTreePartialSig blocks until the external party supplies a + // partial signature over req.SigHash under req.AggNonce for the given + // session (round two). + FetchTreePartialSig(context.Context, + TreeSigningSessionRequest) (*musig2.PartialSignature, error) +} + +// externalMuSig2Signer is a daemon-side input.MuSig2Signer that performs no +// MuSig2 cryptography itself. It stands in for the wallet signer for a single +// external cosigner key and routes nonce generation and partial-signature +// production to an ExternalTreeSignerBackend (in production, an RPC-driven +// broker). The key material never enters this daemon. +// +// It implements only the subset of input.MuSig2Signer that the VTXO tree +// signing path exercises: CreateSession, RegisterCombinedNonce, Sign, and +// Cleanup. The remaining methods return an unsupported error because the client +// never aggregates nonces or combines signatures on this path (the operator +// does). +type externalMuSig2Signer struct { + // ctx bounds the blocking backend calls. It is stored on the struct + // because the input.MuSig2Signer methods this type implements + // (MuSig2CreateSession/MuSig2Sign) take no context parameter, so the + // round lifecycle context must be captured at construction to remain + // cancellable. + // + //nolint:containedctx + ctx context.Context + backend ExternalTreeSignerBackend + roundID RoundID + cosignerKey *btcec.PublicKey + + mu sync.Mutex + counter uint64 + sessions map[input.MuSig2SessionID]*externalTreeSession +} + +// externalTreeSession is the per-transaction session state the proxy retains +// between the nonce and partial-signature rounds. +type externalTreeSession struct { + cosigners []*btcec.PublicKey + sweepTapscriptRoot []byte + aggNonce [musig2.PubNonceSize]byte + haveAggNonce bool +} + +// selectTreeSigner returns the MuSig2 signer for one VTXO's tree path. It is +// the wallet signer by default; when the VTXO's signing key is marked external +// it is a proxy that routes nonce and partial-signature production to the +// configured external party. It errors if a VTXO is marked external but no +// external tree signer is configured, or the external key is missing. +func selectTreeSigner(ctx context.Context, env *ClientEnvironment, + roundID RoundID, vtxoReq types.VTXORequest, + signerKey SignerKey) (input.MuSig2Signer, error) { + + if !vtxoReq.ExternalTreeSigner { + return env.Wallet, nil + } + + if env.ExternalTreeSigner == nil { + return nil, fmt.Errorf("vtxo signer %x is external but no "+ + "external tree signer is configured", signerKey[:]) + } + if vtxoReq.SigningKey.PubKey == nil { + return nil, fmt.Errorf("external tree signer %x has no "+ + "public key", signerKey[:]) + } + + return newExternalMuSig2Signer( + ctx, env.ExternalTreeSigner, roundID, vtxoReq.SigningKey.PubKey, + ), nil +} + +// newExternalMuSig2Signer builds a proxy signer bound to one external cosigner +// key and round. The context bounds all blocking backend calls, so a failing or +// abandoned round cancels any in-flight external request. +func newExternalMuSig2Signer(ctx context.Context, + backend ExternalTreeSignerBackend, roundID RoundID, + cosignerKey *btcec.PublicKey) *externalMuSig2Signer { + + return &externalMuSig2Signer{ + ctx: ctx, + backend: backend, + roundID: roundID, + cosignerKey: cosignerKey, + sessions: make( + map[input.MuSig2SessionID]*externalTreeSession, + ), + } +} + +// nextSessionID deterministically derives a unique per-transaction session id +// from the round, the cosigner key, and a monotonic counter. Determinism keeps +// the id reproducible for tests and avoids pulling in a randomness source. +func (s *externalMuSig2Signer) nextSessionID() input.MuSig2SessionID { + h := sha256.New() + roundID := s.roundID + _, _ = h.Write(roundID[:]) + _, _ = h.Write(s.cosignerKey.SerializeCompressed()) + + var ctr [8]byte + binary.BigEndian.PutUint64(ctr[:], s.counter) + s.counter++ + _, _ = h.Write(ctr[:]) + + var id input.MuSig2SessionID + copy(id[:], h.Sum(nil)) + + return id +} + +// MuSig2CreateSession allocates a session, fetches a fresh public nonce for the +// external cosigner from the backend, and returns a session info carrying that +// nonce. The local key locator is ignored: the cosigner is identified by the +// public key this proxy is bound to, because an external aggregate key has no +// wallet-resident private key or key locator. +func (s *externalMuSig2Signer) MuSig2CreateSession(version input.MuSig2Version, + _ keychain.KeyLocator, signers []*btcec.PublicKey, + tweaks *input.MuSig2Tweaks, _ [][musig2.PubNonceSize]byte, + _ *musig2.Nonces) (*input.MuSig2SessionInfo, error) { + + s.mu.Lock() + sessionID := s.nextSessionID() + + var sweepRoot []byte + if tweaks != nil { + sweepRoot = tweaks.TaprootTweak + } + + s.sessions[sessionID] = &externalTreeSession{ + cosigners: signers, + sweepTapscriptRoot: sweepRoot, + } + s.mu.Unlock() + + pubNonce, err := s.backend.FetchTreeNonce( + s.ctx, TreeSigningSessionRequest{ + RoundID: s.roundID, + CosignerKey: s.cosignerKey, + SessionID: sessionID, + Cosigners: signers, + SweepTapscriptRoot: sweepRoot, + }, + ) + if err != nil { + s.mu.Lock() + delete(s.sessions, sessionID) + s.mu.Unlock() + + return nil, fmt.Errorf("fetch external tree nonce: %w", err) + } + + return &input.MuSig2SessionInfo{ + SessionID: sessionID, + Version: version, + PublicNonce: pubNonce, + }, nil +} + +// MuSig2RegisterCombinedNonce records the operator-aggregated combined nonce so +// the later partial-signature request can carry it to the external party. +func (s *externalMuSig2Signer) MuSig2RegisterCombinedNonce( + sessionID input.MuSig2SessionID, + combinedNonce [musig2.PubNonceSize]byte) error { + + s.mu.Lock() + defer s.mu.Unlock() + + session, ok := s.sessions[sessionID] + if !ok { + return fmt.Errorf("unknown external tree session %x", + sessionID[:]) + } + + session.aggNonce = combinedNonce + session.haveAggNonce = true + + return nil +} + +// MuSig2Sign fetches the external cosigner's partial signature over sigHash +// under the previously registered aggregate nonce. The session must have a +// combined nonce registered first. When cleanup is set the session state is +// dropped after signing. +func (s *externalMuSig2Signer) MuSig2Sign(sessionID input.MuSig2SessionID, + sigHash [sha256.Size]byte, cleanup bool) (*musig2.PartialSignature, + error) { + + s.mu.Lock() + session, ok := s.sessions[sessionID] + if !ok { + s.mu.Unlock() + + return nil, fmt.Errorf("unknown external tree session %x", + sessionID[:]) + } + if !session.haveAggNonce { + s.mu.Unlock() + + return nil, fmt.Errorf("external tree session %x has no "+ + "combined nonce", sessionID[:]) + } + req := TreeSigningSessionRequest{ + RoundID: s.roundID, + CosignerKey: s.cosignerKey, + SessionID: sessionID, + Cosigners: session.cosigners, + SweepTapscriptRoot: session.sweepTapscriptRoot, + SigHash: sigHash, + AggNonce: session.aggNonce, + } + s.mu.Unlock() + + partialSig, err := s.backend.FetchTreePartialSig(s.ctx, req) + if err != nil { + return nil, fmt.Errorf("fetch external tree partial sig: %w", + err) + } + + if cleanup { + s.mu.Lock() + delete(s.sessions, sessionID) + s.mu.Unlock() + } + + return partialSig, nil +} + +// MuSig2Cleanup drops the session state for the given id. +func (s *externalMuSig2Signer) MuSig2Cleanup( + sessionID input.MuSig2SessionID) error { + + s.mu.Lock() + defer s.mu.Unlock() + + delete(s.sessions, sessionID) + + return nil +} + +// MuSig2RegisterNonces is unsupported: on the client tree-signing path the +// operator aggregates nonces and hands back a combined nonce, which arrives via +// MuSig2RegisterCombinedNonce. +func (s *externalMuSig2Signer) MuSig2RegisterNonces(input.MuSig2SessionID, + [][musig2.PubNonceSize]byte) (bool, error) { + + return false, fmt.Errorf("external tree signer does not support " + + "nonce registration; the operator aggregates nonces") +} + +// MuSig2GetCombinedNonce returns the combined nonce previously registered for +// the session, if any. +func (s *externalMuSig2Signer) MuSig2GetCombinedNonce( + sessionID input.MuSig2SessionID) ([musig2.PubNonceSize]byte, error) { + + s.mu.Lock() + defer s.mu.Unlock() + + session, ok := s.sessions[sessionID] + if !ok || !session.haveAggNonce { + return [musig2.PubNonceSize]byte{}, fmt.Errorf("external tree "+ + "session %x has no combined nonce", sessionID[:]) + } + + return session.aggNonce, nil +} + +// MuSig2CombineSig is unsupported: the operator, not the client, combines the +// partial signatures on the tree-signing path. +func (s *externalMuSig2Signer) MuSig2CombineSig(input.MuSig2SessionID, + []*musig2.PartialSignature) (*schnorr.Signature, bool, error) { + + return nil, false, fmt.Errorf("external tree signer does not support " + + "signature combination; the operator combines partial sigs") +} + +// Compile-time assertion that the proxy satisfies the signer interface used by +// the tree-signing sessions. +var _ input.MuSig2Signer = (*externalMuSig2Signer)(nil) diff --git a/round/external_tree_signer_integration_test.go b/round/external_tree_signer_integration_test.go new file mode 100644 index 000000000..b680452c6 --- /dev/null +++ b/round/external_tree_signer_integration_test.go @@ -0,0 +1,194 @@ +package round + +import ( + "context" + "fmt" + "sync" + "testing" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" + "github.com/google/uuid" + "github.com/lightninglabs/wavelength/lib/tree" + "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" + "github.com/stretchr/testify/require" +) + +// realDelegatingTreeBackend is a test ExternalTreeSignerBackend that stands in +// for the external (e.g. FROST) party by running a real in-memory MuSig2 signer +// for the cosigner key. It proves the daemon-side proxy, the signing executor, +// and the tree session machinery drive a genuine MuSig2 signer end to end when +// the private key lives "outside" the daemon. +type realDelegatingTreeBackend struct { + signer input.MuSig2Signer + + mu sync.Mutex + sessions map[[32]byte]input.MuSig2SessionID +} + +func newRealDelegatingTreeBackend( + signer input.MuSig2Signer) *realDelegatingTreeBackend { + + return &realDelegatingTreeBackend{ + signer: signer, + sessions: make(map[[32]byte]input.MuSig2SessionID), + } +} + +func (b *realDelegatingTreeBackend) FetchTreeNonce(_ context.Context, + req TreeSigningSessionRequest) (tree.Musig2PubNonce, error) { + + info, err := b.signer.MuSig2CreateSession( + input.MuSig2Version100RC2, keychain.KeyLocator{}, req.Cosigners, + &input.MuSig2Tweaks{ + TaprootTweak: req.SweepTapscriptRoot, + }, + nil, + nil, + ) + if err != nil { + return tree.Musig2PubNonce{}, err + } + + b.mu.Lock() + b.sessions[req.SessionID] = info.SessionID + b.mu.Unlock() + + return info.PublicNonce, nil +} + +func (b *realDelegatingTreeBackend) FetchTreePartialSig(_ context.Context, + req TreeSigningSessionRequest) (*musig2.PartialSignature, error) { + + b.mu.Lock() + realID, ok := b.sessions[req.SessionID] + b.mu.Unlock() + if !ok { + return nil, fmt.Errorf("no delegated session for %x", + req.SessionID[:]) + } + + if err := b.signer.MuSig2RegisterCombinedNonce( + realID, req.AggNonce, + ); err != nil { + return nil, err + } + + return b.signer.MuSig2Sign(realID, req.SigHash, true) +} + +// TestExternalTreeSignerDrivesRealSigner proves the full daemon-side path for +// an externally signed VTXO tree key: the signing executor drives the proxy +// signer, which routes MuSig2 session creation and signing to a backend running +// a real signer over a real VTXO tree. The externally produced nonces and +// partial signatures cover exactly the transactions on the cosigner's path, and +// the combined signature verifies — the same outcome as signing locally, but +// with the key held "outside" the daemon. +func TestExternalTreeSignerDrivesRealSigner(t *testing.T) { + t.Parallel() + + h := newTestHarness(t) + + keyFetcher := func(*keychain.KeyDescriptor) (*btcec.PrivateKey, error) { + return h.clientPrivKey, nil + } + + // Baseline: a local signer over the same tree, to cross-check that the + // external path signs the identical transaction set. + localSigner := input.NewMusigSessionManager(keyFetcher) + backend := newRealDelegatingTreeBackend( + input.NewMusigSessionManager(keyFetcher), + ) + + vtxoTree, _ := h.newTestVTXOTree(1) + prevOuts, err := vtxoTree.Root.PrevOutputFetcher(vtxoTree.BatchOutput) + require.NoError(t, err) + + signerKey := NewSignerKey(h.clientPubKey) + signingKey := keychain.KeyDescriptor{PubKey: h.clientPubKey} + + newJob := func(signer input.MuSig2Signer) CreateSignerSessionJob { + return CreateSignerSessionJob{ + SignerKey: signerKey, + Signer: signer, + SigningKey: signingKey, + SweepTapscriptRoot: vtxoTree.SweepTapscriptRoot, + PrevOuts: prevOuts, + Root: vtxoTree.Root, + } + } + + ctx := context.Background() + proxy := newExternalMuSig2Signer( + ctx, backend, + RoundID( + uuid.New(), + ), + h.clientPubKey, + ) + + executor := NewSigningExecutor(1) + + // Create sessions through the external proxy and through a local + // signer. + externalResults, err := executor.CreateSessions( + ctx, []CreateSignerSessionJob{newJob(proxy)}, + ) + require.NoError(t, err) + require.Len(t, externalResults, 1) + + localResults, err := executor.CreateSessions( + ctx, []CreateSignerSessionJob{newJob(localSigner)}, + ) + require.NoError(t, err) + require.Len(t, localResults, 1) + + externalNonces := externalResults[0].Nonces + require.NotEmpty(t, externalNonces) + + // The external path must sign exactly the transactions the local path + // does — the same tree path, keyed by the same transaction ids. + require.Equal( + t, txIDSet(localResults[0].Nonces), txIDSet(externalNonces), + ) + + // A coordinator aggregates the single cosigner's nonce per transaction + // (this test tree is a 1-of-1 client MuSig2) and hands the combined + // nonce back for round two. + aggNonces := make( + map[tree.TxID]tree.Musig2PubNonce, len(externalNonces), + ) + for txID, nonce := range externalNonces { + agg, err := musig2.AggregateNonces( + [][musig2.PubNonceSize]byte{nonce}, + ) + require.NoError(t, err) + aggNonces[txID] = agg + } + require.NoError( + t, externalResults[0].Session.RegisterAggNonces(aggNonces), + ) + + // Round two: the external party produces a partial signature for every + // transaction on its path. + sigs, err := executor.Sign(ctx, externalResults) + require.NoError(t, err) + require.Len(t, sigs, 1) + require.Equal(t, len(externalNonces), len(sigs[0].Signatures)) + for txID, sig := range sigs[0].Signatures { + require.NotNil(t, sig, "missing partial sig for tx %s", txID) + } +} + +// txIDSet returns the transaction id set of a nonce map for comparison. +func txIDSet( + nonces map[tree.TxID]tree.Musig2PubNonce) map[tree.TxID]struct{} { + + out := make(map[tree.TxID]struct{}, len(nonces)) + for txID := range nonces { + out[txID] = struct{}{} + } + + return out +} diff --git a/round/external_tree_signer_test.go b/round/external_tree_signer_test.go new file mode 100644 index 000000000..0f141c7b9 --- /dev/null +++ b/round/external_tree_signer_test.go @@ -0,0 +1,196 @@ +package round + +import ( + "context" + "testing" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" + "github.com/google/uuid" + "github.com/lightninglabs/wavelength/lib/tree" + "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" + "github.com/stretchr/testify/require" +) + +// recordingTreeBackend is a test ExternalTreeSignerBackend that records the +// requests it receives and returns canned material, standing in for the +// external (e.g. FROST) party. +type recordingTreeBackend struct { + nonce tree.Musig2PubNonce + partialSig *musig2.PartialSignature + + nonceReqs []TreeSigningSessionRequest + partialReqs []TreeSigningSessionRequest + + nonceErr error + partialErr error +} + +func (b *recordingTreeBackend) FetchTreeNonce(_ context.Context, + req TreeSigningSessionRequest) (tree.Musig2PubNonce, error) { + + b.nonceReqs = append(b.nonceReqs, req) + if b.nonceErr != nil { + return tree.Musig2PubNonce{}, b.nonceErr + } + + return b.nonce, nil +} + +func (b *recordingTreeBackend) FetchTreePartialSig(_ context.Context, + req TreeSigningSessionRequest) (*musig2.PartialSignature, error) { + + b.partialReqs = append(b.partialReqs, req) + if b.partialErr != nil { + return nil, b.partialErr + } + + return b.partialSig, nil +} + +// newTreeSignerTestKey returns a fresh public key for tree-signer tests. +func newTreeSignerTestKey(t *testing.T) *btcec.PublicKey { + t.Helper() + + priv, err := btcec.NewPrivateKey() + require.NoError(t, err) + + return priv.PubKey() +} + +// TestExternalMuSig2SignerFerriesMaterial verifies the proxy ferries the +// external party's nonce and partial signature through the two MuSig2 rounds, +// carries the round-two sighash and aggregate nonce to the backend, keeps the +// session id stable across rounds, and passes through the cosigner set and +// sweep tweak unchanged. +func TestExternalMuSig2SignerFerriesMaterial(t *testing.T) { + t.Parallel() + + roundID := RoundID(uuid.New()) + cosignerKey := newTreeSignerTestKey(t) + operatorKey := newTreeSignerTestKey(t) + cosigners := []*btcec.PublicKey{cosignerKey, operatorKey} + sweepRoot := []byte{0x11, 0x22, 0x33} + + var wantNonce tree.Musig2PubNonce + wantNonce[0] = 0xab + wantSig := &musig2.PartialSignature{S: new(btcec.ModNScalar)} + wantSig.S.SetInt(42) + + backend := &recordingTreeBackend{ + nonce: wantNonce, + partialSig: wantSig, + } + + signer := newExternalMuSig2Signer( + context.Background(), backend, roundID, cosignerKey, + ) + + // Round one: create session fetches a nonce from the backend. + info, err := signer.MuSig2CreateSession( + input.MuSig2Version100RC2, keychain.KeyLocator{}, cosigners, + &input.MuSig2Tweaks{ + TaprootTweak: sweepRoot, + }, + nil, + nil, + ) + require.NoError(t, err) + require.Equal(t, wantNonce, tree.Musig2PubNonce(info.PublicNonce)) + + require.Len(t, backend.nonceReqs, 1) + nonceReq := backend.nonceReqs[0] + require.Equal(t, roundID, nonceReq.RoundID) + require.Equal(t, cosignerKey, nonceReq.CosignerKey) + require.Equal(t, cosigners, nonceReq.Cosigners) + require.Equal(t, sweepRoot, nonceReq.SweepTapscriptRoot) + require.Equal(t, info.SessionID, nonceReq.SessionID) + + // Signing before the combined nonce is registered must fail. + var sigHash [32]byte + sigHash[0] = 0x77 + _, err = signer.MuSig2Sign(info.SessionID, sigHash, true) + require.ErrorContains(t, err, "no combined nonce") + require.Empty(t, backend.partialReqs) + + // Register the operator-aggregated combined nonce (round 1.5). + var aggNonce [musig2.PubNonceSize]byte + aggNonce[0] = 0xcd + require.NoError( + t, signer.MuSig2RegisterCombinedNonce(info.SessionID, aggNonce), + ) + + // Round two: signing fetches the partial signature, carrying the + // sighash and aggregate nonce to the backend. + gotSig, err := signer.MuSig2Sign(info.SessionID, sigHash, true) + require.NoError(t, err) + require.Equal(t, wantSig, gotSig) + + require.Len(t, backend.partialReqs, 1) + partialReq := backend.partialReqs[0] + require.Equal(t, info.SessionID, partialReq.SessionID) + require.Equal(t, sigHash, partialReq.SigHash) + require.Equal(t, aggNonce, partialReq.AggNonce) + require.Equal(t, cosigners, partialReq.Cosigners) + require.Equal(t, sweepRoot, partialReq.SweepTapscriptRoot) + + // After cleanup-on-sign the session is gone. + _, err = signer.MuSig2Sign(info.SessionID, sigHash, true) + require.ErrorContains(t, err, "unknown external tree session") +} + +// TestExternalMuSig2SignerDistinctSessions verifies each CreateSession call +// gets a distinct, stable session id so concurrent transaction sessions on one +// cosigner path do not collide. +func TestExternalMuSig2SignerDistinctSessions(t *testing.T) { + t.Parallel() + + cosignerKey := newTreeSignerTestKey(t) + backend := &recordingTreeBackend{} + signer := newExternalMuSig2Signer( + context.Background(), backend, + RoundID( + uuid.New(), + ), + cosignerKey, + ) + + a, err := signer.MuSig2CreateSession( + input.MuSig2Version100RC2, keychain.KeyLocator{}, + []*btcec.PublicKey{cosignerKey}, &input.MuSig2Tweaks{}, nil, + nil, + ) + require.NoError(t, err) + + b, err := signer.MuSig2CreateSession( + input.MuSig2Version100RC2, keychain.KeyLocator{}, + []*btcec.PublicKey{cosignerKey}, &input.MuSig2Tweaks{}, nil, + nil, + ) + require.NoError(t, err) + + require.NotEqual(t, a.SessionID, b.SessionID) +} + +// TestExternalMuSig2SignerUnsupported verifies the proxy rejects the MuSig2 +// operations the client never performs on the tree-signing path. +func TestExternalMuSig2SignerUnsupported(t *testing.T) { + t.Parallel() + + signer := newExternalMuSig2Signer( + context.Background(), &recordingTreeBackend{}, + RoundID( + uuid.New(), + ), + newTreeSignerTestKey(t), + ) + + _, err := signer.MuSig2RegisterNonces( + input.MuSig2SessionID{}, nil, + ) + require.Error(t, err) + + _, _, err = signer.MuSig2CombineSig(input.MuSig2SessionID{}, nil) + require.Error(t, err) +} diff --git a/round/fsm_environment.go b/round/fsm_environment.go index 614a3ae53..1b8c83677 100644 --- a/round/fsm_environment.go +++ b/round/fsm_environment.go @@ -31,6 +31,14 @@ type ClientEnvironment struct { // falls back to serial execution for focused FSM tests. SigningExecutor SigningExecutor + // ExternalTreeSigner, when non-nil, supplies MuSig2 tree-signing + // material (nonces and partial signatures) for VTXO signing keys marked + // ExternalTreeSigner, routing them to an external party (e.g. an + // aggregate FROST key the client controls off-box) instead of the local + // wallet. Nil disables external tree signing, so every cosigner key + // signs with the wallet. + ExternalTreeSigner ExternalTreeSignerBackend + // OperatorTerms contains the operator's parameters including sweep // keys, fee targets, confirmation thresholds, and amount limits. OperatorTerms *types.OperatorTerms diff --git a/round/transitions.go b/round/transitions.go index 14d2bc3f6..69ef00ce4 100644 --- a/round/transitions.go +++ b/round/transitions.go @@ -2521,10 +2521,22 @@ func (s *CommitmentTxValidatedState) processEvent(ctx context.Context, signerKey[:], err) } + // By default the wallet signs this cosigner's tree + // path. When the VTXO's signing key is marked external, + // route its MuSig2 nonce and partial-signature + // production to the external party via a proxy signer + // instead. The private key never enters this daemon. + signer, err := selectTreeSigner( + ctx, env, s.RoundID, vtxoReq, signerKey, + ) + if err != nil { + return nil, err + } + sessionJobs = append( sessionJobs, CreateSignerSessionJob{ SignerKey: signerKey, - Signer: env.Wallet, + Signer: signer, SigningKey: vtxoReq.SigningKey, SweepTapscriptRoot: sweepTweak, PrevOuts: prevOutFetcher, diff --git a/rpc/restclient/clients.go b/rpc/restclient/clients.go index 161b9cd10..be8ca7092 100644 --- a/rpc/restclient/clients.go +++ b/rpc/restclient/clients.go @@ -588,6 +588,35 @@ func (c *DaemonServiceClient) SubmitForfeitParticipantSignatures( return out, err } +// ListPendingTreeSigningRequests lists pending external MuSig2 VTXO-tree +// signing requests. +func (c *DaemonServiceClient) ListPendingTreeSigningRequests( + ctx context.Context, in *waverpc.ListPendingTreeSigningRequestsRequest, + _ ...grpc.CallOption) (*waverpc.ListPendingTreeSigningRequestsResponse, + error) { + + out := new(waverpc.ListPendingTreeSigningRequestsResponse) + err := c.client.Post( + ctx, "/v1/daemon/list-pending-tree-signing-requests", in, out, + ) + + return out, err +} + +// SubmitTreeSignatures supplies the external cosigner's nonce or partial +// signature for one pending tree-signing request. +func (c *DaemonServiceClient) SubmitTreeSignatures(ctx context.Context, + in *waverpc.SubmitTreeSignaturesRequest, _ ...grpc.CallOption) ( + *waverpc.SubmitTreeSignaturesResponse, error) { + + out := new(waverpc.SubmitTreeSignaturesResponse) + err := c.client.Post( + ctx, "/v1/daemon/submit-tree-signatures", in, out, + ) + + return out, err +} + // LeaveVTXOs queues VTXOs for cooperative exit. func (c *DaemonServiceClient) LeaveVTXOs(ctx context.Context, in *waverpc.LeaveVTXOsRequest, _ ...grpc.CallOption) ( diff --git a/wallet/board_intent_replayer.go b/wallet/board_intent_replayer.go index 7106bada0..6e18ff589 100644 --- a/wallet/board_intent_replayer.go +++ b/wallet/board_intent_replayer.go @@ -53,6 +53,8 @@ func (b *boardIntentReplayer) Replay(ctx context.Context, var ( liveTarget uint32 + livePolicyTemplate []byte + livePkScript []byte earliestRequestedAt int64 liveAnchors int liveIntents int @@ -94,6 +96,8 @@ func (b *boardIntentReplayer) Replay(ctx context.Context, "non-board payload %T", intent.Payload) } liveTarget = payload.TargetVTXOCount + livePolicyTemplate = payload.PolicyTemplate + livePkScript = payload.PkScript if earliestRequestedAt == 0 || intent.RequestedAt < earliestRequestedAt { @@ -153,6 +157,8 @@ func (b *boardIntentReplayer) Replay(ctx context.Context, // replay. err = a.selfRef.Tell(ctx, &BoardRequest{ TargetVTXOCount: liveTarget, + PolicyTemplate: livePolicyTemplate, + PkScript: livePkScript, }) if err != nil { return false, fmt.Errorf("self-tell pending board request: %w", diff --git a/wallet/board_replay_test.go b/wallet/board_replay_test.go index f76847d79..f8de54c7f 100644 --- a/wallet/board_replay_test.go +++ b/wallet/board_replay_test.go @@ -1,6 +1,7 @@ package wallet import ( + "bytes" "context" "errors" "testing" @@ -325,6 +326,137 @@ func TestReplaySelfTellsBoardWhenAnchorIsStillConfirmed(t *testing.T) { store.AssertExpectations(t) } +// TestBoardIntentIDDistinguishesPolicy verifies the intent-ID digest is +// policy-sensitive: two board intents over the same anchors and target that +// differ only by their custom policy (or by an empty vs a set policy) hash to +// distinct IDs. Without this, a custom-policy board and a standard board over +// the same outpoints would collide and upsert over each other in the outbox. +func TestBoardIntentIDDistinguishesPolicy(t *testing.T) { + t.Parallel() + + anchors := []wire.OutPoint{boardReplayTestOutpoint(0x71)} + + standard := &BoardIntentPayload{TargetVTXOCount: 1} + customA := &BoardIntentPayload{ + TargetVTXOCount: 1, + PolicyTemplate: []byte{ + 0x01, + 0xaa, + }, + } + customB := &BoardIntentPayload{ + TargetVTXOCount: 1, + PolicyTemplate: []byte{ + 0x01, + 0xbb, + }, + } + customBWithScript := &BoardIntentPayload{ + TargetVTXOCount: 1, + PolicyTemplate: []byte{ + 0x01, + 0xbb, + }, + PkScript: []byte{ + 0x02, + }, + } + + standardID := NewPendingIntentID(standard, anchors) + customAID := NewPendingIntentID(customA, anchors) + customBID := NewPendingIntentID(customB, anchors) + customBScriptID := NewPendingIntentID(customBWithScript, anchors) + + require.NotEqual( + t, standardID, customAID, + "standard and custom policy must not collide", + ) + require.NotEqual( + t, customAID, customBID, + "distinct policy templates must not collide", + ) + require.NotEqual( + t, customBID, customBScriptID, + "pinned pk_script must affect the intent ID", + ) + + // The digest is deterministic for identical payloads. + require.Equal(t, customAID, NewPendingIntentID(customA, anchors)) +} + +// TestReplayCarriesCustomPolicyToBoardRequest verifies that a persisted board +// intent's custom VTXO policy survives restart replay: the self-Telled +// BoardRequest carries the same PolicyTemplate and PkScript, so replay +// recreates the same custom-owned output instead of silently re-boarding into +// the standard collaborative shape. +func TestReplayCarriesCustomPolicyToBoardRequest(t *testing.T) { + t.Parallel() + + liveOp := boardReplayTestOutpoint(0x61) + + policyTemplate := []byte{0x01, 0xaa, 0xbb, 0xcc} + pkScript := bytes.Repeat([]byte{0x02}, 34) + + payload := &BoardIntentPayload{ + TargetVTXOCount: 3, + PolicyTemplate: policyTemplate, + PkScript: pkScript, + } + anchors := []wire.OutPoint{liveOp} + pending := []PendingIntent{{ + ID: NewPendingIntentID(payload, anchors), + Payload: payload, + RequestedAt: 1_700_000_000, + Anchors: anchors, + }} + + store := &MockBoardingStore{} + store.On( + "ListPendingIntents", mock.Anything, PendingIntentKindBoard, + ).Return(pending, nil) + store.On( + "ListPendingIntents", mock.Anything, + PendingIntentKindSendOnChain, + ).Return([]PendingIntent(nil), nil) + store.On( + "FetchBoardingIntentsByStatus", mock.Anything, + BoardingStatusConfirmed, + ).Return([]BoardingIntent{ + { + Outpoint: liveOp, + ChainInfo: BoardingChainInfo{ + OutPoint: liveOp, + Amount: 25_000, + }, + Status: BoardingStatusConfirmed, + }, + }, nil) + + clk := clock.NewTestClock(time.Unix(1_700_000_000, 0)) + w, _ := newBoardReplayTestWallet(t, store, clk) + + selfRef := actor.NewChannelTellOnlyRef[WalletMsg]( + "test-wallet-self", 4, + ) + w.selfRef = selfRef + + result := w.Receive(t.Context(), &ReplayPendingIntentsRequest{}) + require.True( + t, result.IsOk(), + "replay must succeed; got %v", result.Err(), + ) + + msg, ok := selfRef.AwaitMessage(2 * time.Second) + require.True(t, ok, "expected replay to self-Tell a BoardRequest") + boardReq, ok := msg.(*BoardRequest) + require.True(t, ok, "expected *BoardRequest, got %T", msg) + require.Equal(t, uint32(3), boardReq.TargetVTXOCount) + require.Equal(t, policyTemplate, boardReq.PolicyTemplate) + require.Equal(t, pkScript, boardReq.PkScript) + + store.AssertExpectations(t) +} + // TestReplayDeletesStaleBoardIntentAlongsideLiveOne verifies that a fully // stale board intent (all anchors no longer Confirmed) is deleted by ID // during replay even when another intent is still live, rather than diff --git a/wallet/messages.go b/wallet/messages.go index e5ccec9de..fd6e2be73 100644 --- a/wallet/messages.go +++ b/wallet/messages.go @@ -737,6 +737,20 @@ type BoardRequest struct { // sets this to false so a replay re-persists with a fresh // timestamp. NoPersist bool + + // PolicyTemplate optionally pins the arkscript policy for every boarded + // VTXO output. When nil, the round actor synthesizes the standard + // collaborative policy with a freshly derived owner key. When set, the + // boarded outputs adopt this serialized template verbatim, so a client + // can board directly into a custom-owned VTXO (e.g. one owned by an + // external FROST aggregate key). It is persisted with the board intent + // and re-applied on restart replay. + PolicyTemplate []byte + + // PkScript optionally pins the taproot output script for the boarded + // VTXOs. Only valid alongside PolicyTemplate; when empty the script is + // derived from the template. + PkScript []byte } // MessageType returns the message type identifier for logging and debugging. diff --git a/wallet/pending_intent.go b/wallet/pending_intent.go index b36a43aa4..38f94babb 100644 --- a/wallet/pending_intent.go +++ b/wallet/pending_intent.go @@ -70,6 +70,17 @@ type BoardIntentPayload struct { // "collapse the confirmed boarding balance into one VTXO", non-zero // fans the balance into that many VTXOs. TargetVTXOCount uint32 + + // PolicyTemplate mirrors BoardRequest.PolicyTemplate: the serialized + // arkscript policy the boarded outputs adopt, or nil for the standard + // collaborative policy. Persisted so restart replay recreates the same + // custom output rather than silently re-boarding into the standard + // shape. + PolicyTemplate []byte + + // PkScript mirrors BoardRequest.PkScript: the pinned taproot output + // script, or nil to derive it from PolicyTemplate. + PkScript []byte } // Kind reports the board intent kind. @@ -77,11 +88,17 @@ func (p *BoardIntentPayload) Kind() PendingIntentKind { return PendingIntentKindBoard } -// writeIDDigest writes the canonical field encoding for ID derivation. +// writeIDDigest writes the canonical field encoding for ID derivation. Byte +// slices are length-prefixed so two boards differing only by policy (or by an +// empty vs a set script that shares a prefix) can never collide on the same +// intent ID. func (p *BoardIntentPayload) writeIDDigest(w io.Writer) { var b [4]byte binary.BigEndian.PutUint32(b[:], p.TargetVTXOCount) _, _ = w.Write(b[:]) + + writeLenPrefixed(w, p.PolicyTemplate) + writeLenPrefixed(w, p.PkScript) } func (p *BoardIntentPayload) sealPendingIntentPayload() {} diff --git a/wallet/wallet.go b/wallet/wallet.go index c7c02b172..3f15bb054 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -2349,6 +2349,8 @@ func (a *Ark) handleBoard(ctx context.Context, payload := &BoardIntentPayload{ TargetVTXOCount: req.TargetVTXOCount, + PolicyTemplate: req.PolicyTemplate, + PkScript: req.PkScript, } pendingIntent := PendingIntent{ @@ -2380,9 +2382,11 @@ func (a *Ark) handleBoard(ctx context.Context, if err := roundRef.Tell( ctx, &actormsg.TriggerBoardMsg{ - Amounts: vtxoAmounts, - Outpoints: boardOutpoints, - Change: changeLeave, + Amounts: vtxoAmounts, + Outpoints: boardOutpoints, + Change: changeLeave, + PolicyTemplate: req.PolicyTemplate, + PkScript: req.PkScript, }, ); err != nil { // The persisted row stays in place so the next daemon diff --git a/waved/rpc_auth.go b/waved/rpc_auth.go index db62b4461..c003dfce6 100644 --- a/waved/rpc_auth.go +++ b/waved/rpc_auth.go @@ -105,11 +105,13 @@ func newWavedRPCPermissions() map[string][]bakery.Op { daemon, entityVTXO, "read", "ListVTXOs", "GetIndexedVTXOByPkScript", "GetVTXOExpiryInfo", "ListPendingForfeitParticipantSignatureRequests", + "ListPendingTreeSigningRequests", ) grant( daemon, entityVTXO, "write", "SendVTXO", "SignVTXOForfeit", "RefreshVTXOs", "RefreshCustomVTXOs", "SubmitForfeitParticipantSignatures", "LeaveVTXOs", + "SubmitTreeSignatures", ) grant( daemon, entityAddress, "write", "NewAddress", diff --git a/waved/rpc_board_policy_test.go b/waved/rpc_board_policy_test.go new file mode 100644 index 000000000..0713b01af --- /dev/null +++ b/waved/rpc_board_policy_test.go @@ -0,0 +1,138 @@ +package waved + +import ( + "testing" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/lightninglabs/wavelength/lib/arkscript" + "github.com/lightninglabs/wavelength/lib/types" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// boardPolicyTestKey returns a fresh secp256k1 public key for policy tests. +func boardPolicyTestKey(t *testing.T) *btcec.PublicKey { + t.Helper() + + priv, err := btcec.NewPrivateKey() + require.NoError(t, err) + + return priv.PubKey() +} + +// TestValidateBoardPolicyTemplate exercises the Board custom-policy validation +// boundary: the standard (empty-template) path, the pinned-script-without- +// template rejection, and the decode / operator-binding / pk_script-match +// checks on a supplied template. +func TestValidateBoardPolicyTemplate(t *testing.T) { + t.Parallel() + + const exitDelay = uint32(144) + + operatorKey := boardPolicyTestKey(t) + ownerKey := boardPolicyTestKey(t) + otherOperatorKey := boardPolicyTestKey(t) + + terms := &types.OperatorTerms{ + PubKey: operatorKey, + VTXOExitDelay: exitDelay, + } + + // A standard Ark VTXO template owned by ownerKey, co-signed by the + // operator, with an exit delay meeting the operator's floor. This + // stands in for a FROST-owned VTXO: ownerKey is opaque to the daemon. + validTemplate, err := arkscript.EncodeStandardVTXOTemplate( + ownerKey, operatorKey, exitDelay, + ) + require.NoError(t, err) + + decoded, err := arkscript.DecodePolicyTemplate(validTemplate) + require.NoError(t, err) + validPkScript, err := decoded.PkScript() + require.NoError(t, err) + + // A template whose operator key is not the terms' operator: the + // operator cannot co-sign its collab leaf, so admission must reject it. + wrongOperatorTemplate, err := arkscript.EncodeStandardVTXOTemplate( + ownerKey, otherOperatorKey, exitDelay, + ) + require.NoError(t, err) + + tests := []struct { + name string + policyTemplate []byte + pkScript []byte + wantErr bool + }{ + { + name: "no template, no script", + policyTemplate: nil, + pkScript: nil, + wantErr: false, + }, + { + name: "script without template rejected", + policyTemplate: nil, + pkScript: validPkScript, + wantErr: true, + }, + { + name: "garbage template rejected", + policyTemplate: []byte{ + 0xff, + 0xff, + 0xff, + }, + pkScript: nil, + wantErr: true, + }, + { + name: "wrong operator rejected", + policyTemplate: wrongOperatorTemplate, + pkScript: nil, + wantErr: true, + }, + { + name: "valid template, no script", + policyTemplate: validTemplate, + pkScript: nil, + wantErr: false, + }, + { + name: "valid template, matching script", + policyTemplate: validTemplate, + pkScript: validPkScript, + wantErr: false, + }, + { + name: "valid template, mismatched script", + policyTemplate: validTemplate, + pkScript: append( + []byte{0x51, 0x20}, make([]byte, 32)..., + ), + wantErr: true, + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + err := validateBoardPolicyTemplate( + tc.policyTemplate, tc.pkScript, terms, + ) + if !tc.wantErr { + require.NoError(t, err) + + return + } + + require.Error(t, err) + require.Equal( + t, codes.InvalidArgument, status.Code(err), + ) + }) + } +} diff --git a/waved/rpc_server.go b/waved/rpc_server.go index db7c3e0af..a03625f63 100644 --- a/waved/rpc_server.go +++ b/waved/rpc_server.go @@ -1905,6 +1905,67 @@ func (r *RPCServer) SubmitForfeitParticipantSignatures(ctx context.Context, return &waverpc.SubmitForfeitParticipantSignaturesResponse{}, nil } +// ListPendingTreeSigningRequests returns pending MuSig2 VTXO-tree signing +// requests for externally signed cosigner keys. +func (r *RPCServer) ListPendingTreeSigningRequests(_ context.Context, + req *waverpc.ListPendingTreeSigningRequestsRequest) ( + *waverpc.ListPendingTreeSigningRequestsResponse, error) { + + if r.server.treeSignatures == nil { + return nil, status.Error( + codes.FailedPrecondition, + "tree signature broker is not configured", + ) + } + + after := uint64(0) + limit := uint32(0) + if req != nil { + after = req.GetAfterSequence() + limit = req.GetLimit() + } + + requests, next := r.server.treeSignatures.list(after, limit) + + return &waverpc.ListPendingTreeSigningRequestsResponse{ + Requests: requests, + NextSequence: next, + }, nil +} + +// SubmitTreeSignatures supplies the external cosigner's nonce or partial +// signature for one pending tree-signing request. +func (r *RPCServer) SubmitTreeSignatures(ctx context.Context, + req *waverpc.SubmitTreeSignaturesRequest) ( + *waverpc.SubmitTreeSignaturesResponse, error) { + + if req == nil { + return nil, status.Error( + codes.InvalidArgument, "request is required", + ) + } + if r.server.treeSignatures == nil { + return nil, status.Error( + codes.FailedPrecondition, + "tree signature broker is not configured", + ) + } + + err := r.server.treeSignatures.submit( + req.GetRequestId(), req.GetRound(), req.GetPublicNonce(), + req.GetPartialSignature(), + ) + if err != nil { + return nil, err + } + + r.server.log.DebugS(ctx, "Accepted tree signing submission", + slog.String("round", req.GetRound().String()), + ) + + return &waverpc.SubmitTreeSignaturesResponse{}, nil +} + func buildCustomRefreshRequest(req *waverpc.RefreshCustomVTXOsRequest) ( []wallet.CustomRefreshInput, []wallet.CustomRefreshOutput, []string, error) { @@ -2619,6 +2680,49 @@ func (r *RPCServer) SendOnChain(ctx context.Context, // balance check, VTXO amount computation, and round registration. It // returns immediately after the wallet accepts the request; use // ListRounds/WatchRounds to observe round progress. +// validateBoardPolicyTemplate validates an optional custom VTXO policy template +// (and its optional pinned pk_script) supplied on a Board request against the +// operator's terms. An empty template selects the standard collaborative +// policy; a pinned pk_script without a template is rejected. A non-empty +// template must be a well-formed Ark policy (operator on every collab leaf, +// exit leaves gated by at least the operator's CSV floor) and, when a +// pk_script is pinned, must derive to exactly that script. All failures map to +// InvalidArgument so the caller can correct the request. +func validateBoardPolicyTemplate(policyTemplate, pkScript []byte, + terms *types.OperatorTerms) error { + + if len(policyTemplate) == 0 { + if len(pkScript) > 0 { + return status.Errorf(codes.InvalidArgument, + "pk_script requires vtxo_policy_template") + } + + return nil + } + + template, err := arkscript.DecodePolicyTemplate(policyTemplate) + if err != nil { + return status.Errorf(codes.InvalidArgument, "decode "+ + "vtxo_policy_template: %v", err) + } + + err = template.ValidateArkPolicy(arkscript.PolicyValidationOpts{ + OperatorKey: terms.PubKey, + MinExitDelay: terms.VTXOExitDelay, + }) + if err != nil { + return status.Errorf(codes.InvalidArgument, "invalid "+ + "vtxo_policy_template: %v", err) + } + + if len(pkScript) > 0 && !template.MatchesPkScript(pkScript) { + return status.Errorf(codes.InvalidArgument, "pk_script does "+ + "not match vtxo_policy_template") + } + + return nil +} + func (r *RPCServer) Board(ctx context.Context, req *waverpc.BoardRequest) ( *waverpc.BoardResponse, error) { @@ -2647,6 +2751,21 @@ func (r *RPCServer) Board(ctx context.Context, req *waverpc.BoardRequest) ( } wRef := r.server.walletRef.UnsafeFromSome() + // When the caller pins a custom VTXO policy template for the boarded + // outputs, validate it against the operator's terms before admission so + // a malformed or unsafe policy (operator not on every collab leaf, exit + // leaf below the CSV floor, or a pinned script that does not match the + // template) is rejected at the RPC boundary rather than surfacing as a + // round failure. The operator's own fee authority under #270 is + // unaffected: the template governs ownership, not amounts. + policyTemplate := req.GetVtxoPolicyTemplate() + pkScript := req.GetPkScript() + if err := validateBoardPolicyTemplate( + policyTemplate, pkScript, terms, + ); err != nil { + return nil, err + } + // Under the #270 seal-time fee handshake the server is the // fee authority — the client no longer pre-computes or pre- // deducts an operator fee at submit time. The wallet ships @@ -2654,11 +2773,12 @@ func (r *RPCServer) Board(ctx context.Context, req *waverpc.BoardRequest) ( // residual into the boarding VTXO output when the round // seals. Any CLI / UX fee preview is produced by the // EstimateFee RPC, not by the Board admission path. - _ = terms boardReq := &wallet.BoardRequest{ TargetVTXOCount: req.GetTargetVtxoCount(), NoPersist: req.GetNoPersist(), + PolicyTemplate: policyTemplate, + PkScript: pkScript, } future := wRef.Ask(ctx, boardReq) diff --git a/waved/server.go b/waved/server.go index 4617f0d4c..1ab272ab6 100644 --- a/waved/server.go +++ b/waved/server.go @@ -412,6 +412,8 @@ type Server struct { mailboxMux *mailboxrpc.ServeMux forfeitSignatures *forfeitSignatureBroker + + treeSignatures *treeSignatureBroker } // NewServer allocates a Server from a validated Config. The server is @@ -426,6 +428,7 @@ func NewServer(cfg *Config) (*Server, error) { daemonReady: make(chan struct{}), vhtlcPreimages: &unrollpolicy.PreimageResolverRegistry{}, forfeitSignatures: newForfeitSignatureBroker(), + treeSignatures: newTreeSignatureBroker(), }, nil } @@ -4178,17 +4181,18 @@ func (s *Server) initRoundActor(ctx context.Context, SigningExecutor: round.NewSigningExecutor( signingWorkers, ), - RoundStore: roundStore, - VTXOStore: roundStore, - OperatorTerms: operatorTerms, - ServerConn: s.runtime.TellRef(), - ChainSource: chainSourceRef, - WalletActor: walletRef, - ChainParams: s.chainParams, - ActorSystem: s.actorSystem, - TimeoutActor: timeoutRef, - MaxOperatorFee: maxOperatorFee, - VTXOManager: vtxoManager, + ExternalTreeSigner: s.treeSignatures, + RoundStore: roundStore, + VTXOStore: roundStore, + OperatorTerms: operatorTerms, + ServerConn: s.runtime.TellRef(), + ChainSource: chainSourceRef, + WalletActor: walletRef, + ChainParams: s.chainParams, + ActorSystem: s.actorSystem, + TimeoutActor: timeoutRef, + MaxOperatorFee: maxOperatorFee, + VTXOManager: vtxoManager, DropCustomForfeitSigningContexts: s. dropCustomForfeitSigningContexts, OwnedScriptChecker: scriptChecker, diff --git a/waved/tree_signature_broker.go b/waved/tree_signature_broker.go new file mode 100644 index 000000000..e7983e162 --- /dev/null +++ b/waved/tree_signature_broker.go @@ -0,0 +1,524 @@ +package waved + +import ( + "bytes" + "context" + "crypto/sha256" + "fmt" + "sync" + "time" + + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" + "github.com/lightninglabs/wavelength/lib/tree" + "github.com/lightninglabs/wavelength/round" + "github.com/lightninglabs/wavelength/waverpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const ( + defaultTreeSigningRequestLimit = 100 + defaultAnsweredTreeRequestLimit = 256 + treeSigningRequestDomain = "waved-tree-signing-request-v1" + + // defaultTreeSigningWaitTimeout bounds how long the round FSM blocks + // waiting for an external party to answer one tree-signing request. + defaultTreeSigningWaitTimeout = 5 * time.Minute +) + +// treeSigResult carries the material an external party submits for one +// tree-signing request. Exactly one field is populated per request round. +type treeSigResult struct { + nonce tree.Musig2PubNonce + partialSig *musig2.PartialSignature +} + +type treeSignatureRequest struct { + proto *waverpc.PendingTreeSigningRequest + answered bool + result treeSigResult + waiters []chan treeSigResult +} + +// treeSignatureBroker exposes the round FSM's external MuSig2 tree-signing +// callbacks (ExternalTreeSignerBackend) to an outside party over daemon RPC. +// When a VTXO's cosigner key is marked external, the FSM's proxy signer calls +// FetchTreeNonce / FetchTreePartialSig; the broker parks each call as a pending +// request, surfaces it via ListPendingTreeSigningRequests, and unblocks it when +// SubmitTreeSignatures supplies the material. State is deliberately +// daemon-local: a restart abandons in-flight rounds rather than resuming a +// stale signing transcript. +type treeSignatureBroker struct { + mu sync.Mutex + + nextSequence uint64 + requests map[string]*treeSignatureRequest + order []string + + waitTimeout time.Duration +} + +func newTreeSignatureBroker() *treeSignatureBroker { + return &treeSignatureBroker{ + requests: make(map[string]*treeSignatureRequest), + waitTimeout: defaultTreeSigningWaitTimeout, + } +} + +// FetchTreeNonce blocks until the external party submits a public nonce for the +// requested session, or the context is cancelled. +func (b *treeSignatureBroker) FetchTreeNonce(ctx context.Context, + req round.TreeSigningSessionRequest) (tree.Musig2PubNonce, error) { + + pending, err := pendingTreeSigningRequest( + req, waverpc.TreeSigningRound_TREE_SIGNING_ROUND_NONCE, + ) + if err != nil { + return tree.Musig2PubNonce{}, err + } + + result, err := b.block(ctx, pending) + if err != nil { + return tree.Musig2PubNonce{}, err + } + + return result.nonce, nil +} + +// FetchTreePartialSig blocks until the external party submits a partial +// signature for the requested session, or the context is cancelled. +func (b *treeSignatureBroker) FetchTreePartialSig(ctx context.Context, + req round.TreeSigningSessionRequest) (*musig2.PartialSignature, error) { + + pending, err := pendingTreeSigningRequest( + req, waverpc.TreeSigningRound_TREE_SIGNING_ROUND_PARTIAL_SIG, + ) + if err != nil { + return nil, err + } + + result, err := b.block(ctx, pending) + if err != nil { + return nil, err + } + + return result.partialSig, nil +} + +// block parks the pending request and waits for it to be answered. +func (b *treeSignatureBroker) block(ctx context.Context, + pending *waverpc.PendingTreeSigningRequest) (treeSigResult, error) { + + requestID := string(pending.GetRequestId()) + waiter := make(chan treeSigResult, 1) + + b.mu.Lock() + stored, ok := b.requests[requestID] + if ok { + if !samePendingTreeSigningRequest(stored.proto, pending) { + b.mu.Unlock() + + return treeSigResult{}, fmt.Errorf("tree signing " + + "request id conflict") + } + } else { + b.nextSequence++ + pending.Sequence = b.nextSequence + stored = &treeSignatureRequest{proto: pending} + b.requests[requestID] = stored + b.order = append(b.order, requestID) + } + + if stored.answered { + result := stored.result + b.mu.Unlock() + + return result, nil + } + + stored.waiters = append(stored.waiters, waiter) + b.mu.Unlock() + + waitCtx, cancel := b.waitContext(ctx) + defer cancel() + + select { + case result := <-waiter: + return result, nil + + case <-waitCtx.Done(): + b.removeWaiter(requestID, waiter) + + return treeSigResult{}, waitCtx.Err() + } +} + +func (b *treeSignatureBroker) waitContext(ctx context.Context) (context.Context, + context.CancelFunc) { + + if b.waitTimeout <= 0 { + return ctx, func() {} + } + + return context.WithTimeout(ctx, b.waitTimeout) +} + +func (b *treeSignatureBroker) removeWaiter(requestID string, + waiter chan treeSigResult) { + + b.mu.Lock() + defer b.mu.Unlock() + + stored := b.requests[requestID] + if stored == nil { + return + } + + for i, candidate := range stored.waiters { + if candidate != waiter { + continue + } + + stored.waiters = append( + stored.waiters[:i], stored.waiters[i+1:]..., + ) + + return + } +} + +// list returns pending, unanswered tree-signing requests with a sequence above +// after, up to limit entries. +func (b *treeSignatureBroker) list(after uint64, limit uint32) ( + []*waverpc.PendingTreeSigningRequest, uint64) { + + if b == nil { + return nil, after + } + if limit == 0 { + limit = defaultTreeSigningRequestLimit + } + + b.mu.Lock() + defer b.mu.Unlock() + + b.pruneAnsweredRequestsLocked() + + requests := make([]*waverpc.PendingTreeSigningRequest, 0, limit) + next := after + for _, id := range b.order { + req := b.requests[id] + if req == nil || req.proto.GetSequence() <= after { + continue + } + if req.answered { + continue + } + + requests = append( + requests, clonePendingTreeSigningRequest(req.proto), + ) + next = req.proto.GetSequence() + if uint32(len(requests)) >= limit { + break + } + } + + return requests, next +} + +// submit records the external party's material for one pending request and +// wakes the blocked round FSM. +func (b *treeSignatureBroker) submit(requestID []byte, + sigRound waverpc.TreeSigningRound, publicNonce, + partialSignature []byte) error { + + if b == nil { + return status.Error( + codes.FailedPrecondition, + "tree signature broker is not configured", + ) + } + if len(requestID) == 0 { + return status.Error( + codes.InvalidArgument, "request_id is required", + ) + } + + id := string(requestID) + + b.mu.Lock() + defer b.mu.Unlock() + + req, ok := b.requests[id] + if !ok { + return status.Error( + codes.NotFound, "tree signing request not found", + ) + } + if req.proto.GetRound() != sigRound { + return status.Errorf(codes.InvalidArgument, "round mismatch: "+ + "request is %v, submitted %v", req.proto.GetRound(), + sigRound) + } + + result, err := parseTreeSignatureResult( + sigRound, publicNonce, partialSignature, + ) + if err != nil { + return status.Errorf(codes.InvalidArgument, "%v", err) + } + + if req.answered { + if sameTreeSigResult(sigRound, req.result, result) { + return nil + } + + return status.Error( + codes.AlreadyExists, + "tree signing request already answered", + ) + } + + req.answered = true + req.result = result + waiters := req.waiters + req.waiters = nil + for _, waiter := range waiters { + select { + case waiter <- result: + default: + } + close(waiter) + } + b.pruneAnsweredRequestsLocked() + + return nil +} + +func (b *treeSignatureBroker) pruneAnsweredRequestsLocked() { + answered := 0 + for i := len(b.order) - 1; i >= 0; i-- { + id := b.order[i] + req := b.requests[id] + if req == nil { + b.order = append(b.order[:i], b.order[i+1:]...) + + continue + } + if !req.answered { + continue + } + + answered++ + if answered <= defaultAnsweredTreeRequestLimit { + continue + } + + delete(b.requests, id) + b.order = append(b.order[:i], b.order[i+1:]...) + } +} + +// pendingTreeSigningRequest builds the wire request for one signing round from +// the FSM's internal session request. +func pendingTreeSigningRequest(req round.TreeSigningSessionRequest, + sigRound waverpc.TreeSigningRound) (*waverpc.PendingTreeSigningRequest, + error) { + + if req.CosignerKey == nil { + return nil, fmt.Errorf("cosigner key is required") + } + if len(req.Cosigners) == 0 { + return nil, fmt.Errorf("cosigners are required") + } + + cosigners := make([][]byte, 0, len(req.Cosigners)) + for i, key := range req.Cosigners { + if key == nil { + return nil, fmt.Errorf("cosigner %d is nil", i) + } + cosigners = append(cosigners, key.SerializeCompressed()) + } + + roundID := req.RoundID + + pending := &waverpc.PendingTreeSigningRequest{ + Round: sigRound, + RoundId: append([]byte(nil), roundID[:]...), + CosignerPubkey: req.CosignerKey.SerializeCompressed(), + SessionId: append([]byte(nil), req.SessionID[:]...), + Cosigners: cosigners, + SweepTapscriptRoot: append( + []byte(nil), req.SweepTapscriptRoot..., + ), + } + + if sigRound == waverpc.TreeSigningRound_TREE_SIGNING_ROUND_PARTIAL_SIG { + pending.Sighash = append([]byte(nil), req.SigHash[:]...) + pending.AggregateNonce = append( + []byte(nil), req.AggNonce[:]..., + ) + } + + pending.RequestId = treeSigningRequestID(pending) + + return pending, nil +} + +// treeSigningRequestID is the stable digest over a request's transcript. The +// round tag plus the round-two-only sighash and aggregate nonce give the NONCE +// and PARTIAL_SIG requests for one session distinct ids. +func treeSigningRequestID(req *waverpc.PendingTreeSigningRequest) []byte { + h := sha256.New() + h.Write([]byte(treeSigningRequestDomain)) + h.Write([]byte{0}) + h.Write([]byte{byte(req.GetRound())}) + h.Write(req.GetRoundId()) + h.Write(req.GetCosignerPubkey()) + h.Write(req.GetSessionId()) + for _, cosigner := range req.GetCosigners() { + h.Write(cosigner) + } + h.Write(req.GetSweepTapscriptRoot()) + h.Write(req.GetSighash()) + h.Write(req.GetAggregateNonce()) + + return h.Sum(nil) +} + +// parseTreeSignatureResult validates and decodes the submitted material for the +// given round. It does not cryptographically verify a partial signature against +// the session (that would require reconstructing the MuSig2 context); an +// invalid partial signature instead surfaces downstream as a tree-signature +// validation failure when the operator returns the aggregated signature. +func parseTreeSignatureResult(sigRound waverpc.TreeSigningRound, publicNonce, + partialSignature []byte) (treeSigResult, error) { + + switch sigRound { + case waverpc.TreeSigningRound_TREE_SIGNING_ROUND_NONCE: + if len(publicNonce) != musig2.PubNonceSize { + return treeSigResult{}, fmt.Errorf("public_nonce must "+ + "be %d bytes, got %d", musig2.PubNonceSize, + len(publicNonce)) + } + var nonce tree.Musig2PubNonce + copy(nonce[:], publicNonce) + + return treeSigResult{nonce: nonce}, nil + + case waverpc.TreeSigningRound_TREE_SIGNING_ROUND_PARTIAL_SIG: + if len(partialSignature) == 0 { + return treeSigResult{}, fmt.Errorf( + "partial_signature is required") + } + sig := &musig2.PartialSignature{} + if err := sig.Decode( + bytes.NewReader(partialSignature), + ); err != nil { + return treeSigResult{}, fmt.Errorf("decode partial "+ + "signature: %w", err) + } + + return treeSigResult{partialSig: sig}, nil + + default: + return treeSigResult{}, fmt.Errorf("unsupported signing "+ + "round: %v", sigRound) + } +} + +// sameTreeSigResult reports whether two results for the same round are equal, +// so an idempotent resubmit of identical material is accepted. +func sameTreeSigResult(sigRound waverpc.TreeSigningRound, a, + b treeSigResult) bool { + + switch sigRound { + case waverpc.TreeSigningRound_TREE_SIGNING_ROUND_NONCE: + return a.nonce == b.nonce + + case waverpc.TreeSigningRound_TREE_SIGNING_ROUND_PARTIAL_SIG: + if a.partialSig == nil || b.partialSig == nil { + return a.partialSig == b.partialSig + } + + return serializePartialSig(a.partialSig) == + serializePartialSig(b.partialSig) + + default: + return false + } +} + +// serializePartialSig encodes a partial signature to a comparable string. +func serializePartialSig(sig *musig2.PartialSignature) string { + var buf bytes.Buffer + if err := sig.Encode(&buf); err != nil { + return "" + } + + return buf.String() +} + +// clonePendingTreeSigningRequest returns a detached copy of a pending request +// so callers cannot mutate broker-owned state. +func clonePendingTreeSigningRequest( + req *waverpc.PendingTreeSigningRequest, +) *waverpc.PendingTreeSigningRequest { + + if req == nil { + return nil + } + + cosigners := make([][]byte, 0, len(req.GetCosigners())) + for _, cosigner := range req.GetCosigners() { + cosigners = append(cosigners, bytes.Clone(cosigner)) + } + + return &waverpc.PendingTreeSigningRequest{ + RequestId: bytes.Clone(req.GetRequestId()), + Sequence: req.GetSequence(), + Round: req.GetRound(), + RoundId: bytes.Clone(req.GetRoundId()), + CosignerPubkey: bytes.Clone(req.GetCosignerPubkey()), + SessionId: bytes.Clone(req.GetSessionId()), + Cosigners: cosigners, + SweepTapscriptRoot: bytes.Clone(req.GetSweepTapscriptRoot()), + Sighash: bytes.Clone(req.GetSighash()), + AggregateNonce: bytes.Clone(req.GetAggregateNonce()), + } +} + +// samePendingTreeSigningRequest reports whether two pending requests carry +// identical signing transcripts. +func samePendingTreeSigningRequest( + a, b *waverpc.PendingTreeSigningRequest) bool { + + if !bytes.Equal(a.GetRequestId(), b.GetRequestId()) || + a.GetRound() != b.GetRound() || + !bytes.Equal(a.GetRoundId(), b.GetRoundId()) || + !bytes.Equal(a.GetCosignerPubkey(), b.GetCosignerPubkey()) || + !bytes.Equal(a.GetSessionId(), b.GetSessionId()) || + !bytes.Equal( + a.GetSweepTapscriptRoot(), b.GetSweepTapscriptRoot(), + ) || + !bytes.Equal(a.GetSighash(), b.GetSighash()) || + !bytes.Equal(a.GetAggregateNonce(), b.GetAggregateNonce()) { + return false + } + + if len(a.GetCosigners()) != len(b.GetCosigners()) { + return false + } + for i := range a.GetCosigners() { + if !bytes.Equal(a.GetCosigners()[i], b.GetCosigners()[i]) { + return false + } + } + + return true +} + +// Compile-time assertion that the broker satisfies the FSM's external +// tree-signer backend seam. +var _ round.ExternalTreeSignerBackend = (*treeSignatureBroker)(nil) diff --git a/waved/tree_signature_broker_test.go b/waved/tree_signature_broker_test.go new file mode 100644 index 000000000..aaa0a325c --- /dev/null +++ b/waved/tree_signature_broker_test.go @@ -0,0 +1,336 @@ +package waved + +import ( + "bytes" + "context" + "testing" + "time" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" + "github.com/google/uuid" + "github.com/lightninglabs/wavelength/lib/tree" + "github.com/lightninglabs/wavelength/round" + "github.com/lightninglabs/wavelength/waverpc" + "github.com/stretchr/testify/require" +) + +func treeBrokerTestKey(t *testing.T) *btcec.PublicKey { + t.Helper() + + priv, err := btcec.NewPrivateKey() + require.NoError(t, err) + + return priv.PubKey() +} + +// treeBrokerTestRequest builds a nonce-round session request for the broker. +func treeBrokerTestRequest(t *testing.T) round.TreeSigningSessionRequest { + t.Helper() + + cosigner := treeBrokerTestKey(t) + operator := treeBrokerTestKey(t) + + var sessionID [32]byte + sessionID[0] = 0x09 + + return round.TreeSigningSessionRequest{ + RoundID: round.RoundID(uuid.New()), + CosignerKey: cosigner, + SessionID: sessionID, + Cosigners: []*btcec.PublicKey{ + cosigner, + operator, + }, + SweepTapscriptRoot: []byte{ + 0x01, + 0x02, + 0x03, + }, + } +} + +// serializedPartialSig returns valid partial-signature bytes for submission. +func serializedPartialSig(t *testing.T, v uint32) []byte { + t.Helper() + + sig := &musig2.PartialSignature{S: new(btcec.ModNScalar)} + sig.S.SetInt(v) + + var buf bytes.Buffer + require.NoError(t, sig.Encode(&buf)) + + return buf.Bytes() +} + +// TestTreeSignatureBrokerNonceRoundTrip drives the broker exactly as the round +// FSM's proxy signer does: FetchTreeNonce blocks, the external party sees the +// request via list, submits a nonce, and the blocked fetch returns it. +func TestTreeSignatureBrokerNonceRoundTrip(t *testing.T) { + t.Parallel() + + b := newTreeSignatureBroker() + req := treeBrokerTestRequest(t) + + var wantNonce tree.Musig2PubNonce + wantNonce[0] = 0x5a + wantNonce[1] = 0xa5 + + type result struct { + nonce tree.Musig2PubNonce + err error + } + done := make(chan result, 1) + go func() { + nonce, err := b.FetchTreeNonce(context.Background(), req) + done <- result{nonce: nonce, err: err} + }() + + // The external party polls until the request appears, verifies the + // transcript, and submits the nonce. + var pending *waverpc.PendingTreeSigningRequest + require.Eventually(t, func() bool { + reqs, _ := b.list(0, 0) + if len(reqs) != 1 { + return false + } + pending = reqs[0] + + return true + }, 2*time.Second, 5*time.Millisecond) + + require.Equal( + t, waverpc.TreeSigningRound_TREE_SIGNING_ROUND_NONCE, + pending.GetRound(), + ) + require.Equal( + t, req.CosignerKey.SerializeCompressed(), + pending.GetCosignerPubkey(), + ) + require.Equal(t, req.SessionID[:], pending.GetSessionId()) + require.Len(t, pending.GetCosigners(), 2) + require.Equal( + t, req.SweepTapscriptRoot, pending.GetSweepTapscriptRoot(), + ) + + require.NoError( + t, + b.submit( + pending.GetRequestId(), + waverpc.TreeSigningRound_TREE_SIGNING_ROUND_NONCE, + wantNonce[:], nil, + ), + ) + + got := <-done + require.NoError(t, got.err) + require.Equal(t, wantNonce, got.nonce) + + // The answered request is no longer listed. + reqs, _ := b.list(0, 0) + require.Empty(t, reqs) +} + +// TestTreeSignatureBrokerPartialSigRoundTrip drives the round-two path: the +// partial-sig request carries the sighash and aggregate nonce, and a submitted +// partial signature unblocks the fetch. +func TestTreeSignatureBrokerPartialSigRoundTrip(t *testing.T) { + t.Parallel() + + b := newTreeSignatureBroker() + req := treeBrokerTestRequest(t) + req.SigHash[0] = 0x77 + req.AggNonce[0] = 0xcd + + wantSigBytes := serializedPartialSig(t, 99) + + type result struct { + sig *musig2.PartialSignature + err error + } + done := make(chan result, 1) + go func() { + sig, err := b.FetchTreePartialSig(context.Background(), req) + done <- result{sig: sig, err: err} + }() + + var pending *waverpc.PendingTreeSigningRequest + require.Eventually(t, func() bool { + reqs, _ := b.list(0, 0) + if len(reqs) != 1 { + return false + } + pending = reqs[0] + + return true + }, 2*time.Second, 5*time.Millisecond) + + require.Equal( + t, waverpc.TreeSigningRound_TREE_SIGNING_ROUND_PARTIAL_SIG, + pending.GetRound(), + ) + require.Equal(t, req.SigHash[:], pending.GetSighash()) + require.Equal(t, req.AggNonce[:], pending.GetAggregateNonce()) + + require.NoError( + t, + b.submit( + pending.GetRequestId(), + waverpc.TreeSigningRound_TREE_SIGNING_ROUND_PARTIAL_SIG, + nil, wantSigBytes, + ), + ) + + got := <-done + require.NoError(t, got.err) + require.NotNil(t, got.sig) + + var gotBuf bytes.Buffer + require.NoError(t, got.sig.Encode(&gotBuf)) + require.Equal(t, wantSigBytes, gotBuf.Bytes()) +} + +// TestTreeSignatureBrokerDistinctRoundIDs verifies the nonce and partial-sig +// requests for one session hash to distinct request ids, so the two rounds do +// not collide in the broker. +func TestTreeSignatureBrokerDistinctRoundIDs(t *testing.T) { + t.Parallel() + + req := treeBrokerTestRequest(t) + + nonceReq, err := pendingTreeSigningRequest( + req, waverpc.TreeSigningRound_TREE_SIGNING_ROUND_NONCE, + ) + require.NoError(t, err) + + req.SigHash[0] = 0x01 + req.AggNonce[0] = 0x02 + partialReq, err := pendingTreeSigningRequest( + req, waverpc.TreeSigningRound_TREE_SIGNING_ROUND_PARTIAL_SIG, + ) + require.NoError(t, err) + + require.NotEqual(t, nonceReq.GetRequestId(), partialReq.GetRequestId()) +} + +// TestTreeSignatureBrokerSubmitErrors covers the submit rejection paths. +func TestTreeSignatureBrokerSubmitErrors(t *testing.T) { + t.Parallel() + + b := newTreeSignatureBroker() + + // Unknown request id. + err := b.submit( + []byte{0xde, 0xad}, + waverpc.TreeSigningRound_TREE_SIGNING_ROUND_NONCE, + make([]byte, musig2.PubNonceSize), nil, + ) + require.ErrorContains(t, err, "not found") + + // Empty request id. + err = b.submit( + nil, waverpc.TreeSigningRound_TREE_SIGNING_ROUND_NONCE, + make([]byte, musig2.PubNonceSize), nil, + ) + require.ErrorContains(t, err, "request_id is required") + + // Park a nonce request, then submit with the wrong round and a bad + // nonce length. + req := treeBrokerTestRequest(t) + go func() { + _, _ = b.FetchTreeNonce(context.Background(), req) + }() + + var pending *waverpc.PendingTreeSigningRequest + require.Eventually(t, func() bool { + reqs, _ := b.list(0, 0) + if len(reqs) != 1 { + return false + } + pending = reqs[0] + + return true + }, 2*time.Second, 5*time.Millisecond) + + err = b.submit( + pending.GetRequestId(), + waverpc.TreeSigningRound_TREE_SIGNING_ROUND_PARTIAL_SIG, nil, + serializedPartialSig(t, 1), + ) + require.ErrorContains(t, err, "round mismatch") + + err = b.submit( + pending.GetRequestId(), + waverpc.TreeSigningRound_TREE_SIGNING_ROUND_NONCE, []byte{0x00}, + nil, + ) + require.ErrorContains(t, err, "public_nonce must be") +} + +// TestTreeSignatureBrokerTimeout verifies a fetch fails when the external party +// never answers within the wait window. +func TestTreeSignatureBrokerTimeout(t *testing.T) { + t.Parallel() + + b := newTreeSignatureBroker() + b.waitTimeout = 50 * time.Millisecond + + _, err := b.FetchTreeNonce( + context.Background(), treeBrokerTestRequest(t), + ) + require.Error(t, err) +} + +// TestTreeSignatureBrokerIdempotentSubmit verifies resubmitting identical +// material is accepted while conflicting material is rejected. +func TestTreeSignatureBrokerIdempotentSubmit(t *testing.T) { + t.Parallel() + + b := newTreeSignatureBroker() + req := treeBrokerTestRequest(t) + + go func() { + _, _ = b.FetchTreeNonce(context.Background(), req) + }() + + var pending *waverpc.PendingTreeSigningRequest + require.Eventually(t, func() bool { + reqs, _ := b.list(0, 0) + if len(reqs) != 1 { + return false + } + pending = reqs[0] + + return true + }, 2*time.Second, 5*time.Millisecond) + + nonce := make([]byte, musig2.PubNonceSize) + nonce[0] = 0x11 + require.NoError( + t, + b.submit( + pending.GetRequestId(), + waverpc.TreeSigningRound_TREE_SIGNING_ROUND_NONCE, + nonce, nil, + ), + ) + + // Identical resubmit is accepted. + require.NoError( + t, + b.submit( + pending.GetRequestId(), + waverpc.TreeSigningRound_TREE_SIGNING_ROUND_NONCE, + nonce, nil, + ), + ) + + // Conflicting resubmit is rejected. + other := make([]byte, musig2.PubNonceSize) + other[0] = 0x22 + err := b.submit( + pending.GetRequestId(), + waverpc.TreeSigningRound_TREE_SIGNING_ROUND_NONCE, other, nil, + ) + require.ErrorContains(t, err, "already answered") +} diff --git a/waverpc/daemon.pb.go b/waverpc/daemon.pb.go index 035ab4ca7..f9d2af046 100644 --- a/waverpc/daemon.pb.go +++ b/waverpc/daemon.pb.go @@ -338,6 +338,64 @@ func (ForfeitSigningRoute) EnumDescriptor() ([]byte, []int) { return file_daemon_proto_rawDescGZIP(), []int{3} } +// TreeSigningRound distinguishes the two rounds of the MuSig2 tree-signing +// ceremony that an external cosigner participates in. +type TreeSigningRound int32 + +const ( + // TREE_SIGNING_ROUND_UNSPECIFIED is the zero value and is never emitted. + TreeSigningRound_TREE_SIGNING_ROUND_UNSPECIFIED TreeSigningRound = 0 + // TREE_SIGNING_ROUND_NONCE asks the external party for a fresh public + // nonce for one transaction session (round one). + TreeSigningRound_TREE_SIGNING_ROUND_NONCE TreeSigningRound = 1 + // TREE_SIGNING_ROUND_PARTIAL_SIG asks the external party for a partial + // signature over the request's sighash under its aggregate_nonce (round + // two). The party must sign under the exact secret nonce it committed to + // in the matching NONCE request for the same session_id. + TreeSigningRound_TREE_SIGNING_ROUND_PARTIAL_SIG TreeSigningRound = 2 +) + +// Enum value maps for TreeSigningRound. +var ( + TreeSigningRound_name = map[int32]string{ + 0: "TREE_SIGNING_ROUND_UNSPECIFIED", + 1: "TREE_SIGNING_ROUND_NONCE", + 2: "TREE_SIGNING_ROUND_PARTIAL_SIG", + } + TreeSigningRound_value = map[string]int32{ + "TREE_SIGNING_ROUND_UNSPECIFIED": 0, + "TREE_SIGNING_ROUND_NONCE": 1, + "TREE_SIGNING_ROUND_PARTIAL_SIG": 2, + } +) + +func (x TreeSigningRound) Enum() *TreeSigningRound { + p := new(TreeSigningRound) + *p = x + return p +} + +func (x TreeSigningRound) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (TreeSigningRound) Descriptor() protoreflect.EnumDescriptor { + return file_daemon_proto_enumTypes[4].Descriptor() +} + +func (TreeSigningRound) Type() protoreflect.EnumType { + return &file_daemon_proto_enumTypes[4] +} + +func (x TreeSigningRound) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use TreeSigningRound.Descriptor instead. +func (TreeSigningRound) EnumDescriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{4} +} + // RoundState represents the lifecycle state of a client's round FSM. type RoundState int32 @@ -443,11 +501,11 @@ func (x RoundState) String() string { } func (RoundState) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[4].Descriptor() + return file_daemon_proto_enumTypes[5].Descriptor() } func (RoundState) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[4] + return &file_daemon_proto_enumTypes[5] } func (x RoundState) Number() protoreflect.EnumNumber { @@ -456,7 +514,7 @@ func (x RoundState) Number() protoreflect.EnumNumber { // Deprecated: Use RoundState.Descriptor instead. func (RoundState) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{4} + return file_daemon_proto_rawDescGZIP(), []int{5} } type OORSessionDirection int32 @@ -492,11 +550,11 @@ func (x OORSessionDirection) String() string { } func (OORSessionDirection) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[5].Descriptor() + return file_daemon_proto_enumTypes[6].Descriptor() } func (OORSessionDirection) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[5] + return &file_daemon_proto_enumTypes[6] } func (x OORSessionDirection) Number() protoreflect.EnumNumber { @@ -505,7 +563,7 @@ func (x OORSessionDirection) Number() protoreflect.EnumNumber { // Deprecated: Use OORSessionDirection.Descriptor instead. func (OORSessionDirection) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{5} + return file_daemon_proto_rawDescGZIP(), []int{6} } type OORSessionStatus int32 @@ -544,11 +602,11 @@ func (x OORSessionStatus) String() string { } func (OORSessionStatus) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[6].Descriptor() + return file_daemon_proto_enumTypes[7].Descriptor() } func (OORSessionStatus) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[6] + return &file_daemon_proto_enumTypes[7] } func (x OORSessionStatus) Number() protoreflect.EnumNumber { @@ -557,7 +615,7 @@ func (x OORSessionStatus) Number() protoreflect.EnumNumber { // Deprecated: Use OORSessionStatus.Descriptor instead. func (OORSessionStatus) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{6} + return file_daemon_proto_rawDescGZIP(), []int{7} } // UnrollJobStatus represents the high-level phase of an unroll job. @@ -618,11 +676,11 @@ func (x UnrollJobStatus) String() string { } func (UnrollJobStatus) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[7].Descriptor() + return file_daemon_proto_enumTypes[8].Descriptor() } func (UnrollJobStatus) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[7] + return &file_daemon_proto_enumTypes[8] } func (x UnrollJobStatus) Number() protoreflect.EnumNumber { @@ -631,7 +689,7 @@ func (x UnrollJobStatus) Number() protoreflect.EnumNumber { // Deprecated: Use UnrollJobStatus.Descriptor instead. func (UnrollJobStatus) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{7} + return file_daemon_proto_rawDescGZIP(), []int{8} } // VHTLCRecoveryDirection records which side owns a recovery job. @@ -681,11 +739,11 @@ func (x VHTLCRecoveryDirection) String() string { } func (VHTLCRecoveryDirection) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[8].Descriptor() + return file_daemon_proto_enumTypes[9].Descriptor() } func (VHTLCRecoveryDirection) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[8] + return &file_daemon_proto_enumTypes[9] } func (x VHTLCRecoveryDirection) Number() protoreflect.EnumNumber { @@ -694,7 +752,7 @@ func (x VHTLCRecoveryDirection) Number() protoreflect.EnumNumber { // Deprecated: Use VHTLCRecoveryDirection.Descriptor instead. func (VHTLCRecoveryDirection) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{8} + return file_daemon_proto_rawDescGZIP(), []int{9} } // VHTLCRecoveryAction selects the unilateral vHTLC leaf to execute. @@ -735,11 +793,11 @@ func (x VHTLCRecoveryAction) String() string { } func (VHTLCRecoveryAction) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[9].Descriptor() + return file_daemon_proto_enumTypes[10].Descriptor() } func (VHTLCRecoveryAction) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[9] + return &file_daemon_proto_enumTypes[10] } func (x VHTLCRecoveryAction) Number() protoreflect.EnumNumber { @@ -748,7 +806,7 @@ func (x VHTLCRecoveryAction) Number() protoreflect.EnumNumber { // Deprecated: Use VHTLCRecoveryAction.Descriptor instead. func (VHTLCRecoveryAction) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{9} + return file_daemon_proto_rawDescGZIP(), []int{10} } // VHTLCRecoveryState mirrors the durable vhtlc_recovery_jobs state column. The @@ -816,11 +874,11 @@ func (x VHTLCRecoveryState) String() string { } func (VHTLCRecoveryState) Descriptor() protoreflect.EnumDescriptor { - return file_daemon_proto_enumTypes[10].Descriptor() + return file_daemon_proto_enumTypes[11].Descriptor() } func (VHTLCRecoveryState) Type() protoreflect.EnumType { - return &file_daemon_proto_enumTypes[10] + return &file_daemon_proto_enumTypes[11] } func (x VHTLCRecoveryState) Number() protoreflect.EnumNumber { @@ -829,7 +887,7 @@ func (x VHTLCRecoveryState) Number() protoreflect.EnumNumber { // Deprecated: Use VHTLCRecoveryState.Descriptor instead. func (VHTLCRecoveryState) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{10} + return file_daemon_proto_rawDescGZIP(), []int{11} } type GetInfoRequest struct { @@ -5573,35 +5631,58 @@ func (*SubmitForfeitParticipantSignaturesResponse) Descriptor() ([]byte, []int) return file_daemon_proto_rawDescGZIP(), []int{63} } -// LeaveDestination describes where a single leave output should land. -// Unlike Output (used for VTXO sends), leave destinations are on-chain -// and carry no VTXO-shape constraints: any standard address or -// recognised raw pkScript is acceptable. -type LeaveDestination struct { +// PendingTreeSigningRequest is one blocking MuSig2 tree-signing request for an +// external cosigner key. It carries everything the external party needs to +// independently produce the requested nonce or partial signature. +type PendingTreeSigningRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - // Types that are valid to be assigned to Target: - // - // *LeaveDestination_Address - // *LeaveDestination_PkScript - Target isLeaveDestination_Target `protobuf_oneof:"target"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // request_id is the stable digest of this request. Echo it in + // SubmitTreeSignatures so the daemon can wake the blocked round FSM. + RequestId []byte `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + // sequence is the monotonic cursor for paging the pending request stream. + Sequence uint64 `protobuf:"varint,2,opt,name=sequence,proto3" json:"sequence,omitempty"` + // round selects which round of the ceremony this request is for. + Round TreeSigningRound `protobuf:"varint,3,opt,name=round,proto3,enum=waverpc.TreeSigningRound" json:"round,omitempty"` + // round_id is the 16-byte round identifier this signing material belongs + // to. + RoundId []byte `protobuf:"bytes,4,opt,name=round_id,json=roundId,proto3" json:"round_id,omitempty"` + // cosigner_pubkey is the 33-byte compressed public key of the external + // cosigner this material is requested for. + CosignerPubkey []byte `protobuf:"bytes,5,opt,name=cosigner_pubkey,json=cosignerPubkey,proto3" json:"cosigner_pubkey,omitempty"` + // session_id is the 32-byte per-transaction MuSig2 session identifier. It + // is stable across the NONCE and PARTIAL_SIG rounds for one transaction. + SessionId []byte `protobuf:"bytes,6,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + // cosigners is the full ordered MuSig2 participant set (the external + // cosigner plus the operator), each a 33-byte compressed public key. + Cosigners [][]byte `protobuf:"bytes,7,rep,name=cosigners,proto3" json:"cosigners,omitempty"` + // sweep_tapscript_root is the taproot tweak applied to the aggregate key + // (the VTXO tree's sweep tapscript root). It changes the aggregate key and + // therefore the signature. + SweepTapscriptRoot []byte `protobuf:"bytes,8,opt,name=sweep_tapscript_root,json=sweepTapscriptRoot,proto3" json:"sweep_tapscript_root,omitempty"` + // sighash is the 32-byte taproot sighash the partial signature must cover. + // Set only on PARTIAL_SIG requests. + Sighash []byte `protobuf:"bytes,9,opt,name=sighash,proto3" json:"sighash,omitempty"` + // aggregate_nonce is the 66-byte operator-aggregated combined nonce for + // this session. Set only on PARTIAL_SIG requests. + AggregateNonce []byte `protobuf:"bytes,10,opt,name=aggregate_nonce,json=aggregateNonce,proto3" json:"aggregate_nonce,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *LeaveDestination) Reset() { - *x = LeaveDestination{} +func (x *PendingTreeSigningRequest) Reset() { + *x = PendingTreeSigningRequest{} mi := &file_daemon_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *LeaveDestination) String() string { +func (x *PendingTreeSigningRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*LeaveDestination) ProtoMessage() {} +func (*PendingTreeSigningRequest) ProtoMessage() {} -func (x *LeaveDestination) ProtoReflect() protoreflect.Message { +func (x *PendingTreeSigningRequest) ProtoReflect() protoreflect.Message { mi := &file_daemon_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -5613,101 +5694,106 @@ func (x *LeaveDestination) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use LeaveDestination.ProtoReflect.Descriptor instead. -func (*LeaveDestination) Descriptor() ([]byte, []int) { +// Deprecated: Use PendingTreeSigningRequest.ProtoReflect.Descriptor instead. +func (*PendingTreeSigningRequest) Descriptor() ([]byte, []int) { return file_daemon_proto_rawDescGZIP(), []int{64} } -func (x *LeaveDestination) GetTarget() isLeaveDestination_Target { +func (x *PendingTreeSigningRequest) GetRequestId() []byte { if x != nil { - return x.Target + return x.RequestId } return nil } -func (x *LeaveDestination) GetAddress() string { +func (x *PendingTreeSigningRequest) GetSequence() uint64 { if x != nil { - if x, ok := x.Target.(*LeaveDestination_Address); ok { - return x.Address - } + return x.Sequence } - return "" + return 0 } -func (x *LeaveDestination) GetPkScript() []byte { +func (x *PendingTreeSigningRequest) GetRound() TreeSigningRound { if x != nil { - if x, ok := x.Target.(*LeaveDestination_PkScript); ok { - return x.PkScript - } + return x.Round + } + return TreeSigningRound_TREE_SIGNING_ROUND_UNSPECIFIED +} + +func (x *PendingTreeSigningRequest) GetRoundId() []byte { + if x != nil { + return x.RoundId } return nil } -type isLeaveDestination_Target interface { - isLeaveDestination_Target() +func (x *PendingTreeSigningRequest) GetCosignerPubkey() []byte { + if x != nil { + return x.CosignerPubkey + } + return nil } -type LeaveDestination_Address struct { - // address is the bech32m/base58 on-chain recipient. The daemon - // decodes it via btcutil.DecodeAddress using its configured - // chain params, so cross-network addresses are rejected. - Address string `protobuf:"bytes,1,opt,name=address,proto3,oneof"` +func (x *PendingTreeSigningRequest) GetSessionId() []byte { + if x != nil { + return x.SessionId + } + return nil } -type LeaveDestination_PkScript struct { - // pk_script is the raw output script to pay. Useful when the - // caller has already resolved the script (custom policies, - // OP_RETURN exits, etc.) and does not want address re-encoding. - // The daemon caps the script at txscript.MaxScriptSize, rejects - // the BIP 431 P2A anchor pattern, and whitelists standard - // classes (P2PKH, P2SH, P2WPKH, P2WSH, P2TR, P2PK, multisig, - // OP_RETURN). Network binding is the caller's responsibility on - // this branch — pkScripts are network-agnostic, so the daemon - // does not (and cannot) re-bind them to its chain params. - PkScript []byte `protobuf:"bytes,2,opt,name=pk_script,json=pkScript,proto3,oneof"` +func (x *PendingTreeSigningRequest) GetCosigners() [][]byte { + if x != nil { + return x.Cosigners + } + return nil } -func (*LeaveDestination_Address) isLeaveDestination_Target() {} +func (x *PendingTreeSigningRequest) GetSweepTapscriptRoot() []byte { + if x != nil { + return x.SweepTapscriptRoot + } + return nil +} -func (*LeaveDestination_PkScript) isLeaveDestination_Target() {} +func (x *PendingTreeSigningRequest) GetSighash() []byte { + if x != nil { + return x.Sighash + } + return nil +} -type LeaveVTXOsRequest struct { +func (x *PendingTreeSigningRequest) GetAggregateNonce() []byte { + if x != nil { + return x.AggregateNonce + } + return nil +} + +type ListPendingTreeSigningRequestsRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - // Types that are valid to be assigned to Selection: - // - // *LeaveVTXOsRequest_Outpoints - // *LeaveVTXOsRequest_All - Selection isLeaveVTXOsRequest_Selection `protobuf_oneof:"selection"` - // default_destination applies to every selected outpoint that is - // not overridden in destinations. Required whenever selection=all, - // or whenever any selected outpoint is not present in the - // destinations map. - DefaultDestination *LeaveDestination `protobuf:"bytes,3,opt,name=default_destination,json=defaultDestination,proto3" json:"default_destination,omitempty"` - // destinations overrides the default destination on a per-outpoint - // basis. The key is the outpoint in "txid:index" format. Only - // honored when selection=outpoints; the RPC rejects non-empty - // overrides combined with selection=all. - Destinations map[string]*LeaveDestination `protobuf:"bytes,4,rep,name=destinations,proto3" json:"destinations,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - // dry_run validates the request without queuing the leave. - DryRun bool `protobuf:"varint,5,opt,name=dry_run,json=dryRun,proto3" json:"dry_run,omitempty"` + // after_sequence returns requests with a larger sequence. Zero starts at + // the beginning of the daemon-local pending request stream. + AfterSequence uint64 `protobuf:"varint,1,opt,name=after_sequence,json=afterSequence,proto3" json:"after_sequence,omitempty"` + // limit caps the number of returned requests. Zero uses a daemon default. + Limit uint32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *LeaveVTXOsRequest) Reset() { - *x = LeaveVTXOsRequest{} +func (x *ListPendingTreeSigningRequestsRequest) Reset() { + *x = ListPendingTreeSigningRequestsRequest{} mi := &file_daemon_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *LeaveVTXOsRequest) String() string { +func (x *ListPendingTreeSigningRequestsRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*LeaveVTXOsRequest) ProtoMessage() {} +func (*ListPendingTreeSigningRequestsRequest) ProtoMessage() {} -func (x *LeaveVTXOsRequest) ProtoReflect() protoreflect.Message { +func (x *ListPendingTreeSigningRequestsRequest) ProtoReflect() protoreflect.Message { mi := &file_daemon_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -5719,77 +5805,404 @@ func (x *LeaveVTXOsRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use LeaveVTXOsRequest.ProtoReflect.Descriptor instead. -func (*LeaveVTXOsRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use ListPendingTreeSigningRequestsRequest.ProtoReflect.Descriptor instead. +func (*ListPendingTreeSigningRequestsRequest) Descriptor() ([]byte, []int) { return file_daemon_proto_rawDescGZIP(), []int{65} } -func (x *LeaveVTXOsRequest) GetSelection() isLeaveVTXOsRequest_Selection { +func (x *ListPendingTreeSigningRequestsRequest) GetAfterSequence() uint64 { if x != nil { - return x.Selection + return x.AfterSequence } - return nil + return 0 } -func (x *LeaveVTXOsRequest) GetOutpoints() *OutpointSelection { +func (x *ListPendingTreeSigningRequestsRequest) GetLimit() uint32 { if x != nil { - if x, ok := x.Selection.(*LeaveVTXOsRequest_Outpoints); ok { - return x.Outpoints - } + return x.Limit } - return nil + return 0 } -func (x *LeaveVTXOsRequest) GetAll() bool { +type ListPendingTreeSigningRequestsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Requests []*PendingTreeSigningRequest `protobuf:"bytes,1,rep,name=requests,proto3" json:"requests,omitempty"` + NextSequence uint64 `protobuf:"varint,2,opt,name=next_sequence,json=nextSequence,proto3" json:"next_sequence,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListPendingTreeSigningRequestsResponse) Reset() { + *x = ListPendingTreeSigningRequestsResponse{} + mi := &file_daemon_proto_msgTypes[66] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListPendingTreeSigningRequestsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListPendingTreeSigningRequestsResponse) ProtoMessage() {} + +func (x *ListPendingTreeSigningRequestsResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[66] if x != nil { - if x, ok := x.Selection.(*LeaveVTXOsRequest_All); ok { - return x.All + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) } + return ms } - return false + return mi.MessageOf(x) } -func (x *LeaveVTXOsRequest) GetDefaultDestination() *LeaveDestination { - if x != nil { - return x.DefaultDestination - } - return nil +// Deprecated: Use ListPendingTreeSigningRequestsResponse.ProtoReflect.Descriptor instead. +func (*ListPendingTreeSigningRequestsResponse) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{66} } -func (x *LeaveVTXOsRequest) GetDestinations() map[string]*LeaveDestination { +func (x *ListPendingTreeSigningRequestsResponse) GetRequests() []*PendingTreeSigningRequest { if x != nil { - return x.Destinations + return x.Requests } return nil } -func (x *LeaveVTXOsRequest) GetDryRun() bool { +func (x *ListPendingTreeSigningRequestsResponse) GetNextSequence() uint64 { if x != nil { - return x.DryRun + return x.NextSequence } - return false + return 0 } -type isLeaveVTXOsRequest_Selection interface { - isLeaveVTXOsRequest_Selection() +type SubmitTreeSignaturesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // request_id identifies the pending request being answered. It must match + // a request_id previously returned by ListPendingTreeSigningRequests. + RequestId []byte `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + // round must match the listed request's round. + Round TreeSigningRound `protobuf:"varint,2,opt,name=round,proto3,enum=waverpc.TreeSigningRound" json:"round,omitempty"` + // public_nonce is the 66-byte MuSig2 public nonce. Set on NONCE requests. + PublicNonce []byte `protobuf:"bytes,3,opt,name=public_nonce,json=publicNonce,proto3" json:"public_nonce,omitempty"` + // partial_signature is the serialized MuSig2 partial signature. Set on + // PARTIAL_SIG requests. + PartialSignature []byte `protobuf:"bytes,4,opt,name=partial_signature,json=partialSignature,proto3" json:"partial_signature,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -type LeaveVTXOsRequest_Outpoints struct { - // outpoints lists specific VTXOs to leave, in "txid:index" - // format. - Outpoints *OutpointSelection `protobuf:"bytes,1,opt,name=outpoints,proto3,oneof"` +func (x *SubmitTreeSignaturesRequest) Reset() { + *x = SubmitTreeSignaturesRequest{} + mi := &file_daemon_proto_msgTypes[67] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -type LeaveVTXOsRequest_All struct { - // all leaves every live VTXO when true. Per-outpoint overrides - // are rejected under this selection because the daemon does - // not know the outpoint set ahead of time. - All bool `protobuf:"varint,2,opt,name=all,proto3,oneof"` +func (x *SubmitTreeSignaturesRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (*LeaveVTXOsRequest_Outpoints) isLeaveVTXOsRequest_Selection() {} - -func (*LeaveVTXOsRequest_All) isLeaveVTXOsRequest_Selection() {} +func (*SubmitTreeSignaturesRequest) ProtoMessage() {} + +func (x *SubmitTreeSignaturesRequest) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[67] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitTreeSignaturesRequest.ProtoReflect.Descriptor instead. +func (*SubmitTreeSignaturesRequest) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{67} +} + +func (x *SubmitTreeSignaturesRequest) GetRequestId() []byte { + if x != nil { + return x.RequestId + } + return nil +} + +func (x *SubmitTreeSignaturesRequest) GetRound() TreeSigningRound { + if x != nil { + return x.Round + } + return TreeSigningRound_TREE_SIGNING_ROUND_UNSPECIFIED +} + +func (x *SubmitTreeSignaturesRequest) GetPublicNonce() []byte { + if x != nil { + return x.PublicNonce + } + return nil +} + +func (x *SubmitTreeSignaturesRequest) GetPartialSignature() []byte { + if x != nil { + return x.PartialSignature + } + return nil +} + +type SubmitTreeSignaturesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubmitTreeSignaturesResponse) Reset() { + *x = SubmitTreeSignaturesResponse{} + mi := &file_daemon_proto_msgTypes[68] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitTreeSignaturesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitTreeSignaturesResponse) ProtoMessage() {} + +func (x *SubmitTreeSignaturesResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[68] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitTreeSignaturesResponse.ProtoReflect.Descriptor instead. +func (*SubmitTreeSignaturesResponse) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{68} +} + +// LeaveDestination describes where a single leave output should land. +// Unlike Output (used for VTXO sends), leave destinations are on-chain +// and carry no VTXO-shape constraints: any standard address or +// recognised raw pkScript is acceptable. +type LeaveDestination struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Target: + // + // *LeaveDestination_Address + // *LeaveDestination_PkScript + Target isLeaveDestination_Target `protobuf_oneof:"target"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LeaveDestination) Reset() { + *x = LeaveDestination{} + mi := &file_daemon_proto_msgTypes[69] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LeaveDestination) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LeaveDestination) ProtoMessage() {} + +func (x *LeaveDestination) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[69] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LeaveDestination.ProtoReflect.Descriptor instead. +func (*LeaveDestination) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{69} +} + +func (x *LeaveDestination) GetTarget() isLeaveDestination_Target { + if x != nil { + return x.Target + } + return nil +} + +func (x *LeaveDestination) GetAddress() string { + if x != nil { + if x, ok := x.Target.(*LeaveDestination_Address); ok { + return x.Address + } + } + return "" +} + +func (x *LeaveDestination) GetPkScript() []byte { + if x != nil { + if x, ok := x.Target.(*LeaveDestination_PkScript); ok { + return x.PkScript + } + } + return nil +} + +type isLeaveDestination_Target interface { + isLeaveDestination_Target() +} + +type LeaveDestination_Address struct { + // address is the bech32m/base58 on-chain recipient. The daemon + // decodes it via btcutil.DecodeAddress using its configured + // chain params, so cross-network addresses are rejected. + Address string `protobuf:"bytes,1,opt,name=address,proto3,oneof"` +} + +type LeaveDestination_PkScript struct { + // pk_script is the raw output script to pay. Useful when the + // caller has already resolved the script (custom policies, + // OP_RETURN exits, etc.) and does not want address re-encoding. + // The daemon caps the script at txscript.MaxScriptSize, rejects + // the BIP 431 P2A anchor pattern, and whitelists standard + // classes (P2PKH, P2SH, P2WPKH, P2WSH, P2TR, P2PK, multisig, + // OP_RETURN). Network binding is the caller's responsibility on + // this branch — pkScripts are network-agnostic, so the daemon + // does not (and cannot) re-bind them to its chain params. + PkScript []byte `protobuf:"bytes,2,opt,name=pk_script,json=pkScript,proto3,oneof"` +} + +func (*LeaveDestination_Address) isLeaveDestination_Target() {} + +func (*LeaveDestination_PkScript) isLeaveDestination_Target() {} + +type LeaveVTXOsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Selection: + // + // *LeaveVTXOsRequest_Outpoints + // *LeaveVTXOsRequest_All + Selection isLeaveVTXOsRequest_Selection `protobuf_oneof:"selection"` + // default_destination applies to every selected outpoint that is + // not overridden in destinations. Required whenever selection=all, + // or whenever any selected outpoint is not present in the + // destinations map. + DefaultDestination *LeaveDestination `protobuf:"bytes,3,opt,name=default_destination,json=defaultDestination,proto3" json:"default_destination,omitempty"` + // destinations overrides the default destination on a per-outpoint + // basis. The key is the outpoint in "txid:index" format. Only + // honored when selection=outpoints; the RPC rejects non-empty + // overrides combined with selection=all. + Destinations map[string]*LeaveDestination `protobuf:"bytes,4,rep,name=destinations,proto3" json:"destinations,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // dry_run validates the request without queuing the leave. + DryRun bool `protobuf:"varint,5,opt,name=dry_run,json=dryRun,proto3" json:"dry_run,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LeaveVTXOsRequest) Reset() { + *x = LeaveVTXOsRequest{} + mi := &file_daemon_proto_msgTypes[70] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LeaveVTXOsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LeaveVTXOsRequest) ProtoMessage() {} + +func (x *LeaveVTXOsRequest) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[70] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LeaveVTXOsRequest.ProtoReflect.Descriptor instead. +func (*LeaveVTXOsRequest) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{70} +} + +func (x *LeaveVTXOsRequest) GetSelection() isLeaveVTXOsRequest_Selection { + if x != nil { + return x.Selection + } + return nil +} + +func (x *LeaveVTXOsRequest) GetOutpoints() *OutpointSelection { + if x != nil { + if x, ok := x.Selection.(*LeaveVTXOsRequest_Outpoints); ok { + return x.Outpoints + } + } + return nil +} + +func (x *LeaveVTXOsRequest) GetAll() bool { + if x != nil { + if x, ok := x.Selection.(*LeaveVTXOsRequest_All); ok { + return x.All + } + } + return false +} + +func (x *LeaveVTXOsRequest) GetDefaultDestination() *LeaveDestination { + if x != nil { + return x.DefaultDestination + } + return nil +} + +func (x *LeaveVTXOsRequest) GetDestinations() map[string]*LeaveDestination { + if x != nil { + return x.Destinations + } + return nil +} + +func (x *LeaveVTXOsRequest) GetDryRun() bool { + if x != nil { + return x.DryRun + } + return false +} + +type isLeaveVTXOsRequest_Selection interface { + isLeaveVTXOsRequest_Selection() +} + +type LeaveVTXOsRequest_Outpoints struct { + // outpoints lists specific VTXOs to leave, in "txid:index" + // format. + Outpoints *OutpointSelection `protobuf:"bytes,1,opt,name=outpoints,proto3,oneof"` +} + +type LeaveVTXOsRequest_All struct { + // all leaves every live VTXO when true. Per-outpoint overrides + // are rejected under this selection because the daemon does + // not know the outpoint set ahead of time. + All bool `protobuf:"varint,2,opt,name=all,proto3,oneof"` +} + +func (*LeaveVTXOsRequest_Outpoints) isLeaveVTXOsRequest_Selection() {} + +func (*LeaveVTXOsRequest_All) isLeaveVTXOsRequest_Selection() {} type LeaveVTXOsResponse struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -5804,7 +6217,7 @@ type LeaveVTXOsResponse struct { func (x *LeaveVTXOsResponse) Reset() { *x = LeaveVTXOsResponse{} - mi := &file_daemon_proto_msgTypes[66] + mi := &file_daemon_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5816,7 +6229,7 @@ func (x *LeaveVTXOsResponse) String() string { func (*LeaveVTXOsResponse) ProtoMessage() {} func (x *LeaveVTXOsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[66] + mi := &file_daemon_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5829,7 +6242,7 @@ func (x *LeaveVTXOsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LeaveVTXOsResponse.ProtoReflect.Descriptor instead. func (*LeaveVTXOsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{66} + return file_daemon_proto_rawDescGZIP(), []int{71} } func (x *LeaveVTXOsResponse) GetQueuedOutpoints() []string { @@ -5867,7 +6280,7 @@ type SendOnChainRequest struct { func (x *SendOnChainRequest) Reset() { *x = SendOnChainRequest{} - mi := &file_daemon_proto_msgTypes[67] + mi := &file_daemon_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5879,7 +6292,7 @@ func (x *SendOnChainRequest) String() string { func (*SendOnChainRequest) ProtoMessage() {} func (x *SendOnChainRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[67] + mi := &file_daemon_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5892,7 +6305,7 @@ func (x *SendOnChainRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SendOnChainRequest.ProtoReflect.Descriptor instead. func (*SendOnChainRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{67} + return file_daemon_proto_rawDescGZIP(), []int{72} } func (x *SendOnChainRequest) GetDestination() *LeaveDestination { @@ -6000,7 +6413,7 @@ type SendOnChainResponse struct { func (x *SendOnChainResponse) Reset() { *x = SendOnChainResponse{} - mi := &file_daemon_proto_msgTypes[68] + mi := &file_daemon_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6012,7 +6425,7 @@ func (x *SendOnChainResponse) String() string { func (*SendOnChainResponse) ProtoMessage() {} func (x *SendOnChainResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[68] + mi := &file_daemon_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6025,7 +6438,7 @@ func (x *SendOnChainResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SendOnChainResponse.ProtoReflect.Descriptor instead. func (*SendOnChainResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{68} + return file_daemon_proto_rawDescGZIP(), []int{73} } func (x *SendOnChainResponse) GetActualAmountSat() int64 { @@ -6084,14 +6497,29 @@ type BoardRequest struct { // intent anchored to every admitted confirmed outpoint and replays // the Board through the wallet's self-Tell on startup until the // round adopts or the user fires a fresh Board. - NoPersist bool `protobuf:"varint,2,opt,name=no_persist,json=noPersist,proto3" json:"no_persist,omitempty"` + NoPersist bool `protobuf:"varint,2,opt,name=no_persist,json=noPersist,proto3" json:"no_persist,omitempty"` + // vtxo_policy_template optionally pins the arkscript policy for every + // boarded VTXO output produced by this request. When empty, the daemon + // synthesizes the standard 2-of-2 collaborative policy with a freshly + // derived owner key (the legacy behavior). When supplied, the boarded + // outputs adopt this policy verbatim, letting a client board directly + // into a custom-owned VTXO (for example one owned by an external FROST + // aggregate key) without a follow-up refresh. The template must validate + // against the operator's terms, and it is persisted with the board intent + // so restart replay recreates the same custom output. + VtxoPolicyTemplate []byte `protobuf:"bytes,3,opt,name=vtxo_policy_template,json=vtxoPolicyTemplate,proto3" json:"vtxo_policy_template,omitempty"` + // pk_script optionally pins the taproot output script for the boarded + // VTXOs. It is only valid alongside vtxo_policy_template, and when set it + // must match the script derived from that template. Leaving it empty lets + // the daemon derive the script from the template. + PkScript []byte `protobuf:"bytes,4,opt,name=pk_script,json=pkScript,proto3" json:"pk_script,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *BoardRequest) Reset() { *x = BoardRequest{} - mi := &file_daemon_proto_msgTypes[69] + mi := &file_daemon_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6103,7 +6531,7 @@ func (x *BoardRequest) String() string { func (*BoardRequest) ProtoMessage() {} func (x *BoardRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[69] + mi := &file_daemon_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6116,7 +6544,7 @@ func (x *BoardRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BoardRequest.ProtoReflect.Descriptor instead. func (*BoardRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{69} + return file_daemon_proto_rawDescGZIP(), []int{74} } func (x *BoardRequest) GetTargetVtxoCount() uint32 { @@ -6133,6 +6561,20 @@ func (x *BoardRequest) GetNoPersist() bool { return false } +func (x *BoardRequest) GetVtxoPolicyTemplate() []byte { + if x != nil { + return x.VtxoPolicyTemplate + } + return nil +} + +func (x *BoardRequest) GetPkScript() []byte { + if x != nil { + return x.PkScript + } + return nil +} + type BoardResponse struct { state protoimpl.MessageState `protogen:"open.v1"` // status is "registered" on success, "no_boarding_utxos" if @@ -6147,7 +6589,7 @@ type BoardResponse struct { func (x *BoardResponse) Reset() { *x = BoardResponse{} - mi := &file_daemon_proto_msgTypes[70] + mi := &file_daemon_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6159,7 +6601,7 @@ func (x *BoardResponse) String() string { func (*BoardResponse) ProtoMessage() {} func (x *BoardResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[70] + mi := &file_daemon_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6172,7 +6614,7 @@ func (x *BoardResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BoardResponse.ProtoReflect.Descriptor instead. func (*BoardResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{70} + return file_daemon_proto_rawDescGZIP(), []int{75} } func (x *BoardResponse) GetStatus() string { @@ -6197,7 +6639,7 @@ type JoinNextRoundRequest struct { func (x *JoinNextRoundRequest) Reset() { *x = JoinNextRoundRequest{} - mi := &file_daemon_proto_msgTypes[71] + mi := &file_daemon_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6209,7 +6651,7 @@ func (x *JoinNextRoundRequest) String() string { func (*JoinNextRoundRequest) ProtoMessage() {} func (x *JoinNextRoundRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[71] + mi := &file_daemon_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6222,7 +6664,7 @@ func (x *JoinNextRoundRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use JoinNextRoundRequest.ProtoReflect.Descriptor instead. func (*JoinNextRoundRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{71} + return file_daemon_proto_rawDescGZIP(), []int{76} } type JoinNextRoundResponse struct { @@ -6237,7 +6679,7 @@ type JoinNextRoundResponse struct { func (x *JoinNextRoundResponse) Reset() { *x = JoinNextRoundResponse{} - mi := &file_daemon_proto_msgTypes[72] + mi := &file_daemon_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6249,7 +6691,7 @@ func (x *JoinNextRoundResponse) String() string { func (*JoinNextRoundResponse) ProtoMessage() {} func (x *JoinNextRoundResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[72] + mi := &file_daemon_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6262,7 +6704,7 @@ func (x *JoinNextRoundResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use JoinNextRoundResponse.ProtoReflect.Descriptor instead. func (*JoinNextRoundResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{72} + return file_daemon_proto_rawDescGZIP(), []int{77} } func (x *JoinNextRoundResponse) GetStatus() string { @@ -6298,7 +6740,7 @@ type SweepBoardingUTXOsRequest struct { func (x *SweepBoardingUTXOsRequest) Reset() { *x = SweepBoardingUTXOsRequest{} - mi := &file_daemon_proto_msgTypes[73] + mi := &file_daemon_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6310,7 +6752,7 @@ func (x *SweepBoardingUTXOsRequest) String() string { func (*SweepBoardingUTXOsRequest) ProtoMessage() {} func (x *SweepBoardingUTXOsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[73] + mi := &file_daemon_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6323,7 +6765,7 @@ func (x *SweepBoardingUTXOsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SweepBoardingUTXOsRequest.ProtoReflect.Descriptor instead. func (*SweepBoardingUTXOsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{73} + return file_daemon_proto_rawDescGZIP(), []int{78} } func (x *SweepBoardingUTXOsRequest) GetOutpoints() []string { @@ -6376,7 +6818,7 @@ type BoardingSweepOutput struct { func (x *BoardingSweepOutput) Reset() { *x = BoardingSweepOutput{} - mi := &file_daemon_proto_msgTypes[74] + mi := &file_daemon_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6388,7 +6830,7 @@ func (x *BoardingSweepOutput) String() string { func (*BoardingSweepOutput) ProtoMessage() {} func (x *BoardingSweepOutput) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[74] + mi := &file_daemon_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6401,7 +6843,7 @@ func (x *BoardingSweepOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use BoardingSweepOutput.ProtoReflect.Descriptor instead. func (*BoardingSweepOutput) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{74} + return file_daemon_proto_rawDescGZIP(), []int{79} } func (x *BoardingSweepOutput) GetOutpoint() string { @@ -6467,7 +6909,7 @@ type SweepBoardingUTXOsResponse struct { func (x *SweepBoardingUTXOsResponse) Reset() { *x = SweepBoardingUTXOsResponse{} - mi := &file_daemon_proto_msgTypes[75] + mi := &file_daemon_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6479,7 +6921,7 @@ func (x *SweepBoardingUTXOsResponse) String() string { func (*SweepBoardingUTXOsResponse) ProtoMessage() {} func (x *SweepBoardingUTXOsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[75] + mi := &file_daemon_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6492,7 +6934,7 @@ func (x *SweepBoardingUTXOsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SweepBoardingUTXOsResponse.ProtoReflect.Descriptor instead. func (*SweepBoardingUTXOsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{75} + return file_daemon_proto_rawDescGZIP(), []int{80} } func (x *SweepBoardingUTXOsResponse) GetStatus() string { @@ -6596,7 +7038,7 @@ type ListBoardingSweepsRequest struct { func (x *ListBoardingSweepsRequest) Reset() { *x = ListBoardingSweepsRequest{} - mi := &file_daemon_proto_msgTypes[76] + mi := &file_daemon_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6608,7 +7050,7 @@ func (x *ListBoardingSweepsRequest) String() string { func (*ListBoardingSweepsRequest) ProtoMessage() {} func (x *ListBoardingSweepsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[76] + mi := &file_daemon_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6621,7 +7063,7 @@ func (x *ListBoardingSweepsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListBoardingSweepsRequest.ProtoReflect.Descriptor instead. func (*ListBoardingSweepsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{76} + return file_daemon_proto_rawDescGZIP(), []int{81} } func (x *ListBoardingSweepsRequest) GetStatus() string { @@ -6664,7 +7106,7 @@ type BoardingSweepInput struct { func (x *BoardingSweepInput) Reset() { *x = BoardingSweepInput{} - mi := &file_daemon_proto_msgTypes[77] + mi := &file_daemon_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6676,7 +7118,7 @@ func (x *BoardingSweepInput) String() string { func (*BoardingSweepInput) ProtoMessage() {} func (x *BoardingSweepInput) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[77] + mi := &file_daemon_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6689,7 +7131,7 @@ func (x *BoardingSweepInput) ProtoReflect() protoreflect.Message { // Deprecated: Use BoardingSweepInput.ProtoReflect.Descriptor instead. func (*BoardingSweepInput) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{77} + return file_daemon_proto_rawDescGZIP(), []int{82} } func (x *BoardingSweepInput) GetOutpoint() string { @@ -6759,7 +7201,7 @@ type BoardingSweep struct { func (x *BoardingSweep) Reset() { *x = BoardingSweep{} - mi := &file_daemon_proto_msgTypes[78] + mi := &file_daemon_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6771,7 +7213,7 @@ func (x *BoardingSweep) String() string { func (*BoardingSweep) ProtoMessage() {} func (x *BoardingSweep) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[78] + mi := &file_daemon_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6784,7 +7226,7 @@ func (x *BoardingSweep) ProtoReflect() protoreflect.Message { // Deprecated: Use BoardingSweep.ProtoReflect.Descriptor instead. func (*BoardingSweep) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{78} + return file_daemon_proto_rawDescGZIP(), []int{83} } func (x *BoardingSweep) GetTxid() string { @@ -6876,7 +7318,7 @@ type ListBoardingSweepsResponse struct { func (x *ListBoardingSweepsResponse) Reset() { *x = ListBoardingSweepsResponse{} - mi := &file_daemon_proto_msgTypes[79] + mi := &file_daemon_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6888,7 +7330,7 @@ func (x *ListBoardingSweepsResponse) String() string { func (*ListBoardingSweepsResponse) ProtoMessage() {} func (x *ListBoardingSweepsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[79] + mi := &file_daemon_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6901,7 +7343,7 @@ func (x *ListBoardingSweepsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListBoardingSweepsResponse.ProtoReflect.Descriptor instead. func (*ListBoardingSweepsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{79} + return file_daemon_proto_rawDescGZIP(), []int{84} } func (x *ListBoardingSweepsResponse) GetSweeps() []*BoardingSweep { @@ -6931,7 +7373,7 @@ type RoundVTXOInfo struct { func (x *RoundVTXOInfo) Reset() { *x = RoundVTXOInfo{} - mi := &file_daemon_proto_msgTypes[80] + mi := &file_daemon_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6943,7 +7385,7 @@ func (x *RoundVTXOInfo) String() string { func (*RoundVTXOInfo) ProtoMessage() {} func (x *RoundVTXOInfo) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[80] + mi := &file_daemon_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6956,7 +7398,7 @@ func (x *RoundVTXOInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use RoundVTXOInfo.ProtoReflect.Descriptor instead. func (*RoundVTXOInfo) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{80} + return file_daemon_proto_rawDescGZIP(), []int{85} } func (x *RoundVTXOInfo) GetOutpoint() string { @@ -7024,7 +7466,7 @@ type RoundInfo struct { func (x *RoundInfo) Reset() { *x = RoundInfo{} - mi := &file_daemon_proto_msgTypes[81] + mi := &file_daemon_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7036,7 +7478,7 @@ func (x *RoundInfo) String() string { func (*RoundInfo) ProtoMessage() {} func (x *RoundInfo) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[81] + mi := &file_daemon_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7049,7 +7491,7 @@ func (x *RoundInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use RoundInfo.ProtoReflect.Descriptor instead. func (*RoundInfo) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{81} + return file_daemon_proto_rawDescGZIP(), []int{86} } func (x *RoundInfo) GetRoundId() string { @@ -7161,7 +7603,7 @@ type ListRoundsRequest struct { func (x *ListRoundsRequest) Reset() { *x = ListRoundsRequest{} - mi := &file_daemon_proto_msgTypes[82] + mi := &file_daemon_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7173,7 +7615,7 @@ func (x *ListRoundsRequest) String() string { func (*ListRoundsRequest) ProtoMessage() {} func (x *ListRoundsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[82] + mi := &file_daemon_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7186,7 +7628,7 @@ func (x *ListRoundsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListRoundsRequest.ProtoReflect.Descriptor instead. func (*ListRoundsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{82} + return file_daemon_proto_rawDescGZIP(), []int{87} } func (x *ListRoundsRequest) GetPageSize() int32 { @@ -7241,7 +7683,7 @@ type GetRoundRequest struct { func (x *GetRoundRequest) Reset() { *x = GetRoundRequest{} - mi := &file_daemon_proto_msgTypes[83] + mi := &file_daemon_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7253,7 +7695,7 @@ func (x *GetRoundRequest) String() string { func (*GetRoundRequest) ProtoMessage() {} func (x *GetRoundRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[83] + mi := &file_daemon_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7266,7 +7708,7 @@ func (x *GetRoundRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRoundRequest.ProtoReflect.Descriptor instead. func (*GetRoundRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{83} + return file_daemon_proto_rawDescGZIP(), []int{88} } func (x *GetRoundRequest) GetRoundId() string { @@ -7286,7 +7728,7 @@ type GetRoundResponse struct { func (x *GetRoundResponse) Reset() { *x = GetRoundResponse{} - mi := &file_daemon_proto_msgTypes[84] + mi := &file_daemon_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7298,7 +7740,7 @@ func (x *GetRoundResponse) String() string { func (*GetRoundResponse) ProtoMessage() {} func (x *GetRoundResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[84] + mi := &file_daemon_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7311,7 +7753,7 @@ func (x *GetRoundResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRoundResponse.ProtoReflect.Descriptor instead. func (*GetRoundResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{84} + return file_daemon_proto_rawDescGZIP(), []int{89} } func (x *GetRoundResponse) GetRound() *RoundInfo { @@ -7334,7 +7776,7 @@ type ListRoundsResponse struct { func (x *ListRoundsResponse) Reset() { *x = ListRoundsResponse{} - mi := &file_daemon_proto_msgTypes[85] + mi := &file_daemon_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7346,7 +7788,7 @@ func (x *ListRoundsResponse) String() string { func (*ListRoundsResponse) ProtoMessage() {} func (x *ListRoundsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[85] + mi := &file_daemon_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7359,7 +7801,7 @@ func (x *ListRoundsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListRoundsResponse.ProtoReflect.Descriptor instead. func (*ListRoundsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{85} + return file_daemon_proto_rawDescGZIP(), []int{90} } func (x *ListRoundsResponse) GetRounds() []*RoundInfo { @@ -7384,7 +7826,7 @@ type WatchRoundsRequest struct { func (x *WatchRoundsRequest) Reset() { *x = WatchRoundsRequest{} - mi := &file_daemon_proto_msgTypes[86] + mi := &file_daemon_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7396,7 +7838,7 @@ func (x *WatchRoundsRequest) String() string { func (*WatchRoundsRequest) ProtoMessage() {} func (x *WatchRoundsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[86] + mi := &file_daemon_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7409,7 +7851,7 @@ func (x *WatchRoundsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WatchRoundsRequest.ProtoReflect.Descriptor instead. func (*WatchRoundsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{86} + return file_daemon_proto_rawDescGZIP(), []int{91} } type WatchRoundsResponse struct { @@ -7423,7 +7865,7 @@ type WatchRoundsResponse struct { func (x *WatchRoundsResponse) Reset() { *x = WatchRoundsResponse{} - mi := &file_daemon_proto_msgTypes[87] + mi := &file_daemon_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7435,7 +7877,7 @@ func (x *WatchRoundsResponse) String() string { func (*WatchRoundsResponse) ProtoMessage() {} func (x *WatchRoundsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[87] + mi := &file_daemon_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7448,7 +7890,7 @@ func (x *WatchRoundsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use WatchRoundsResponse.ProtoReflect.Descriptor instead. func (*WatchRoundsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{87} + return file_daemon_proto_rawDescGZIP(), []int{92} } func (x *WatchRoundsResponse) GetRound() *RoundInfo { @@ -7486,7 +7928,7 @@ type OORSessionInfo struct { func (x *OORSessionInfo) Reset() { *x = OORSessionInfo{} - mi := &file_daemon_proto_msgTypes[88] + mi := &file_daemon_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7498,7 +7940,7 @@ func (x *OORSessionInfo) String() string { func (*OORSessionInfo) ProtoMessage() {} func (x *OORSessionInfo) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[88] + mi := &file_daemon_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7511,7 +7953,7 @@ func (x *OORSessionInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use OORSessionInfo.ProtoReflect.Descriptor instead. func (*OORSessionInfo) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{88} + return file_daemon_proto_rawDescGZIP(), []int{93} } func (x *OORSessionInfo) GetSessionId() string { @@ -7595,7 +8037,7 @@ type ListOORSessionsRequest struct { func (x *ListOORSessionsRequest) Reset() { *x = ListOORSessionsRequest{} - mi := &file_daemon_proto_msgTypes[89] + mi := &file_daemon_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7607,7 +8049,7 @@ func (x *ListOORSessionsRequest) String() string { func (*ListOORSessionsRequest) ProtoMessage() {} func (x *ListOORSessionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[89] + mi := &file_daemon_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7620,7 +8062,7 @@ func (x *ListOORSessionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListOORSessionsRequest.ProtoReflect.Descriptor instead. func (*ListOORSessionsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{89} + return file_daemon_proto_rawDescGZIP(), []int{94} } func (x *ListOORSessionsRequest) GetPageSize() int32 { @@ -7664,7 +8106,7 @@ type ListOORSessionsResponse struct { func (x *ListOORSessionsResponse) Reset() { *x = ListOORSessionsResponse{} - mi := &file_daemon_proto_msgTypes[90] + mi := &file_daemon_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7676,7 +8118,7 @@ func (x *ListOORSessionsResponse) String() string { func (*ListOORSessionsResponse) ProtoMessage() {} func (x *ListOORSessionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[90] + mi := &file_daemon_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7689,7 +8131,7 @@ func (x *ListOORSessionsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListOORSessionsResponse.ProtoReflect.Descriptor instead. func (*ListOORSessionsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{90} + return file_daemon_proto_rawDescGZIP(), []int{95} } func (x *ListOORSessionsResponse) GetSessions() []*OORSessionInfo { @@ -7716,7 +8158,7 @@ type GetOORSessionRequest struct { func (x *GetOORSessionRequest) Reset() { *x = GetOORSessionRequest{} - mi := &file_daemon_proto_msgTypes[91] + mi := &file_daemon_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7728,7 +8170,7 @@ func (x *GetOORSessionRequest) String() string { func (*GetOORSessionRequest) ProtoMessage() {} func (x *GetOORSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[91] + mi := &file_daemon_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7741,7 +8183,7 @@ func (x *GetOORSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetOORSessionRequest.ProtoReflect.Descriptor instead. func (*GetOORSessionRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{91} + return file_daemon_proto_rawDescGZIP(), []int{96} } func (x *GetOORSessionRequest) GetSessionId() string { @@ -7761,7 +8203,7 @@ type GetOORSessionResponse struct { func (x *GetOORSessionResponse) Reset() { *x = GetOORSessionResponse{} - mi := &file_daemon_proto_msgTypes[92] + mi := &file_daemon_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7773,7 +8215,7 @@ func (x *GetOORSessionResponse) String() string { func (*GetOORSessionResponse) ProtoMessage() {} func (x *GetOORSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[92] + mi := &file_daemon_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7786,7 +8228,7 @@ func (x *GetOORSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetOORSessionResponse.ProtoReflect.Descriptor instead. func (*GetOORSessionResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{92} + return file_daemon_proto_rawDescGZIP(), []int{97} } func (x *GetOORSessionResponse) GetSession() *OORSessionInfo { @@ -7814,7 +8256,7 @@ type EstimateFeeRequest struct { func (x *EstimateFeeRequest) Reset() { *x = EstimateFeeRequest{} - mi := &file_daemon_proto_msgTypes[93] + mi := &file_daemon_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7826,7 +8268,7 @@ func (x *EstimateFeeRequest) String() string { func (*EstimateFeeRequest) ProtoMessage() {} func (x *EstimateFeeRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[93] + mi := &file_daemon_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7839,7 +8281,7 @@ func (x *EstimateFeeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EstimateFeeRequest.ProtoReflect.Descriptor instead. func (*EstimateFeeRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{93} + return file_daemon_proto_rawDescGZIP(), []int{98} } func (x *EstimateFeeRequest) GetAmountSat() int64 { @@ -7893,7 +8335,7 @@ type EstimateFeeResponse struct { func (x *EstimateFeeResponse) Reset() { *x = EstimateFeeResponse{} - mi := &file_daemon_proto_msgTypes[94] + mi := &file_daemon_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7905,7 +8347,7 @@ func (x *EstimateFeeResponse) String() string { func (*EstimateFeeResponse) ProtoMessage() {} func (x *EstimateFeeResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[94] + mi := &file_daemon_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7918,7 +8360,7 @@ func (x *EstimateFeeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EstimateFeeResponse.ProtoReflect.Descriptor instead. func (*EstimateFeeResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{94} + return file_daemon_proto_rawDescGZIP(), []int{99} } func (x *EstimateFeeResponse) GetLiquidityFeeSat() int64 { @@ -7988,7 +8430,7 @@ type GetFeeHistoryRequest struct { func (x *GetFeeHistoryRequest) Reset() { *x = GetFeeHistoryRequest{} - mi := &file_daemon_proto_msgTypes[95] + mi := &file_daemon_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8000,7 +8442,7 @@ func (x *GetFeeHistoryRequest) String() string { func (*GetFeeHistoryRequest) ProtoMessage() {} func (x *GetFeeHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[95] + mi := &file_daemon_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8013,7 +8455,7 @@ func (x *GetFeeHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetFeeHistoryRequest.ProtoReflect.Descriptor instead. func (*GetFeeHistoryRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{95} + return file_daemon_proto_rawDescGZIP(), []int{100} } func (x *GetFeeHistoryRequest) GetLimit() uint32 { @@ -8088,7 +8530,7 @@ type FeeHistoryEntry struct { func (x *FeeHistoryEntry) Reset() { *x = FeeHistoryEntry{} - mi := &file_daemon_proto_msgTypes[96] + mi := &file_daemon_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8100,7 +8542,7 @@ func (x *FeeHistoryEntry) String() string { func (*FeeHistoryEntry) ProtoMessage() {} func (x *FeeHistoryEntry) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[96] + mi := &file_daemon_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8113,7 +8555,7 @@ func (x *FeeHistoryEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use FeeHistoryEntry.ProtoReflect.Descriptor instead. func (*FeeHistoryEntry) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{96} + return file_daemon_proto_rawDescGZIP(), []int{101} } func (x *FeeHistoryEntry) GetEntryId() int64 { @@ -8193,7 +8635,7 @@ type GetFeeHistoryResponse struct { func (x *GetFeeHistoryResponse) Reset() { *x = GetFeeHistoryResponse{} - mi := &file_daemon_proto_msgTypes[97] + mi := &file_daemon_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8205,7 +8647,7 @@ func (x *GetFeeHistoryResponse) String() string { func (*GetFeeHistoryResponse) ProtoMessage() {} func (x *GetFeeHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[97] + mi := &file_daemon_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8218,7 +8660,7 @@ func (x *GetFeeHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetFeeHistoryResponse.ProtoReflect.Descriptor instead. func (*GetFeeHistoryResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{97} + return file_daemon_proto_rawDescGZIP(), []int{102} } func (x *GetFeeHistoryResponse) GetEntries() []*FeeHistoryEntry { @@ -8259,7 +8701,7 @@ type ListTransactionsRequest struct { func (x *ListTransactionsRequest) Reset() { *x = ListTransactionsRequest{} - mi := &file_daemon_proto_msgTypes[98] + mi := &file_daemon_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8271,7 +8713,7 @@ func (x *ListTransactionsRequest) String() string { func (*ListTransactionsRequest) ProtoMessage() {} func (x *ListTransactionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[98] + mi := &file_daemon_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8284,7 +8726,7 @@ func (x *ListTransactionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTransactionsRequest.ProtoReflect.Descriptor instead. func (*ListTransactionsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{98} + return file_daemon_proto_rawDescGZIP(), []int{103} } func (x *ListTransactionsRequest) GetFromUnixS() int64 { @@ -8375,7 +8817,7 @@ type TransactionHistoryEntry struct { func (x *TransactionHistoryEntry) Reset() { *x = TransactionHistoryEntry{} - mi := &file_daemon_proto_msgTypes[99] + mi := &file_daemon_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8387,7 +8829,7 @@ func (x *TransactionHistoryEntry) String() string { func (*TransactionHistoryEntry) ProtoMessage() {} func (x *TransactionHistoryEntry) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[99] + mi := &file_daemon_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8400,7 +8842,7 @@ func (x *TransactionHistoryEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionHistoryEntry.ProtoReflect.Descriptor instead. func (*TransactionHistoryEntry) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{99} + return file_daemon_proto_rawDescGZIP(), []int{104} } func (x *TransactionHistoryEntry) GetSource() string { @@ -8537,7 +8979,7 @@ type ListTransactionsResponse struct { func (x *ListTransactionsResponse) Reset() { *x = ListTransactionsResponse{} - mi := &file_daemon_proto_msgTypes[100] + mi := &file_daemon_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8549,7 +8991,7 @@ func (x *ListTransactionsResponse) String() string { func (*ListTransactionsResponse) ProtoMessage() {} func (x *ListTransactionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[100] + mi := &file_daemon_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8562,7 +9004,7 @@ func (x *ListTransactionsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTransactionsResponse.ProtoReflect.Descriptor instead. func (*ListTransactionsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{100} + return file_daemon_proto_rawDescGZIP(), []int{105} } func (x *ListTransactionsResponse) GetTransactions() []*TransactionHistoryEntry { @@ -8597,7 +9039,7 @@ type UnrollRequest struct { func (x *UnrollRequest) Reset() { *x = UnrollRequest{} - mi := &file_daemon_proto_msgTypes[101] + mi := &file_daemon_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8609,7 +9051,7 @@ func (x *UnrollRequest) String() string { func (*UnrollRequest) ProtoMessage() {} func (x *UnrollRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[101] + mi := &file_daemon_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8622,7 +9064,7 @@ func (x *UnrollRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UnrollRequest.ProtoReflect.Descriptor instead. func (*UnrollRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{101} + return file_daemon_proto_rawDescGZIP(), []int{106} } func (x *UnrollRequest) GetOutpoint() string { @@ -8645,7 +9087,7 @@ type UnrollResponse struct { func (x *UnrollResponse) Reset() { *x = UnrollResponse{} - mi := &file_daemon_proto_msgTypes[102] + mi := &file_daemon_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8657,7 +9099,7 @@ func (x *UnrollResponse) String() string { func (*UnrollResponse) ProtoMessage() {} func (x *UnrollResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[102] + mi := &file_daemon_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8670,7 +9112,7 @@ func (x *UnrollResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UnrollResponse.ProtoReflect.Descriptor instead. func (*UnrollResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{102} + return file_daemon_proto_rawDescGZIP(), []int{107} } func (x *UnrollResponse) GetCreated() bool { @@ -8702,7 +9144,7 @@ type GetUnrollStatusRequest struct { func (x *GetUnrollStatusRequest) Reset() { *x = GetUnrollStatusRequest{} - mi := &file_daemon_proto_msgTypes[103] + mi := &file_daemon_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8714,7 +9156,7 @@ func (x *GetUnrollStatusRequest) String() string { func (*GetUnrollStatusRequest) ProtoMessage() {} func (x *GetUnrollStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[103] + mi := &file_daemon_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8727,7 +9169,7 @@ func (x *GetUnrollStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetUnrollStatusRequest.ProtoReflect.Descriptor instead. func (*GetUnrollStatusRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{103} + return file_daemon_proto_rawDescGZIP(), []int{108} } func (x *GetUnrollStatusRequest) GetOutpoint() string { @@ -8779,7 +9221,7 @@ type UnrollProgress struct { func (x *UnrollProgress) Reset() { *x = UnrollProgress{} - mi := &file_daemon_proto_msgTypes[104] + mi := &file_daemon_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8791,7 +9233,7 @@ func (x *UnrollProgress) String() string { func (*UnrollProgress) ProtoMessage() {} func (x *UnrollProgress) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[104] + mi := &file_daemon_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8804,7 +9246,7 @@ func (x *UnrollProgress) ProtoReflect() protoreflect.Message { // Deprecated: Use UnrollProgress.ProtoReflect.Descriptor instead. func (*UnrollProgress) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{104} + return file_daemon_proto_rawDescGZIP(), []int{109} } func (x *UnrollProgress) GetConfirmedTxs() uint32 { @@ -8889,7 +9331,7 @@ type UnrollCSV struct { func (x *UnrollCSV) Reset() { *x = UnrollCSV{} - mi := &file_daemon_proto_msgTypes[105] + mi := &file_daemon_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8901,7 +9343,7 @@ func (x *UnrollCSV) String() string { func (*UnrollCSV) ProtoMessage() {} func (x *UnrollCSV) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[105] + mi := &file_daemon_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8914,7 +9356,7 @@ func (x *UnrollCSV) ProtoReflect() protoreflect.Message { // Deprecated: Use UnrollCSV.ProtoReflect.Descriptor instead. func (*UnrollCSV) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{105} + return file_daemon_proto_rawDescGZIP(), []int{110} } func (x *UnrollCSV) GetTargetConfirmHeight() int32 { @@ -8979,7 +9421,7 @@ type UnrollFees struct { func (x *UnrollFees) Reset() { *x = UnrollFees{} - mi := &file_daemon_proto_msgTypes[106] + mi := &file_daemon_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8991,7 +9433,7 @@ func (x *UnrollFees) String() string { func (*UnrollFees) ProtoMessage() {} func (x *UnrollFees) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[106] + mi := &file_daemon_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9004,7 +9446,7 @@ func (x *UnrollFees) ProtoReflect() protoreflect.Message { // Deprecated: Use UnrollFees.ProtoReflect.Descriptor instead. func (*UnrollFees) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{106} + return file_daemon_proto_rawDescGZIP(), []int{111} } func (x *UnrollFees) GetCpfpFeeSat() int64 { @@ -9106,7 +9548,7 @@ type GetUnrollStatusResponse struct { func (x *GetUnrollStatusResponse) Reset() { *x = GetUnrollStatusResponse{} - mi := &file_daemon_proto_msgTypes[107] + mi := &file_daemon_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9118,7 +9560,7 @@ func (x *GetUnrollStatusResponse) String() string { func (*GetUnrollStatusResponse) ProtoMessage() {} func (x *GetUnrollStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[107] + mi := &file_daemon_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9131,7 +9573,7 @@ func (x *GetUnrollStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetUnrollStatusResponse.ProtoReflect.Descriptor instead. func (*GetUnrollStatusResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{107} + return file_daemon_proto_rawDescGZIP(), []int{112} } func (x *GetUnrollStatusResponse) GetFound() bool { @@ -9262,7 +9704,7 @@ type ArmVHTLCRecoveryRequest struct { func (x *ArmVHTLCRecoveryRequest) Reset() { *x = ArmVHTLCRecoveryRequest{} - mi := &file_daemon_proto_msgTypes[108] + mi := &file_daemon_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9274,7 +9716,7 @@ func (x *ArmVHTLCRecoveryRequest) String() string { func (*ArmVHTLCRecoveryRequest) ProtoMessage() {} func (x *ArmVHTLCRecoveryRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[108] + mi := &file_daemon_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9287,7 +9729,7 @@ func (x *ArmVHTLCRecoveryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ArmVHTLCRecoveryRequest.ProtoReflect.Descriptor instead. func (*ArmVHTLCRecoveryRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{108} + return file_daemon_proto_rawDescGZIP(), []int{113} } func (x *ArmVHTLCRecoveryRequest) GetRequestId() string { @@ -9430,7 +9872,7 @@ type ArmVHTLCRecoveryResponse struct { func (x *ArmVHTLCRecoveryResponse) Reset() { *x = ArmVHTLCRecoveryResponse{} - mi := &file_daemon_proto_msgTypes[109] + mi := &file_daemon_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9442,7 +9884,7 @@ func (x *ArmVHTLCRecoveryResponse) String() string { func (*ArmVHTLCRecoveryResponse) ProtoMessage() {} func (x *ArmVHTLCRecoveryResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[109] + mi := &file_daemon_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9455,7 +9897,7 @@ func (x *ArmVHTLCRecoveryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ArmVHTLCRecoveryResponse.ProtoReflect.Descriptor instead. func (*ArmVHTLCRecoveryResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{109} + return file_daemon_proto_rawDescGZIP(), []int{114} } func (x *ArmVHTLCRecoveryResponse) GetRecoveryId() string { @@ -9495,7 +9937,7 @@ type EscalateVHTLCRecoveryRequest struct { func (x *EscalateVHTLCRecoveryRequest) Reset() { *x = EscalateVHTLCRecoveryRequest{} - mi := &file_daemon_proto_msgTypes[110] + mi := &file_daemon_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9507,7 +9949,7 @@ func (x *EscalateVHTLCRecoveryRequest) String() string { func (*EscalateVHTLCRecoveryRequest) ProtoMessage() {} func (x *EscalateVHTLCRecoveryRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[110] + mi := &file_daemon_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9520,7 +9962,7 @@ func (x *EscalateVHTLCRecoveryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EscalateVHTLCRecoveryRequest.ProtoReflect.Descriptor instead. func (*EscalateVHTLCRecoveryRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{110} + return file_daemon_proto_rawDescGZIP(), []int{115} } func (x *EscalateVHTLCRecoveryRequest) GetRecoveryId() string { @@ -9554,7 +9996,7 @@ type EscalateVHTLCRecoveryResponse struct { func (x *EscalateVHTLCRecoveryResponse) Reset() { *x = EscalateVHTLCRecoveryResponse{} - mi := &file_daemon_proto_msgTypes[111] + mi := &file_daemon_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9566,7 +10008,7 @@ func (x *EscalateVHTLCRecoveryResponse) String() string { func (*EscalateVHTLCRecoveryResponse) ProtoMessage() {} func (x *EscalateVHTLCRecoveryResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[111] + mi := &file_daemon_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9579,7 +10021,7 @@ func (x *EscalateVHTLCRecoveryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EscalateVHTLCRecoveryResponse.ProtoReflect.Descriptor instead. func (*EscalateVHTLCRecoveryResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{111} + return file_daemon_proto_rawDescGZIP(), []int{116} } func (x *EscalateVHTLCRecoveryResponse) GetStatus() *VHTLCRecoveryStatus { @@ -9603,7 +10045,7 @@ type CancelVHTLCRecoveryRequest struct { func (x *CancelVHTLCRecoveryRequest) Reset() { *x = CancelVHTLCRecoveryRequest{} - mi := &file_daemon_proto_msgTypes[112] + mi := &file_daemon_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9615,7 +10057,7 @@ func (x *CancelVHTLCRecoveryRequest) String() string { func (*CancelVHTLCRecoveryRequest) ProtoMessage() {} func (x *CancelVHTLCRecoveryRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[112] + mi := &file_daemon_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9628,7 +10070,7 @@ func (x *CancelVHTLCRecoveryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CancelVHTLCRecoveryRequest.ProtoReflect.Descriptor instead. func (*CancelVHTLCRecoveryRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{112} + return file_daemon_proto_rawDescGZIP(), []int{117} } func (x *CancelVHTLCRecoveryRequest) GetRecoveryId() string { @@ -9662,7 +10104,7 @@ type CancelVHTLCRecoveryResponse struct { func (x *CancelVHTLCRecoveryResponse) Reset() { *x = CancelVHTLCRecoveryResponse{} - mi := &file_daemon_proto_msgTypes[113] + mi := &file_daemon_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9674,7 +10116,7 @@ func (x *CancelVHTLCRecoveryResponse) String() string { func (*CancelVHTLCRecoveryResponse) ProtoMessage() {} func (x *CancelVHTLCRecoveryResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[113] + mi := &file_daemon_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9687,7 +10129,7 @@ func (x *CancelVHTLCRecoveryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CancelVHTLCRecoveryResponse.ProtoReflect.Descriptor instead. func (*CancelVHTLCRecoveryResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{113} + return file_daemon_proto_rawDescGZIP(), []int{118} } func (x *CancelVHTLCRecoveryResponse) GetStatus() *VHTLCRecoveryStatus { @@ -9707,7 +10149,7 @@ type GetVHTLCRecoveryStatusRequest struct { func (x *GetVHTLCRecoveryStatusRequest) Reset() { *x = GetVHTLCRecoveryStatusRequest{} - mi := &file_daemon_proto_msgTypes[114] + mi := &file_daemon_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9719,7 +10161,7 @@ func (x *GetVHTLCRecoveryStatusRequest) String() string { func (*GetVHTLCRecoveryStatusRequest) ProtoMessage() {} func (x *GetVHTLCRecoveryStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[114] + mi := &file_daemon_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9732,7 +10174,7 @@ func (x *GetVHTLCRecoveryStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetVHTLCRecoveryStatusRequest.ProtoReflect.Descriptor instead. func (*GetVHTLCRecoveryStatusRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{114} + return file_daemon_proto_rawDescGZIP(), []int{119} } func (x *GetVHTLCRecoveryStatusRequest) GetRecoveryId() string { @@ -9754,7 +10196,7 @@ type GetVHTLCRecoveryStatusResponse struct { func (x *GetVHTLCRecoveryStatusResponse) Reset() { *x = GetVHTLCRecoveryStatusResponse{} - mi := &file_daemon_proto_msgTypes[115] + mi := &file_daemon_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9766,7 +10208,7 @@ func (x *GetVHTLCRecoveryStatusResponse) String() string { func (*GetVHTLCRecoveryStatusResponse) ProtoMessage() {} func (x *GetVHTLCRecoveryStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[115] + mi := &file_daemon_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9779,7 +10221,7 @@ func (x *GetVHTLCRecoveryStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetVHTLCRecoveryStatusResponse.ProtoReflect.Descriptor instead. func (*GetVHTLCRecoveryStatusResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{115} + return file_daemon_proto_rawDescGZIP(), []int{120} } func (x *GetVHTLCRecoveryStatusResponse) GetFound() bool { @@ -9806,7 +10248,7 @@ type ListVHTLCRecoveriesRequest struct { func (x *ListVHTLCRecoveriesRequest) Reset() { *x = ListVHTLCRecoveriesRequest{} - mi := &file_daemon_proto_msgTypes[116] + mi := &file_daemon_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9818,7 +10260,7 @@ func (x *ListVHTLCRecoveriesRequest) String() string { func (*ListVHTLCRecoveriesRequest) ProtoMessage() {} func (x *ListVHTLCRecoveriesRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[116] + mi := &file_daemon_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9831,7 +10273,7 @@ func (x *ListVHTLCRecoveriesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListVHTLCRecoveriesRequest.ProtoReflect.Descriptor instead. func (*ListVHTLCRecoveriesRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{116} + return file_daemon_proto_rawDescGZIP(), []int{121} } func (x *ListVHTLCRecoveriesRequest) GetIncludeTerminal() bool { @@ -9851,7 +10293,7 @@ type ListVHTLCRecoveriesResponse struct { func (x *ListVHTLCRecoveriesResponse) Reset() { *x = ListVHTLCRecoveriesResponse{} - mi := &file_daemon_proto_msgTypes[117] + mi := &file_daemon_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9863,7 +10305,7 @@ func (x *ListVHTLCRecoveriesResponse) String() string { func (*ListVHTLCRecoveriesResponse) ProtoMessage() {} func (x *ListVHTLCRecoveriesResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[117] + mi := &file_daemon_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9876,7 +10318,7 @@ func (x *ListVHTLCRecoveriesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListVHTLCRecoveriesResponse.ProtoReflect.Descriptor instead. func (*ListVHTLCRecoveriesResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{117} + return file_daemon_proto_rawDescGZIP(), []int{122} } func (x *ListVHTLCRecoveriesResponse) GetStatuses() []*VHTLCRecoveryStatus { @@ -9951,7 +10393,7 @@ type VHTLCRecoveryStatus struct { func (x *VHTLCRecoveryStatus) Reset() { *x = VHTLCRecoveryStatus{} - mi := &file_daemon_proto_msgTypes[118] + mi := &file_daemon_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9963,7 +10405,7 @@ func (x *VHTLCRecoveryStatus) String() string { func (*VHTLCRecoveryStatus) ProtoMessage() {} func (x *VHTLCRecoveryStatus) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[118] + mi := &file_daemon_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9976,7 +10418,7 @@ func (x *VHTLCRecoveryStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use VHTLCRecoveryStatus.ProtoReflect.Descriptor instead. func (*VHTLCRecoveryStatus) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{118} + return file_daemon_proto_rawDescGZIP(), []int{123} } func (x *VHTLCRecoveryStatus) GetRecoveryId() string { @@ -10492,7 +10934,34 @@ const file_daemon_proto_rawDesc = "" + "\n" + "signatures\x18\x02 \x03(\v2$.waverpc.ForfeitParticipantSignatureR\n" + "signatures\",\n" + - "*SubmitForfeitParticipantSignaturesResponse\"W\n" + + "*SubmitForfeitParticipantSignaturesResponse\"\xfd\x02\n" + + "\x19PendingTreeSigningRequest\x12\x1d\n" + + "\n" + + "request_id\x18\x01 \x01(\fR\trequestId\x12\x1a\n" + + "\bsequence\x18\x02 \x01(\x04R\bsequence\x12/\n" + + "\x05round\x18\x03 \x01(\x0e2\x19.waverpc.TreeSigningRoundR\x05round\x12\x19\n" + + "\bround_id\x18\x04 \x01(\fR\aroundId\x12'\n" + + "\x0fcosigner_pubkey\x18\x05 \x01(\fR\x0ecosignerPubkey\x12\x1d\n" + + "\n" + + "session_id\x18\x06 \x01(\fR\tsessionId\x12\x1c\n" + + "\tcosigners\x18\a \x03(\fR\tcosigners\x120\n" + + "\x14sweep_tapscript_root\x18\b \x01(\fR\x12sweepTapscriptRoot\x12\x18\n" + + "\asighash\x18\t \x01(\fR\asighash\x12'\n" + + "\x0faggregate_nonce\x18\n" + + " \x01(\fR\x0eaggregateNonce\"d\n" + + "%ListPendingTreeSigningRequestsRequest\x12%\n" + + "\x0eafter_sequence\x18\x01 \x01(\x04R\rafterSequence\x12\x14\n" + + "\x05limit\x18\x02 \x01(\rR\x05limit\"\x8d\x01\n" + + "&ListPendingTreeSigningRequestsResponse\x12>\n" + + "\brequests\x18\x01 \x03(\v2\".waverpc.PendingTreeSigningRequestR\brequests\x12#\n" + + "\rnext_sequence\x18\x02 \x01(\x04R\fnextSequence\"\xbd\x01\n" + + "\x1bSubmitTreeSignaturesRequest\x12\x1d\n" + + "\n" + + "request_id\x18\x01 \x01(\fR\trequestId\x12/\n" + + "\x05round\x18\x02 \x01(\x0e2\x19.waverpc.TreeSigningRoundR\x05round\x12!\n" + + "\fpublic_nonce\x18\x03 \x01(\fR\vpublicNonce\x12+\n" + + "\x11partial_signature\x18\x04 \x01(\fR\x10partialSignature\"\x1e\n" + + "\x1cSubmitTreeSignaturesResponse\"W\n" + "\x10LeaveDestination\x12\x1a\n" + "\aaddress\x18\x01 \x01(\tH\x00R\aaddress\x12\x1d\n" + "\tpk_script\x18\x02 \x01(\fH\x00R\bpkScriptB\b\n" + @@ -10523,11 +10992,13 @@ const file_daemon_proto_rawDesc = "" + "\x12selected_outpoints\x18\x03 \x03(\tR\x11selectedOutpoints\x12'\n" + "\x0fchange_outpoint\x18\x04 \x01(\tR\x0echangeOutpoint\x12\x16\n" + "\x06status\x18\x05 \x01(\tR\x06status\x12\x1e\n" + - "\vsend_job_id\x18\x06 \x01(\tR\tsendJobId\"Y\n" + + "\vsend_job_id\x18\x06 \x01(\tR\tsendJobId\"\xa8\x01\n" + "\fBoardRequest\x12*\n" + "\x11target_vtxo_count\x18\x01 \x01(\rR\x0ftargetVtxoCount\x12\x1d\n" + "\n" + - "no_persist\x18\x02 \x01(\bR\tnoPersist\"F\n" + + "no_persist\x18\x02 \x01(\bR\tnoPersist\x120\n" + + "\x14vtxo_policy_template\x18\x03 \x01(\fR\x12vtxoPolicyTemplate\x12\x1b\n" + + "\tpk_script\x18\x04 \x01(\fR\bpkScript\"F\n" + "\rBoardResponse\x12\x16\n" + "\x06status\x18\x01 \x01(\tR\x06status\x12\x1d\n" + "\n" + @@ -10878,7 +11349,11 @@ const file_daemon_proto_rawDesc = "" + "\x13ForfeitSigningRoute\x12%\n" + "!FORFEIT_SIGNING_ROUTE_UNSPECIFIED\x10\x00\x12&\n" + "\"FORFEIT_SIGNING_ROUTE_LOCAL_SIGNER\x10\x01\x12)\n" + - "%FORFEIT_SIGNING_ROUTE_PENDING_REQUEST\x10\x02*\xf7\x03\n" + + "%FORFEIT_SIGNING_ROUTE_PENDING_REQUEST\x10\x02*x\n" + + "\x10TreeSigningRound\x12\"\n" + + "\x1eTREE_SIGNING_ROUND_UNSPECIFIED\x10\x00\x12\x1c\n" + + "\x18TREE_SIGNING_ROUND_NONCE\x10\x01\x12\"\n" + + "\x1eTREE_SIGNING_ROUND_PARTIAL_SIG\x10\x02*\xf7\x03\n" + "\n" + "RoundState\x12\x17\n" + "\x13ROUND_STATE_UNKNOWN\x10\x00\x12\x14\n" + @@ -10938,7 +11413,7 @@ const file_daemon_proto_rawDesc = "" + "\x1eVHTLC_RECOVERY_STATE_COMPLETED\x10\t\x12\"\n" + "\x1eVHTLC_RECOVERY_STATE_CANCELLED\x10\n" + "\x12\x1f\n" + - "\x1bVHTLC_RECOVERY_STATE_FAILED\x10\v2\xd2\x1e\n" + + "\x1bVHTLC_RECOVERY_STATE_FAILED\x10\v2\xbb \n" + "\rDaemonService\x12<\n" + "\aGetInfo\x12\x17.waverpc.GetInfoRequest\x1a\x18.waverpc.GetInfoResponse\x12<\n" + "\aGenSeed\x12\x17.waverpc.GenSeedRequest\x1a\x18.waverpc.GenSeedResponse\x12E\n" + @@ -10967,7 +11442,9 @@ const file_daemon_proto_rawDesc = "" + "\fRefreshVTXOs\x12\x1c.waverpc.RefreshVTXOsRequest\x1a\x1d.waverpc.RefreshVTXOsResponse\x12]\n" + "\x12RefreshCustomVTXOs\x12\".waverpc.RefreshCustomVTXOsRequest\x1a#.waverpc.RefreshCustomVTXOsResponse\x12\xb1\x01\n" + ".ListPendingForfeitParticipantSignatureRequests\x12>.waverpc.ListPendingForfeitParticipantSignatureRequestsRequest\x1a?.waverpc.ListPendingForfeitParticipantSignatureRequestsResponse\x12\x8d\x01\n" + - "\"SubmitForfeitParticipantSignatures\x122.waverpc.SubmitForfeitParticipantSignaturesRequest\x1a3.waverpc.SubmitForfeitParticipantSignaturesResponse\x12E\n" + + "\"SubmitForfeitParticipantSignatures\x122.waverpc.SubmitForfeitParticipantSignaturesRequest\x1a3.waverpc.SubmitForfeitParticipantSignaturesResponse\x12\x81\x01\n" + + "\x1eListPendingTreeSigningRequests\x12..waverpc.ListPendingTreeSigningRequestsRequest\x1a/.waverpc.ListPendingTreeSigningRequestsResponse\x12c\n" + + "\x14SubmitTreeSignatures\x12$.waverpc.SubmitTreeSignaturesRequest\x1a%.waverpc.SubmitTreeSignaturesResponse\x12E\n" + "\n" + "LeaveVTXOs\x12\x1a.waverpc.LeaveVTXOsRequest\x1a\x1b.waverpc.LeaveVTXOsResponse\x12H\n" + "\vSendOnChain\x12\x1b.waverpc.SendOnChainRequest\x1a\x1c.waverpc.SendOnChainResponse\x126\n" + @@ -11004,306 +11481,319 @@ func file_daemon_proto_rawDescGZIP() []byte { return file_daemon_proto_rawDescData } -var file_daemon_proto_enumTypes = make([]protoimpl.EnumInfo, 11) -var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 120) +var file_daemon_proto_enumTypes = make([]protoimpl.EnumInfo, 12) +var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 125) var file_daemon_proto_goTypes = []any{ (WalletState)(0), // 0: waverpc.WalletState (VTXOStatus)(0), // 1: waverpc.VTXOStatus (VTXOExpiryStatus)(0), // 2: waverpc.VTXOExpiryStatus (ForfeitSigningRoute)(0), // 3: waverpc.ForfeitSigningRoute - (RoundState)(0), // 4: waverpc.RoundState - (OORSessionDirection)(0), // 5: waverpc.OORSessionDirection - (OORSessionStatus)(0), // 6: waverpc.OORSessionStatus - (UnrollJobStatus)(0), // 7: waverpc.UnrollJobStatus - (VHTLCRecoveryDirection)(0), // 8: waverpc.VHTLCRecoveryDirection - (VHTLCRecoveryAction)(0), // 9: waverpc.VHTLCRecoveryAction - (VHTLCRecoveryState)(0), // 10: waverpc.VHTLCRecoveryState - (*GetInfoRequest)(nil), // 11: waverpc.GetInfoRequest - (*GetInfoResponse)(nil), // 12: waverpc.GetInfoResponse - (*ServerInfo)(nil), // 13: waverpc.ServerInfo - (*GenSeedRequest)(nil), // 14: waverpc.GenSeedRequest - (*GenSeedResponse)(nil), // 15: waverpc.GenSeedResponse - (*InitWalletRequest)(nil), // 16: waverpc.InitWalletRequest - (*InitWalletResponse)(nil), // 17: waverpc.InitWalletResponse - (*UnlockWalletRequest)(nil), // 18: waverpc.UnlockWalletRequest - (*UnlockWalletResponse)(nil), // 19: waverpc.UnlockWalletResponse - (*GetBalanceRequest)(nil), // 20: waverpc.GetBalanceRequest - (*GetBalanceResponse)(nil), // 21: waverpc.GetBalanceResponse - (*VTXOExpiryInfo)(nil), // 22: waverpc.VTXOExpiryInfo - (*VTXO)(nil), // 23: waverpc.VTXO - (*VTXOSettlement)(nil), // 24: waverpc.VTXOSettlement - (*ListVTXOsRequest)(nil), // 25: waverpc.ListVTXOsRequest - (*ListVTXOsResponse)(nil), // 26: waverpc.ListVTXOsResponse - (*NewAddressRequest)(nil), // 27: waverpc.NewAddressRequest - (*NewAddressResponse)(nil), // 28: waverpc.NewAddressResponse - (*NewReceiveScriptRequest)(nil), // 29: waverpc.NewReceiveScriptRequest - (*NewReceiveScriptResponse)(nil), // 30: waverpc.NewReceiveScriptResponse - (*ReceiveAuthKeyRequest)(nil), // 31: waverpc.ReceiveAuthKeyRequest - (*ReceiveAuthKeyResponse)(nil), // 32: waverpc.ReceiveAuthKeyResponse - (*SignReceiveAuthMessageRequest)(nil), // 33: waverpc.SignReceiveAuthMessageRequest - (*SignReceiveAuthMessageResponse)(nil), // 34: waverpc.SignReceiveAuthMessageResponse - (*SignReceiveAuthMessageCompactRequest)(nil), // 35: waverpc.SignReceiveAuthMessageCompactRequest - (*SignReceiveAuthMessageCompactResponse)(nil), // 36: waverpc.SignReceiveAuthMessageCompactResponse - (*ReceiveAuthECDHRequest)(nil), // 37: waverpc.ReceiveAuthECDHRequest - (*ReceiveAuthECDHResponse)(nil), // 38: waverpc.ReceiveAuthECDHResponse - (*GetIndexedVTXOByPkScriptRequest)(nil), // 39: waverpc.GetIndexedVTXOByPkScriptRequest - (*GetIndexedVTXOByPkScriptResponse)(nil), // 40: waverpc.GetIndexedVTXOByPkScriptResponse - (*GetVTXOExpiryInfoRequest)(nil), // 41: waverpc.GetVTXOExpiryInfoRequest - (*GetVTXOExpiryInfoResponse)(nil), // 42: waverpc.GetVTXOExpiryInfoResponse - (*GetIndexedOORSessionByTxidRequest)(nil), // 43: waverpc.GetIndexedOORSessionByTxidRequest - (*GetIndexedOORSessionByTxidResponse)(nil), // 44: waverpc.GetIndexedOORSessionByTxidResponse - (*Output)(nil), // 45: waverpc.Output - (*SendVTXORequest)(nil), // 46: waverpc.SendVTXORequest - (*SendVTXOResponse)(nil), // 47: waverpc.SendVTXOResponse - (*SendOORRequest)(nil), // 48: waverpc.SendOORRequest - (*CustomOORInput)(nil), // 49: waverpc.CustomOORInput - (*TaprootScriptSignature)(nil), // 50: waverpc.TaprootScriptSignature - (*SendOORResponse)(nil), // 51: waverpc.SendOORResponse - (*PrepareOORRequest)(nil), // 52: waverpc.PrepareOORRequest - (*PreparedOORCustomInput)(nil), // 53: waverpc.PreparedOORCustomInput - (*PrepareOORResponse)(nil), // 54: waverpc.PrepareOORResponse - (*SignOORCustomInputRequest)(nil), // 55: waverpc.SignOORCustomInputRequest - (*SignOORCustomInputResponse)(nil), // 56: waverpc.SignOORCustomInputResponse - (*SignVTXOForfeitRequest)(nil), // 57: waverpc.SignVTXOForfeitRequest - (*SignVTXOForfeitResponse)(nil), // 58: waverpc.SignVTXOForfeitResponse - (*ForfeitSigningContext)(nil), // 59: waverpc.ForfeitSigningContext - (*OutpointSelection)(nil), // 60: waverpc.OutpointSelection - (*RefreshVTXOsRequest)(nil), // 61: waverpc.RefreshVTXOsRequest - (*RefreshVTXOsResponse)(nil), // 62: waverpc.RefreshVTXOsResponse - (*RefreshFeeEstimate)(nil), // 63: waverpc.RefreshFeeEstimate - (*OutpointFeeEstimate)(nil), // 64: waverpc.OutpointFeeEstimate - (*CustomRefreshVTXOInput)(nil), // 65: waverpc.CustomRefreshVTXOInput - (*CustomRefreshVTXOOutput)(nil), // 66: waverpc.CustomRefreshVTXOOutput - (*RefreshCustomVTXOsRequest)(nil), // 67: waverpc.RefreshCustomVTXOsRequest - (*RefreshCustomVTXOsResponse)(nil), // 68: waverpc.RefreshCustomVTXOsResponse - (*PendingForfeitParticipantSignatureRequest)(nil), // 69: waverpc.PendingForfeitParticipantSignatureRequest - (*ListPendingForfeitParticipantSignatureRequestsRequest)(nil), // 70: waverpc.ListPendingForfeitParticipantSignatureRequestsRequest - (*ListPendingForfeitParticipantSignatureRequestsResponse)(nil), // 71: waverpc.ListPendingForfeitParticipantSignatureRequestsResponse - (*ForfeitParticipantSignature)(nil), // 72: waverpc.ForfeitParticipantSignature - (*SubmitForfeitParticipantSignaturesRequest)(nil), // 73: waverpc.SubmitForfeitParticipantSignaturesRequest - (*SubmitForfeitParticipantSignaturesResponse)(nil), // 74: waverpc.SubmitForfeitParticipantSignaturesResponse - (*LeaveDestination)(nil), // 75: waverpc.LeaveDestination - (*LeaveVTXOsRequest)(nil), // 76: waverpc.LeaveVTXOsRequest - (*LeaveVTXOsResponse)(nil), // 77: waverpc.LeaveVTXOsResponse - (*SendOnChainRequest)(nil), // 78: waverpc.SendOnChainRequest - (*SendOnChainResponse)(nil), // 79: waverpc.SendOnChainResponse - (*BoardRequest)(nil), // 80: waverpc.BoardRequest - (*BoardResponse)(nil), // 81: waverpc.BoardResponse - (*JoinNextRoundRequest)(nil), // 82: waverpc.JoinNextRoundRequest - (*JoinNextRoundResponse)(nil), // 83: waverpc.JoinNextRoundResponse - (*SweepBoardingUTXOsRequest)(nil), // 84: waverpc.SweepBoardingUTXOsRequest - (*BoardingSweepOutput)(nil), // 85: waverpc.BoardingSweepOutput - (*SweepBoardingUTXOsResponse)(nil), // 86: waverpc.SweepBoardingUTXOsResponse - (*ListBoardingSweepsRequest)(nil), // 87: waverpc.ListBoardingSweepsRequest - (*BoardingSweepInput)(nil), // 88: waverpc.BoardingSweepInput - (*BoardingSweep)(nil), // 89: waverpc.BoardingSweep - (*ListBoardingSweepsResponse)(nil), // 90: waverpc.ListBoardingSweepsResponse - (*RoundVTXOInfo)(nil), // 91: waverpc.RoundVTXOInfo - (*RoundInfo)(nil), // 92: waverpc.RoundInfo - (*ListRoundsRequest)(nil), // 93: waverpc.ListRoundsRequest - (*GetRoundRequest)(nil), // 94: waverpc.GetRoundRequest - (*GetRoundResponse)(nil), // 95: waverpc.GetRoundResponse - (*ListRoundsResponse)(nil), // 96: waverpc.ListRoundsResponse - (*WatchRoundsRequest)(nil), // 97: waverpc.WatchRoundsRequest - (*WatchRoundsResponse)(nil), // 98: waverpc.WatchRoundsResponse - (*OORSessionInfo)(nil), // 99: waverpc.OORSessionInfo - (*ListOORSessionsRequest)(nil), // 100: waverpc.ListOORSessionsRequest - (*ListOORSessionsResponse)(nil), // 101: waverpc.ListOORSessionsResponse - (*GetOORSessionRequest)(nil), // 102: waverpc.GetOORSessionRequest - (*GetOORSessionResponse)(nil), // 103: waverpc.GetOORSessionResponse - (*EstimateFeeRequest)(nil), // 104: waverpc.EstimateFeeRequest - (*EstimateFeeResponse)(nil), // 105: waverpc.EstimateFeeResponse - (*GetFeeHistoryRequest)(nil), // 106: waverpc.GetFeeHistoryRequest - (*FeeHistoryEntry)(nil), // 107: waverpc.FeeHistoryEntry - (*GetFeeHistoryResponse)(nil), // 108: waverpc.GetFeeHistoryResponse - (*ListTransactionsRequest)(nil), // 109: waverpc.ListTransactionsRequest - (*TransactionHistoryEntry)(nil), // 110: waverpc.TransactionHistoryEntry - (*ListTransactionsResponse)(nil), // 111: waverpc.ListTransactionsResponse - (*UnrollRequest)(nil), // 112: waverpc.UnrollRequest - (*UnrollResponse)(nil), // 113: waverpc.UnrollResponse - (*GetUnrollStatusRequest)(nil), // 114: waverpc.GetUnrollStatusRequest - (*UnrollProgress)(nil), // 115: waverpc.UnrollProgress - (*UnrollCSV)(nil), // 116: waverpc.UnrollCSV - (*UnrollFees)(nil), // 117: waverpc.UnrollFees - (*GetUnrollStatusResponse)(nil), // 118: waverpc.GetUnrollStatusResponse - (*ArmVHTLCRecoveryRequest)(nil), // 119: waverpc.ArmVHTLCRecoveryRequest - (*ArmVHTLCRecoveryResponse)(nil), // 120: waverpc.ArmVHTLCRecoveryResponse - (*EscalateVHTLCRecoveryRequest)(nil), // 121: waverpc.EscalateVHTLCRecoveryRequest - (*EscalateVHTLCRecoveryResponse)(nil), // 122: waverpc.EscalateVHTLCRecoveryResponse - (*CancelVHTLCRecoveryRequest)(nil), // 123: waverpc.CancelVHTLCRecoveryRequest - (*CancelVHTLCRecoveryResponse)(nil), // 124: waverpc.CancelVHTLCRecoveryResponse - (*GetVHTLCRecoveryStatusRequest)(nil), // 125: waverpc.GetVHTLCRecoveryStatusRequest - (*GetVHTLCRecoveryStatusResponse)(nil), // 126: waverpc.GetVHTLCRecoveryStatusResponse - (*ListVHTLCRecoveriesRequest)(nil), // 127: waverpc.ListVHTLCRecoveriesRequest - (*ListVHTLCRecoveriesResponse)(nil), // 128: waverpc.ListVHTLCRecoveriesResponse - (*VHTLCRecoveryStatus)(nil), // 129: waverpc.VHTLCRecoveryStatus - nil, // 130: waverpc.LeaveVTXOsRequest.DestinationsEntry + (TreeSigningRound)(0), // 4: waverpc.TreeSigningRound + (RoundState)(0), // 5: waverpc.RoundState + (OORSessionDirection)(0), // 6: waverpc.OORSessionDirection + (OORSessionStatus)(0), // 7: waverpc.OORSessionStatus + (UnrollJobStatus)(0), // 8: waverpc.UnrollJobStatus + (VHTLCRecoveryDirection)(0), // 9: waverpc.VHTLCRecoveryDirection + (VHTLCRecoveryAction)(0), // 10: waverpc.VHTLCRecoveryAction + (VHTLCRecoveryState)(0), // 11: waverpc.VHTLCRecoveryState + (*GetInfoRequest)(nil), // 12: waverpc.GetInfoRequest + (*GetInfoResponse)(nil), // 13: waverpc.GetInfoResponse + (*ServerInfo)(nil), // 14: waverpc.ServerInfo + (*GenSeedRequest)(nil), // 15: waverpc.GenSeedRequest + (*GenSeedResponse)(nil), // 16: waverpc.GenSeedResponse + (*InitWalletRequest)(nil), // 17: waverpc.InitWalletRequest + (*InitWalletResponse)(nil), // 18: waverpc.InitWalletResponse + (*UnlockWalletRequest)(nil), // 19: waverpc.UnlockWalletRequest + (*UnlockWalletResponse)(nil), // 20: waverpc.UnlockWalletResponse + (*GetBalanceRequest)(nil), // 21: waverpc.GetBalanceRequest + (*GetBalanceResponse)(nil), // 22: waverpc.GetBalanceResponse + (*VTXOExpiryInfo)(nil), // 23: waverpc.VTXOExpiryInfo + (*VTXO)(nil), // 24: waverpc.VTXO + (*VTXOSettlement)(nil), // 25: waverpc.VTXOSettlement + (*ListVTXOsRequest)(nil), // 26: waverpc.ListVTXOsRequest + (*ListVTXOsResponse)(nil), // 27: waverpc.ListVTXOsResponse + (*NewAddressRequest)(nil), // 28: waverpc.NewAddressRequest + (*NewAddressResponse)(nil), // 29: waverpc.NewAddressResponse + (*NewReceiveScriptRequest)(nil), // 30: waverpc.NewReceiveScriptRequest + (*NewReceiveScriptResponse)(nil), // 31: waverpc.NewReceiveScriptResponse + (*ReceiveAuthKeyRequest)(nil), // 32: waverpc.ReceiveAuthKeyRequest + (*ReceiveAuthKeyResponse)(nil), // 33: waverpc.ReceiveAuthKeyResponse + (*SignReceiveAuthMessageRequest)(nil), // 34: waverpc.SignReceiveAuthMessageRequest + (*SignReceiveAuthMessageResponse)(nil), // 35: waverpc.SignReceiveAuthMessageResponse + (*SignReceiveAuthMessageCompactRequest)(nil), // 36: waverpc.SignReceiveAuthMessageCompactRequest + (*SignReceiveAuthMessageCompactResponse)(nil), // 37: waverpc.SignReceiveAuthMessageCompactResponse + (*ReceiveAuthECDHRequest)(nil), // 38: waverpc.ReceiveAuthECDHRequest + (*ReceiveAuthECDHResponse)(nil), // 39: waverpc.ReceiveAuthECDHResponse + (*GetIndexedVTXOByPkScriptRequest)(nil), // 40: waverpc.GetIndexedVTXOByPkScriptRequest + (*GetIndexedVTXOByPkScriptResponse)(nil), // 41: waverpc.GetIndexedVTXOByPkScriptResponse + (*GetVTXOExpiryInfoRequest)(nil), // 42: waverpc.GetVTXOExpiryInfoRequest + (*GetVTXOExpiryInfoResponse)(nil), // 43: waverpc.GetVTXOExpiryInfoResponse + (*GetIndexedOORSessionByTxidRequest)(nil), // 44: waverpc.GetIndexedOORSessionByTxidRequest + (*GetIndexedOORSessionByTxidResponse)(nil), // 45: waverpc.GetIndexedOORSessionByTxidResponse + (*Output)(nil), // 46: waverpc.Output + (*SendVTXORequest)(nil), // 47: waverpc.SendVTXORequest + (*SendVTXOResponse)(nil), // 48: waverpc.SendVTXOResponse + (*SendOORRequest)(nil), // 49: waverpc.SendOORRequest + (*CustomOORInput)(nil), // 50: waverpc.CustomOORInput + (*TaprootScriptSignature)(nil), // 51: waverpc.TaprootScriptSignature + (*SendOORResponse)(nil), // 52: waverpc.SendOORResponse + (*PrepareOORRequest)(nil), // 53: waverpc.PrepareOORRequest + (*PreparedOORCustomInput)(nil), // 54: waverpc.PreparedOORCustomInput + (*PrepareOORResponse)(nil), // 55: waverpc.PrepareOORResponse + (*SignOORCustomInputRequest)(nil), // 56: waverpc.SignOORCustomInputRequest + (*SignOORCustomInputResponse)(nil), // 57: waverpc.SignOORCustomInputResponse + (*SignVTXOForfeitRequest)(nil), // 58: waverpc.SignVTXOForfeitRequest + (*SignVTXOForfeitResponse)(nil), // 59: waverpc.SignVTXOForfeitResponse + (*ForfeitSigningContext)(nil), // 60: waverpc.ForfeitSigningContext + (*OutpointSelection)(nil), // 61: waverpc.OutpointSelection + (*RefreshVTXOsRequest)(nil), // 62: waverpc.RefreshVTXOsRequest + (*RefreshVTXOsResponse)(nil), // 63: waverpc.RefreshVTXOsResponse + (*RefreshFeeEstimate)(nil), // 64: waverpc.RefreshFeeEstimate + (*OutpointFeeEstimate)(nil), // 65: waverpc.OutpointFeeEstimate + (*CustomRefreshVTXOInput)(nil), // 66: waverpc.CustomRefreshVTXOInput + (*CustomRefreshVTXOOutput)(nil), // 67: waverpc.CustomRefreshVTXOOutput + (*RefreshCustomVTXOsRequest)(nil), // 68: waverpc.RefreshCustomVTXOsRequest + (*RefreshCustomVTXOsResponse)(nil), // 69: waverpc.RefreshCustomVTXOsResponse + (*PendingForfeitParticipantSignatureRequest)(nil), // 70: waverpc.PendingForfeitParticipantSignatureRequest + (*ListPendingForfeitParticipantSignatureRequestsRequest)(nil), // 71: waverpc.ListPendingForfeitParticipantSignatureRequestsRequest + (*ListPendingForfeitParticipantSignatureRequestsResponse)(nil), // 72: waverpc.ListPendingForfeitParticipantSignatureRequestsResponse + (*ForfeitParticipantSignature)(nil), // 73: waverpc.ForfeitParticipantSignature + (*SubmitForfeitParticipantSignaturesRequest)(nil), // 74: waverpc.SubmitForfeitParticipantSignaturesRequest + (*SubmitForfeitParticipantSignaturesResponse)(nil), // 75: waverpc.SubmitForfeitParticipantSignaturesResponse + (*PendingTreeSigningRequest)(nil), // 76: waverpc.PendingTreeSigningRequest + (*ListPendingTreeSigningRequestsRequest)(nil), // 77: waverpc.ListPendingTreeSigningRequestsRequest + (*ListPendingTreeSigningRequestsResponse)(nil), // 78: waverpc.ListPendingTreeSigningRequestsResponse + (*SubmitTreeSignaturesRequest)(nil), // 79: waverpc.SubmitTreeSignaturesRequest + (*SubmitTreeSignaturesResponse)(nil), // 80: waverpc.SubmitTreeSignaturesResponse + (*LeaveDestination)(nil), // 81: waverpc.LeaveDestination + (*LeaveVTXOsRequest)(nil), // 82: waverpc.LeaveVTXOsRequest + (*LeaveVTXOsResponse)(nil), // 83: waverpc.LeaveVTXOsResponse + (*SendOnChainRequest)(nil), // 84: waverpc.SendOnChainRequest + (*SendOnChainResponse)(nil), // 85: waverpc.SendOnChainResponse + (*BoardRequest)(nil), // 86: waverpc.BoardRequest + (*BoardResponse)(nil), // 87: waverpc.BoardResponse + (*JoinNextRoundRequest)(nil), // 88: waverpc.JoinNextRoundRequest + (*JoinNextRoundResponse)(nil), // 89: waverpc.JoinNextRoundResponse + (*SweepBoardingUTXOsRequest)(nil), // 90: waverpc.SweepBoardingUTXOsRequest + (*BoardingSweepOutput)(nil), // 91: waverpc.BoardingSweepOutput + (*SweepBoardingUTXOsResponse)(nil), // 92: waverpc.SweepBoardingUTXOsResponse + (*ListBoardingSweepsRequest)(nil), // 93: waverpc.ListBoardingSweepsRequest + (*BoardingSweepInput)(nil), // 94: waverpc.BoardingSweepInput + (*BoardingSweep)(nil), // 95: waverpc.BoardingSweep + (*ListBoardingSweepsResponse)(nil), // 96: waverpc.ListBoardingSweepsResponse + (*RoundVTXOInfo)(nil), // 97: waverpc.RoundVTXOInfo + (*RoundInfo)(nil), // 98: waverpc.RoundInfo + (*ListRoundsRequest)(nil), // 99: waverpc.ListRoundsRequest + (*GetRoundRequest)(nil), // 100: waverpc.GetRoundRequest + (*GetRoundResponse)(nil), // 101: waverpc.GetRoundResponse + (*ListRoundsResponse)(nil), // 102: waverpc.ListRoundsResponse + (*WatchRoundsRequest)(nil), // 103: waverpc.WatchRoundsRequest + (*WatchRoundsResponse)(nil), // 104: waverpc.WatchRoundsResponse + (*OORSessionInfo)(nil), // 105: waverpc.OORSessionInfo + (*ListOORSessionsRequest)(nil), // 106: waverpc.ListOORSessionsRequest + (*ListOORSessionsResponse)(nil), // 107: waverpc.ListOORSessionsResponse + (*GetOORSessionRequest)(nil), // 108: waverpc.GetOORSessionRequest + (*GetOORSessionResponse)(nil), // 109: waverpc.GetOORSessionResponse + (*EstimateFeeRequest)(nil), // 110: waverpc.EstimateFeeRequest + (*EstimateFeeResponse)(nil), // 111: waverpc.EstimateFeeResponse + (*GetFeeHistoryRequest)(nil), // 112: waverpc.GetFeeHistoryRequest + (*FeeHistoryEntry)(nil), // 113: waverpc.FeeHistoryEntry + (*GetFeeHistoryResponse)(nil), // 114: waverpc.GetFeeHistoryResponse + (*ListTransactionsRequest)(nil), // 115: waverpc.ListTransactionsRequest + (*TransactionHistoryEntry)(nil), // 116: waverpc.TransactionHistoryEntry + (*ListTransactionsResponse)(nil), // 117: waverpc.ListTransactionsResponse + (*UnrollRequest)(nil), // 118: waverpc.UnrollRequest + (*UnrollResponse)(nil), // 119: waverpc.UnrollResponse + (*GetUnrollStatusRequest)(nil), // 120: waverpc.GetUnrollStatusRequest + (*UnrollProgress)(nil), // 121: waverpc.UnrollProgress + (*UnrollCSV)(nil), // 122: waverpc.UnrollCSV + (*UnrollFees)(nil), // 123: waverpc.UnrollFees + (*GetUnrollStatusResponse)(nil), // 124: waverpc.GetUnrollStatusResponse + (*ArmVHTLCRecoveryRequest)(nil), // 125: waverpc.ArmVHTLCRecoveryRequest + (*ArmVHTLCRecoveryResponse)(nil), // 126: waverpc.ArmVHTLCRecoveryResponse + (*EscalateVHTLCRecoveryRequest)(nil), // 127: waverpc.EscalateVHTLCRecoveryRequest + (*EscalateVHTLCRecoveryResponse)(nil), // 128: waverpc.EscalateVHTLCRecoveryResponse + (*CancelVHTLCRecoveryRequest)(nil), // 129: waverpc.CancelVHTLCRecoveryRequest + (*CancelVHTLCRecoveryResponse)(nil), // 130: waverpc.CancelVHTLCRecoveryResponse + (*GetVHTLCRecoveryStatusRequest)(nil), // 131: waverpc.GetVHTLCRecoveryStatusRequest + (*GetVHTLCRecoveryStatusResponse)(nil), // 132: waverpc.GetVHTLCRecoveryStatusResponse + (*ListVHTLCRecoveriesRequest)(nil), // 133: waverpc.ListVHTLCRecoveriesRequest + (*ListVHTLCRecoveriesResponse)(nil), // 134: waverpc.ListVHTLCRecoveriesResponse + (*VHTLCRecoveryStatus)(nil), // 135: waverpc.VHTLCRecoveryStatus + nil, // 136: waverpc.LeaveVTXOsRequest.DestinationsEntry } var file_daemon_proto_depIdxs = []int32{ 0, // 0: waverpc.GetInfoResponse.wallet_state:type_name -> waverpc.WalletState - 13, // 1: waverpc.GetInfoResponse.server_info:type_name -> waverpc.ServerInfo + 14, // 1: waverpc.GetInfoResponse.server_info:type_name -> waverpc.ServerInfo 2, // 2: waverpc.VTXOExpiryInfo.status:type_name -> waverpc.VTXOExpiryStatus 1, // 3: waverpc.VTXO.status:type_name -> waverpc.VTXOStatus - 22, // 4: waverpc.VTXO.expiry_info:type_name -> waverpc.VTXOExpiryInfo - 24, // 5: waverpc.VTXO.settlement:type_name -> waverpc.VTXOSettlement + 23, // 4: waverpc.VTXO.expiry_info:type_name -> waverpc.VTXOExpiryInfo + 25, // 5: waverpc.VTXO.settlement:type_name -> waverpc.VTXOSettlement 1, // 6: waverpc.ListVTXOsRequest.status_filter:type_name -> waverpc.VTXOStatus - 23, // 7: waverpc.ListVTXOsResponse.vtxos:type_name -> waverpc.VTXO + 24, // 7: waverpc.ListVTXOsResponse.vtxos:type_name -> waverpc.VTXO 1, // 8: waverpc.GetIndexedVTXOByPkScriptRequest.status_filter:type_name -> waverpc.VTXOStatus - 23, // 9: waverpc.GetIndexedVTXOByPkScriptResponse.vtxo:type_name -> waverpc.VTXO + 24, // 9: waverpc.GetIndexedVTXOByPkScriptResponse.vtxo:type_name -> waverpc.VTXO 1, // 10: waverpc.GetVTXOExpiryInfoRequest.status_filter:type_name -> waverpc.VTXOStatus - 22, // 11: waverpc.GetVTXOExpiryInfoResponse.expiry_info:type_name -> waverpc.VTXOExpiryInfo - 23, // 12: waverpc.GetVTXOExpiryInfoResponse.vtxo:type_name -> waverpc.VTXO - 45, // 13: waverpc.SendVTXORequest.recipients:type_name -> waverpc.Output - 45, // 14: waverpc.SendOORRequest.recipients:type_name -> waverpc.Output - 49, // 15: waverpc.SendOORRequest.custom_inputs:type_name -> waverpc.CustomOORInput - 50, // 16: waverpc.CustomOORInput.external_signatures:type_name -> waverpc.TaprootScriptSignature - 45, // 17: waverpc.PrepareOORRequest.recipient:type_name -> waverpc.Output - 49, // 18: waverpc.PrepareOORRequest.custom_inputs:type_name -> waverpc.CustomOORInput - 53, // 19: waverpc.PrepareOORResponse.custom_inputs:type_name -> waverpc.PreparedOORCustomInput - 49, // 20: waverpc.SignOORCustomInputRequest.custom_input:type_name -> waverpc.CustomOORInput - 50, // 21: waverpc.SignOORCustomInputResponse.signature:type_name -> waverpc.TaprootScriptSignature + 23, // 11: waverpc.GetVTXOExpiryInfoResponse.expiry_info:type_name -> waverpc.VTXOExpiryInfo + 24, // 12: waverpc.GetVTXOExpiryInfoResponse.vtxo:type_name -> waverpc.VTXO + 46, // 13: waverpc.SendVTXORequest.recipients:type_name -> waverpc.Output + 46, // 14: waverpc.SendOORRequest.recipients:type_name -> waverpc.Output + 50, // 15: waverpc.SendOORRequest.custom_inputs:type_name -> waverpc.CustomOORInput + 51, // 16: waverpc.CustomOORInput.external_signatures:type_name -> waverpc.TaprootScriptSignature + 46, // 17: waverpc.PrepareOORRequest.recipient:type_name -> waverpc.Output + 50, // 18: waverpc.PrepareOORRequest.custom_inputs:type_name -> waverpc.CustomOORInput + 54, // 19: waverpc.PrepareOORResponse.custom_inputs:type_name -> waverpc.PreparedOORCustomInput + 50, // 20: waverpc.SignOORCustomInputRequest.custom_input:type_name -> waverpc.CustomOORInput + 51, // 21: waverpc.SignOORCustomInputResponse.signature:type_name -> waverpc.TaprootScriptSignature 3, // 22: waverpc.ForfeitSigningContext.signing_route:type_name -> waverpc.ForfeitSigningRoute - 60, // 23: waverpc.RefreshVTXOsRequest.outpoints:type_name -> waverpc.OutpointSelection - 63, // 24: waverpc.RefreshVTXOsResponse.fee_estimate:type_name -> waverpc.RefreshFeeEstimate - 64, // 25: waverpc.RefreshFeeEstimate.outpoints:type_name -> waverpc.OutpointFeeEstimate - 59, // 26: waverpc.CustomRefreshVTXOInput.forfeit_signing_context:type_name -> waverpc.ForfeitSigningContext - 65, // 27: waverpc.RefreshCustomVTXOsRequest.inputs:type_name -> waverpc.CustomRefreshVTXOInput - 66, // 28: waverpc.RefreshCustomVTXOsRequest.outputs:type_name -> waverpc.CustomRefreshVTXOOutput + 61, // 23: waverpc.RefreshVTXOsRequest.outpoints:type_name -> waverpc.OutpointSelection + 64, // 24: waverpc.RefreshVTXOsResponse.fee_estimate:type_name -> waverpc.RefreshFeeEstimate + 65, // 25: waverpc.RefreshFeeEstimate.outpoints:type_name -> waverpc.OutpointFeeEstimate + 60, // 26: waverpc.CustomRefreshVTXOInput.forfeit_signing_context:type_name -> waverpc.ForfeitSigningContext + 66, // 27: waverpc.RefreshCustomVTXOsRequest.inputs:type_name -> waverpc.CustomRefreshVTXOInput + 67, // 28: waverpc.RefreshCustomVTXOsRequest.outputs:type_name -> waverpc.CustomRefreshVTXOOutput 3, // 29: waverpc.PendingForfeitParticipantSignatureRequest.signing_route:type_name -> waverpc.ForfeitSigningRoute - 69, // 30: waverpc.ListPendingForfeitParticipantSignatureRequestsResponse.requests:type_name -> waverpc.PendingForfeitParticipantSignatureRequest - 72, // 31: waverpc.SubmitForfeitParticipantSignaturesRequest.signatures:type_name -> waverpc.ForfeitParticipantSignature - 60, // 32: waverpc.LeaveVTXOsRequest.outpoints:type_name -> waverpc.OutpointSelection - 75, // 33: waverpc.LeaveVTXOsRequest.default_destination:type_name -> waverpc.LeaveDestination - 130, // 34: waverpc.LeaveVTXOsRequest.destinations:type_name -> waverpc.LeaveVTXOsRequest.DestinationsEntry - 75, // 35: waverpc.SendOnChainRequest.destination:type_name -> waverpc.LeaveDestination - 85, // 36: waverpc.SweepBoardingUTXOsResponse.sweepable_outputs:type_name -> waverpc.BoardingSweepOutput - 88, // 37: waverpc.BoardingSweep.inputs:type_name -> waverpc.BoardingSweepInput - 89, // 38: waverpc.ListBoardingSweepsResponse.sweeps:type_name -> waverpc.BoardingSweep - 4, // 39: waverpc.RoundInfo.state:type_name -> waverpc.RoundState - 91, // 40: waverpc.RoundInfo.vtxos:type_name -> waverpc.RoundVTXOInfo - 4, // 41: waverpc.ListRoundsRequest.state_filter:type_name -> waverpc.RoundState - 92, // 42: waverpc.GetRoundResponse.round:type_name -> waverpc.RoundInfo - 92, // 43: waverpc.ListRoundsResponse.rounds:type_name -> waverpc.RoundInfo - 92, // 44: waverpc.WatchRoundsResponse.round:type_name -> waverpc.RoundInfo - 5, // 45: waverpc.OORSessionInfo.direction:type_name -> waverpc.OORSessionDirection - 6, // 46: waverpc.OORSessionInfo.status:type_name -> waverpc.OORSessionStatus - 5, // 47: waverpc.ListOORSessionsRequest.direction_filter:type_name -> waverpc.OORSessionDirection - 6, // 48: waverpc.ListOORSessionsRequest.status_filter:type_name -> waverpc.OORSessionStatus - 99, // 49: waverpc.ListOORSessionsResponse.sessions:type_name -> waverpc.OORSessionInfo - 99, // 50: waverpc.GetOORSessionResponse.session:type_name -> waverpc.OORSessionInfo - 107, // 51: waverpc.GetFeeHistoryResponse.entries:type_name -> waverpc.FeeHistoryEntry - 110, // 52: waverpc.ListTransactionsResponse.transactions:type_name -> waverpc.TransactionHistoryEntry - 7, // 53: waverpc.GetUnrollStatusResponse.status:type_name -> waverpc.UnrollJobStatus - 115, // 54: waverpc.GetUnrollStatusResponse.progress:type_name -> waverpc.UnrollProgress - 116, // 55: waverpc.GetUnrollStatusResponse.csv:type_name -> waverpc.UnrollCSV - 117, // 56: waverpc.GetUnrollStatusResponse.fees:type_name -> waverpc.UnrollFees - 8, // 57: waverpc.ArmVHTLCRecoveryRequest.direction:type_name -> waverpc.VHTLCRecoveryDirection - 9, // 58: waverpc.ArmVHTLCRecoveryRequest.action:type_name -> waverpc.VHTLCRecoveryAction - 129, // 59: waverpc.ArmVHTLCRecoveryResponse.status:type_name -> waverpc.VHTLCRecoveryStatus - 129, // 60: waverpc.EscalateVHTLCRecoveryResponse.status:type_name -> waverpc.VHTLCRecoveryStatus - 129, // 61: waverpc.CancelVHTLCRecoveryResponse.status:type_name -> waverpc.VHTLCRecoveryStatus - 129, // 62: waverpc.GetVHTLCRecoveryStatusResponse.status:type_name -> waverpc.VHTLCRecoveryStatus - 129, // 63: waverpc.ListVHTLCRecoveriesResponse.statuses:type_name -> waverpc.VHTLCRecoveryStatus - 8, // 64: waverpc.VHTLCRecoveryStatus.direction:type_name -> waverpc.VHTLCRecoveryDirection - 9, // 65: waverpc.VHTLCRecoveryStatus.action:type_name -> waverpc.VHTLCRecoveryAction - 10, // 66: waverpc.VHTLCRecoveryStatus.state:type_name -> waverpc.VHTLCRecoveryState - 7, // 67: waverpc.VHTLCRecoveryStatus.unroll_status:type_name -> waverpc.UnrollJobStatus - 75, // 68: waverpc.LeaveVTXOsRequest.DestinationsEntry.value:type_name -> waverpc.LeaveDestination - 11, // 69: waverpc.DaemonService.GetInfo:input_type -> waverpc.GetInfoRequest - 14, // 70: waverpc.DaemonService.GenSeed:input_type -> waverpc.GenSeedRequest - 16, // 71: waverpc.DaemonService.InitWallet:input_type -> waverpc.InitWalletRequest - 18, // 72: waverpc.DaemonService.UnlockWallet:input_type -> waverpc.UnlockWalletRequest - 20, // 73: waverpc.DaemonService.GetBalance:input_type -> waverpc.GetBalanceRequest - 25, // 74: waverpc.DaemonService.ListVTXOs:input_type -> waverpc.ListVTXOsRequest - 27, // 75: waverpc.DaemonService.NewAddress:input_type -> waverpc.NewAddressRequest - 29, // 76: waverpc.DaemonService.NewReceiveScript:input_type -> waverpc.NewReceiveScriptRequest - 31, // 77: waverpc.DaemonService.ReceiveAuthKey:input_type -> waverpc.ReceiveAuthKeyRequest - 33, // 78: waverpc.DaemonService.SignReceiveAuthMessage:input_type -> waverpc.SignReceiveAuthMessageRequest - 35, // 79: waverpc.DaemonService.SignReceiveAuthMessageCompact:input_type -> waverpc.SignReceiveAuthMessageCompactRequest - 37, // 80: waverpc.DaemonService.ReceiveAuthECDH:input_type -> waverpc.ReceiveAuthECDHRequest - 39, // 81: waverpc.DaemonService.GetIndexedVTXOByPkScript:input_type -> waverpc.GetIndexedVTXOByPkScriptRequest - 41, // 82: waverpc.DaemonService.GetVTXOExpiryInfo:input_type -> waverpc.GetVTXOExpiryInfoRequest - 43, // 83: waverpc.DaemonService.GetIndexedOORSessionByTxid:input_type -> waverpc.GetIndexedOORSessionByTxidRequest - 46, // 84: waverpc.DaemonService.SendVTXO:input_type -> waverpc.SendVTXORequest - 48, // 85: waverpc.DaemonService.SendOOR:input_type -> waverpc.SendOORRequest - 52, // 86: waverpc.DaemonService.PrepareOOR:input_type -> waverpc.PrepareOORRequest - 55, // 87: waverpc.DaemonService.SignOORCustomInput:input_type -> waverpc.SignOORCustomInputRequest - 57, // 88: waverpc.DaemonService.SignVTXOForfeit:input_type -> waverpc.SignVTXOForfeitRequest - 61, // 89: waverpc.DaemonService.RefreshVTXOs:input_type -> waverpc.RefreshVTXOsRequest - 67, // 90: waverpc.DaemonService.RefreshCustomVTXOs:input_type -> waverpc.RefreshCustomVTXOsRequest - 70, // 91: waverpc.DaemonService.ListPendingForfeitParticipantSignatureRequests:input_type -> waverpc.ListPendingForfeitParticipantSignatureRequestsRequest - 73, // 92: waverpc.DaemonService.SubmitForfeitParticipantSignatures:input_type -> waverpc.SubmitForfeitParticipantSignaturesRequest - 76, // 93: waverpc.DaemonService.LeaveVTXOs:input_type -> waverpc.LeaveVTXOsRequest - 78, // 94: waverpc.DaemonService.SendOnChain:input_type -> waverpc.SendOnChainRequest - 80, // 95: waverpc.DaemonService.Board:input_type -> waverpc.BoardRequest - 82, // 96: waverpc.DaemonService.JoinNextRound:input_type -> waverpc.JoinNextRoundRequest - 84, // 97: waverpc.DaemonService.SweepBoardingUTXOs:input_type -> waverpc.SweepBoardingUTXOsRequest - 87, // 98: waverpc.DaemonService.ListBoardingSweeps:input_type -> waverpc.ListBoardingSweepsRequest - 93, // 99: waverpc.DaemonService.ListRounds:input_type -> waverpc.ListRoundsRequest - 94, // 100: waverpc.DaemonService.GetRound:input_type -> waverpc.GetRoundRequest - 97, // 101: waverpc.DaemonService.WatchRounds:input_type -> waverpc.WatchRoundsRequest - 100, // 102: waverpc.DaemonService.ListOORSessions:input_type -> waverpc.ListOORSessionsRequest - 102, // 103: waverpc.DaemonService.GetOORSession:input_type -> waverpc.GetOORSessionRequest - 104, // 104: waverpc.DaemonService.EstimateFee:input_type -> waverpc.EstimateFeeRequest - 106, // 105: waverpc.DaemonService.GetFeeHistory:input_type -> waverpc.GetFeeHistoryRequest - 109, // 106: waverpc.DaemonService.ListTransactions:input_type -> waverpc.ListTransactionsRequest - 112, // 107: waverpc.DaemonService.Unroll:input_type -> waverpc.UnrollRequest - 114, // 108: waverpc.DaemonService.GetUnrollStatus:input_type -> waverpc.GetUnrollStatusRequest - 119, // 109: waverpc.DaemonService.ArmVHTLCRecovery:input_type -> waverpc.ArmVHTLCRecoveryRequest - 121, // 110: waverpc.DaemonService.EscalateVHTLCRecovery:input_type -> waverpc.EscalateVHTLCRecoveryRequest - 123, // 111: waverpc.DaemonService.CancelVHTLCRecovery:input_type -> waverpc.CancelVHTLCRecoveryRequest - 125, // 112: waverpc.DaemonService.GetVHTLCRecoveryStatus:input_type -> waverpc.GetVHTLCRecoveryStatusRequest - 127, // 113: waverpc.DaemonService.ListVHTLCRecoveries:input_type -> waverpc.ListVHTLCRecoveriesRequest - 12, // 114: waverpc.DaemonService.GetInfo:output_type -> waverpc.GetInfoResponse - 15, // 115: waverpc.DaemonService.GenSeed:output_type -> waverpc.GenSeedResponse - 17, // 116: waverpc.DaemonService.InitWallet:output_type -> waverpc.InitWalletResponse - 19, // 117: waverpc.DaemonService.UnlockWallet:output_type -> waverpc.UnlockWalletResponse - 21, // 118: waverpc.DaemonService.GetBalance:output_type -> waverpc.GetBalanceResponse - 26, // 119: waverpc.DaemonService.ListVTXOs:output_type -> waverpc.ListVTXOsResponse - 28, // 120: waverpc.DaemonService.NewAddress:output_type -> waverpc.NewAddressResponse - 30, // 121: waverpc.DaemonService.NewReceiveScript:output_type -> waverpc.NewReceiveScriptResponse - 32, // 122: waverpc.DaemonService.ReceiveAuthKey:output_type -> waverpc.ReceiveAuthKeyResponse - 34, // 123: waverpc.DaemonService.SignReceiveAuthMessage:output_type -> waverpc.SignReceiveAuthMessageResponse - 36, // 124: waverpc.DaemonService.SignReceiveAuthMessageCompact:output_type -> waverpc.SignReceiveAuthMessageCompactResponse - 38, // 125: waverpc.DaemonService.ReceiveAuthECDH:output_type -> waverpc.ReceiveAuthECDHResponse - 40, // 126: waverpc.DaemonService.GetIndexedVTXOByPkScript:output_type -> waverpc.GetIndexedVTXOByPkScriptResponse - 42, // 127: waverpc.DaemonService.GetVTXOExpiryInfo:output_type -> waverpc.GetVTXOExpiryInfoResponse - 44, // 128: waverpc.DaemonService.GetIndexedOORSessionByTxid:output_type -> waverpc.GetIndexedOORSessionByTxidResponse - 47, // 129: waverpc.DaemonService.SendVTXO:output_type -> waverpc.SendVTXOResponse - 51, // 130: waverpc.DaemonService.SendOOR:output_type -> waverpc.SendOORResponse - 54, // 131: waverpc.DaemonService.PrepareOOR:output_type -> waverpc.PrepareOORResponse - 56, // 132: waverpc.DaemonService.SignOORCustomInput:output_type -> waverpc.SignOORCustomInputResponse - 58, // 133: waverpc.DaemonService.SignVTXOForfeit:output_type -> waverpc.SignVTXOForfeitResponse - 62, // 134: waverpc.DaemonService.RefreshVTXOs:output_type -> waverpc.RefreshVTXOsResponse - 68, // 135: waverpc.DaemonService.RefreshCustomVTXOs:output_type -> waverpc.RefreshCustomVTXOsResponse - 71, // 136: waverpc.DaemonService.ListPendingForfeitParticipantSignatureRequests:output_type -> waverpc.ListPendingForfeitParticipantSignatureRequestsResponse - 74, // 137: waverpc.DaemonService.SubmitForfeitParticipantSignatures:output_type -> waverpc.SubmitForfeitParticipantSignaturesResponse - 77, // 138: waverpc.DaemonService.LeaveVTXOs:output_type -> waverpc.LeaveVTXOsResponse - 79, // 139: waverpc.DaemonService.SendOnChain:output_type -> waverpc.SendOnChainResponse - 81, // 140: waverpc.DaemonService.Board:output_type -> waverpc.BoardResponse - 83, // 141: waverpc.DaemonService.JoinNextRound:output_type -> waverpc.JoinNextRoundResponse - 86, // 142: waverpc.DaemonService.SweepBoardingUTXOs:output_type -> waverpc.SweepBoardingUTXOsResponse - 90, // 143: waverpc.DaemonService.ListBoardingSweeps:output_type -> waverpc.ListBoardingSweepsResponse - 96, // 144: waverpc.DaemonService.ListRounds:output_type -> waverpc.ListRoundsResponse - 95, // 145: waverpc.DaemonService.GetRound:output_type -> waverpc.GetRoundResponse - 98, // 146: waverpc.DaemonService.WatchRounds:output_type -> waverpc.WatchRoundsResponse - 101, // 147: waverpc.DaemonService.ListOORSessions:output_type -> waverpc.ListOORSessionsResponse - 103, // 148: waverpc.DaemonService.GetOORSession:output_type -> waverpc.GetOORSessionResponse - 105, // 149: waverpc.DaemonService.EstimateFee:output_type -> waverpc.EstimateFeeResponse - 108, // 150: waverpc.DaemonService.GetFeeHistory:output_type -> waverpc.GetFeeHistoryResponse - 111, // 151: waverpc.DaemonService.ListTransactions:output_type -> waverpc.ListTransactionsResponse - 113, // 152: waverpc.DaemonService.Unroll:output_type -> waverpc.UnrollResponse - 118, // 153: waverpc.DaemonService.GetUnrollStatus:output_type -> waverpc.GetUnrollStatusResponse - 120, // 154: waverpc.DaemonService.ArmVHTLCRecovery:output_type -> waverpc.ArmVHTLCRecoveryResponse - 122, // 155: waverpc.DaemonService.EscalateVHTLCRecovery:output_type -> waverpc.EscalateVHTLCRecoveryResponse - 124, // 156: waverpc.DaemonService.CancelVHTLCRecovery:output_type -> waverpc.CancelVHTLCRecoveryResponse - 126, // 157: waverpc.DaemonService.GetVHTLCRecoveryStatus:output_type -> waverpc.GetVHTLCRecoveryStatusResponse - 128, // 158: waverpc.DaemonService.ListVHTLCRecoveries:output_type -> waverpc.ListVHTLCRecoveriesResponse - 114, // [114:159] is the sub-list for method output_type - 69, // [69:114] is the sub-list for method input_type - 69, // [69:69] is the sub-list for extension type_name - 69, // [69:69] is the sub-list for extension extendee - 0, // [0:69] is the sub-list for field type_name + 70, // 30: waverpc.ListPendingForfeitParticipantSignatureRequestsResponse.requests:type_name -> waverpc.PendingForfeitParticipantSignatureRequest + 73, // 31: waverpc.SubmitForfeitParticipantSignaturesRequest.signatures:type_name -> waverpc.ForfeitParticipantSignature + 4, // 32: waverpc.PendingTreeSigningRequest.round:type_name -> waverpc.TreeSigningRound + 76, // 33: waverpc.ListPendingTreeSigningRequestsResponse.requests:type_name -> waverpc.PendingTreeSigningRequest + 4, // 34: waverpc.SubmitTreeSignaturesRequest.round:type_name -> waverpc.TreeSigningRound + 61, // 35: waverpc.LeaveVTXOsRequest.outpoints:type_name -> waverpc.OutpointSelection + 81, // 36: waverpc.LeaveVTXOsRequest.default_destination:type_name -> waverpc.LeaveDestination + 136, // 37: waverpc.LeaveVTXOsRequest.destinations:type_name -> waverpc.LeaveVTXOsRequest.DestinationsEntry + 81, // 38: waverpc.SendOnChainRequest.destination:type_name -> waverpc.LeaveDestination + 91, // 39: waverpc.SweepBoardingUTXOsResponse.sweepable_outputs:type_name -> waverpc.BoardingSweepOutput + 94, // 40: waverpc.BoardingSweep.inputs:type_name -> waverpc.BoardingSweepInput + 95, // 41: waverpc.ListBoardingSweepsResponse.sweeps:type_name -> waverpc.BoardingSweep + 5, // 42: waverpc.RoundInfo.state:type_name -> waverpc.RoundState + 97, // 43: waverpc.RoundInfo.vtxos:type_name -> waverpc.RoundVTXOInfo + 5, // 44: waverpc.ListRoundsRequest.state_filter:type_name -> waverpc.RoundState + 98, // 45: waverpc.GetRoundResponse.round:type_name -> waverpc.RoundInfo + 98, // 46: waverpc.ListRoundsResponse.rounds:type_name -> waverpc.RoundInfo + 98, // 47: waverpc.WatchRoundsResponse.round:type_name -> waverpc.RoundInfo + 6, // 48: waverpc.OORSessionInfo.direction:type_name -> waverpc.OORSessionDirection + 7, // 49: waverpc.OORSessionInfo.status:type_name -> waverpc.OORSessionStatus + 6, // 50: waverpc.ListOORSessionsRequest.direction_filter:type_name -> waverpc.OORSessionDirection + 7, // 51: waverpc.ListOORSessionsRequest.status_filter:type_name -> waverpc.OORSessionStatus + 105, // 52: waverpc.ListOORSessionsResponse.sessions:type_name -> waverpc.OORSessionInfo + 105, // 53: waverpc.GetOORSessionResponse.session:type_name -> waverpc.OORSessionInfo + 113, // 54: waverpc.GetFeeHistoryResponse.entries:type_name -> waverpc.FeeHistoryEntry + 116, // 55: waverpc.ListTransactionsResponse.transactions:type_name -> waverpc.TransactionHistoryEntry + 8, // 56: waverpc.GetUnrollStatusResponse.status:type_name -> waverpc.UnrollJobStatus + 121, // 57: waverpc.GetUnrollStatusResponse.progress:type_name -> waverpc.UnrollProgress + 122, // 58: waverpc.GetUnrollStatusResponse.csv:type_name -> waverpc.UnrollCSV + 123, // 59: waverpc.GetUnrollStatusResponse.fees:type_name -> waverpc.UnrollFees + 9, // 60: waverpc.ArmVHTLCRecoveryRequest.direction:type_name -> waverpc.VHTLCRecoveryDirection + 10, // 61: waverpc.ArmVHTLCRecoveryRequest.action:type_name -> waverpc.VHTLCRecoveryAction + 135, // 62: waverpc.ArmVHTLCRecoveryResponse.status:type_name -> waverpc.VHTLCRecoveryStatus + 135, // 63: waverpc.EscalateVHTLCRecoveryResponse.status:type_name -> waverpc.VHTLCRecoveryStatus + 135, // 64: waverpc.CancelVHTLCRecoveryResponse.status:type_name -> waverpc.VHTLCRecoveryStatus + 135, // 65: waverpc.GetVHTLCRecoveryStatusResponse.status:type_name -> waverpc.VHTLCRecoveryStatus + 135, // 66: waverpc.ListVHTLCRecoveriesResponse.statuses:type_name -> waverpc.VHTLCRecoveryStatus + 9, // 67: waverpc.VHTLCRecoveryStatus.direction:type_name -> waverpc.VHTLCRecoveryDirection + 10, // 68: waverpc.VHTLCRecoveryStatus.action:type_name -> waverpc.VHTLCRecoveryAction + 11, // 69: waverpc.VHTLCRecoveryStatus.state:type_name -> waverpc.VHTLCRecoveryState + 8, // 70: waverpc.VHTLCRecoveryStatus.unroll_status:type_name -> waverpc.UnrollJobStatus + 81, // 71: waverpc.LeaveVTXOsRequest.DestinationsEntry.value:type_name -> waverpc.LeaveDestination + 12, // 72: waverpc.DaemonService.GetInfo:input_type -> waverpc.GetInfoRequest + 15, // 73: waverpc.DaemonService.GenSeed:input_type -> waverpc.GenSeedRequest + 17, // 74: waverpc.DaemonService.InitWallet:input_type -> waverpc.InitWalletRequest + 19, // 75: waverpc.DaemonService.UnlockWallet:input_type -> waverpc.UnlockWalletRequest + 21, // 76: waverpc.DaemonService.GetBalance:input_type -> waverpc.GetBalanceRequest + 26, // 77: waverpc.DaemonService.ListVTXOs:input_type -> waverpc.ListVTXOsRequest + 28, // 78: waverpc.DaemonService.NewAddress:input_type -> waverpc.NewAddressRequest + 30, // 79: waverpc.DaemonService.NewReceiveScript:input_type -> waverpc.NewReceiveScriptRequest + 32, // 80: waverpc.DaemonService.ReceiveAuthKey:input_type -> waverpc.ReceiveAuthKeyRequest + 34, // 81: waverpc.DaemonService.SignReceiveAuthMessage:input_type -> waverpc.SignReceiveAuthMessageRequest + 36, // 82: waverpc.DaemonService.SignReceiveAuthMessageCompact:input_type -> waverpc.SignReceiveAuthMessageCompactRequest + 38, // 83: waverpc.DaemonService.ReceiveAuthECDH:input_type -> waverpc.ReceiveAuthECDHRequest + 40, // 84: waverpc.DaemonService.GetIndexedVTXOByPkScript:input_type -> waverpc.GetIndexedVTXOByPkScriptRequest + 42, // 85: waverpc.DaemonService.GetVTXOExpiryInfo:input_type -> waverpc.GetVTXOExpiryInfoRequest + 44, // 86: waverpc.DaemonService.GetIndexedOORSessionByTxid:input_type -> waverpc.GetIndexedOORSessionByTxidRequest + 47, // 87: waverpc.DaemonService.SendVTXO:input_type -> waverpc.SendVTXORequest + 49, // 88: waverpc.DaemonService.SendOOR:input_type -> waverpc.SendOORRequest + 53, // 89: waverpc.DaemonService.PrepareOOR:input_type -> waverpc.PrepareOORRequest + 56, // 90: waverpc.DaemonService.SignOORCustomInput:input_type -> waverpc.SignOORCustomInputRequest + 58, // 91: waverpc.DaemonService.SignVTXOForfeit:input_type -> waverpc.SignVTXOForfeitRequest + 62, // 92: waverpc.DaemonService.RefreshVTXOs:input_type -> waverpc.RefreshVTXOsRequest + 68, // 93: waverpc.DaemonService.RefreshCustomVTXOs:input_type -> waverpc.RefreshCustomVTXOsRequest + 71, // 94: waverpc.DaemonService.ListPendingForfeitParticipantSignatureRequests:input_type -> waverpc.ListPendingForfeitParticipantSignatureRequestsRequest + 74, // 95: waverpc.DaemonService.SubmitForfeitParticipantSignatures:input_type -> waverpc.SubmitForfeitParticipantSignaturesRequest + 77, // 96: waverpc.DaemonService.ListPendingTreeSigningRequests:input_type -> waverpc.ListPendingTreeSigningRequestsRequest + 79, // 97: waverpc.DaemonService.SubmitTreeSignatures:input_type -> waverpc.SubmitTreeSignaturesRequest + 82, // 98: waverpc.DaemonService.LeaveVTXOs:input_type -> waverpc.LeaveVTXOsRequest + 84, // 99: waverpc.DaemonService.SendOnChain:input_type -> waverpc.SendOnChainRequest + 86, // 100: waverpc.DaemonService.Board:input_type -> waverpc.BoardRequest + 88, // 101: waverpc.DaemonService.JoinNextRound:input_type -> waverpc.JoinNextRoundRequest + 90, // 102: waverpc.DaemonService.SweepBoardingUTXOs:input_type -> waverpc.SweepBoardingUTXOsRequest + 93, // 103: waverpc.DaemonService.ListBoardingSweeps:input_type -> waverpc.ListBoardingSweepsRequest + 99, // 104: waverpc.DaemonService.ListRounds:input_type -> waverpc.ListRoundsRequest + 100, // 105: waverpc.DaemonService.GetRound:input_type -> waverpc.GetRoundRequest + 103, // 106: waverpc.DaemonService.WatchRounds:input_type -> waverpc.WatchRoundsRequest + 106, // 107: waverpc.DaemonService.ListOORSessions:input_type -> waverpc.ListOORSessionsRequest + 108, // 108: waverpc.DaemonService.GetOORSession:input_type -> waverpc.GetOORSessionRequest + 110, // 109: waverpc.DaemonService.EstimateFee:input_type -> waverpc.EstimateFeeRequest + 112, // 110: waverpc.DaemonService.GetFeeHistory:input_type -> waverpc.GetFeeHistoryRequest + 115, // 111: waverpc.DaemonService.ListTransactions:input_type -> waverpc.ListTransactionsRequest + 118, // 112: waverpc.DaemonService.Unroll:input_type -> waverpc.UnrollRequest + 120, // 113: waverpc.DaemonService.GetUnrollStatus:input_type -> waverpc.GetUnrollStatusRequest + 125, // 114: waverpc.DaemonService.ArmVHTLCRecovery:input_type -> waverpc.ArmVHTLCRecoveryRequest + 127, // 115: waverpc.DaemonService.EscalateVHTLCRecovery:input_type -> waverpc.EscalateVHTLCRecoveryRequest + 129, // 116: waverpc.DaemonService.CancelVHTLCRecovery:input_type -> waverpc.CancelVHTLCRecoveryRequest + 131, // 117: waverpc.DaemonService.GetVHTLCRecoveryStatus:input_type -> waverpc.GetVHTLCRecoveryStatusRequest + 133, // 118: waverpc.DaemonService.ListVHTLCRecoveries:input_type -> waverpc.ListVHTLCRecoveriesRequest + 13, // 119: waverpc.DaemonService.GetInfo:output_type -> waverpc.GetInfoResponse + 16, // 120: waverpc.DaemonService.GenSeed:output_type -> waverpc.GenSeedResponse + 18, // 121: waverpc.DaemonService.InitWallet:output_type -> waverpc.InitWalletResponse + 20, // 122: waverpc.DaemonService.UnlockWallet:output_type -> waverpc.UnlockWalletResponse + 22, // 123: waverpc.DaemonService.GetBalance:output_type -> waverpc.GetBalanceResponse + 27, // 124: waverpc.DaemonService.ListVTXOs:output_type -> waverpc.ListVTXOsResponse + 29, // 125: waverpc.DaemonService.NewAddress:output_type -> waverpc.NewAddressResponse + 31, // 126: waverpc.DaemonService.NewReceiveScript:output_type -> waverpc.NewReceiveScriptResponse + 33, // 127: waverpc.DaemonService.ReceiveAuthKey:output_type -> waverpc.ReceiveAuthKeyResponse + 35, // 128: waverpc.DaemonService.SignReceiveAuthMessage:output_type -> waverpc.SignReceiveAuthMessageResponse + 37, // 129: waverpc.DaemonService.SignReceiveAuthMessageCompact:output_type -> waverpc.SignReceiveAuthMessageCompactResponse + 39, // 130: waverpc.DaemonService.ReceiveAuthECDH:output_type -> waverpc.ReceiveAuthECDHResponse + 41, // 131: waverpc.DaemonService.GetIndexedVTXOByPkScript:output_type -> waverpc.GetIndexedVTXOByPkScriptResponse + 43, // 132: waverpc.DaemonService.GetVTXOExpiryInfo:output_type -> waverpc.GetVTXOExpiryInfoResponse + 45, // 133: waverpc.DaemonService.GetIndexedOORSessionByTxid:output_type -> waverpc.GetIndexedOORSessionByTxidResponse + 48, // 134: waverpc.DaemonService.SendVTXO:output_type -> waverpc.SendVTXOResponse + 52, // 135: waverpc.DaemonService.SendOOR:output_type -> waverpc.SendOORResponse + 55, // 136: waverpc.DaemonService.PrepareOOR:output_type -> waverpc.PrepareOORResponse + 57, // 137: waverpc.DaemonService.SignOORCustomInput:output_type -> waverpc.SignOORCustomInputResponse + 59, // 138: waverpc.DaemonService.SignVTXOForfeit:output_type -> waverpc.SignVTXOForfeitResponse + 63, // 139: waverpc.DaemonService.RefreshVTXOs:output_type -> waverpc.RefreshVTXOsResponse + 69, // 140: waverpc.DaemonService.RefreshCustomVTXOs:output_type -> waverpc.RefreshCustomVTXOsResponse + 72, // 141: waverpc.DaemonService.ListPendingForfeitParticipantSignatureRequests:output_type -> waverpc.ListPendingForfeitParticipantSignatureRequestsResponse + 75, // 142: waverpc.DaemonService.SubmitForfeitParticipantSignatures:output_type -> waverpc.SubmitForfeitParticipantSignaturesResponse + 78, // 143: waverpc.DaemonService.ListPendingTreeSigningRequests:output_type -> waverpc.ListPendingTreeSigningRequestsResponse + 80, // 144: waverpc.DaemonService.SubmitTreeSignatures:output_type -> waverpc.SubmitTreeSignaturesResponse + 83, // 145: waverpc.DaemonService.LeaveVTXOs:output_type -> waverpc.LeaveVTXOsResponse + 85, // 146: waverpc.DaemonService.SendOnChain:output_type -> waverpc.SendOnChainResponse + 87, // 147: waverpc.DaemonService.Board:output_type -> waverpc.BoardResponse + 89, // 148: waverpc.DaemonService.JoinNextRound:output_type -> waverpc.JoinNextRoundResponse + 92, // 149: waverpc.DaemonService.SweepBoardingUTXOs:output_type -> waverpc.SweepBoardingUTXOsResponse + 96, // 150: waverpc.DaemonService.ListBoardingSweeps:output_type -> waverpc.ListBoardingSweepsResponse + 102, // 151: waverpc.DaemonService.ListRounds:output_type -> waverpc.ListRoundsResponse + 101, // 152: waverpc.DaemonService.GetRound:output_type -> waverpc.GetRoundResponse + 104, // 153: waverpc.DaemonService.WatchRounds:output_type -> waverpc.WatchRoundsResponse + 107, // 154: waverpc.DaemonService.ListOORSessions:output_type -> waverpc.ListOORSessionsResponse + 109, // 155: waverpc.DaemonService.GetOORSession:output_type -> waverpc.GetOORSessionResponse + 111, // 156: waverpc.DaemonService.EstimateFee:output_type -> waverpc.EstimateFeeResponse + 114, // 157: waverpc.DaemonService.GetFeeHistory:output_type -> waverpc.GetFeeHistoryResponse + 117, // 158: waverpc.DaemonService.ListTransactions:output_type -> waverpc.ListTransactionsResponse + 119, // 159: waverpc.DaemonService.Unroll:output_type -> waverpc.UnrollResponse + 124, // 160: waverpc.DaemonService.GetUnrollStatus:output_type -> waverpc.GetUnrollStatusResponse + 126, // 161: waverpc.DaemonService.ArmVHTLCRecovery:output_type -> waverpc.ArmVHTLCRecoveryResponse + 128, // 162: waverpc.DaemonService.EscalateVHTLCRecovery:output_type -> waverpc.EscalateVHTLCRecoveryResponse + 130, // 163: waverpc.DaemonService.CancelVHTLCRecovery:output_type -> waverpc.CancelVHTLCRecoveryResponse + 132, // 164: waverpc.DaemonService.GetVHTLCRecoveryStatus:output_type -> waverpc.GetVHTLCRecoveryStatusResponse + 134, // 165: waverpc.DaemonService.ListVHTLCRecoveries:output_type -> waverpc.ListVHTLCRecoveriesResponse + 119, // [119:166] is the sub-list for method output_type + 72, // [72:119] is the sub-list for method input_type + 72, // [72:72] is the sub-list for extension type_name + 72, // [72:72] is the sub-list for extension extendee + 0, // [0:72] is the sub-list for field type_name } func init() { file_daemon_proto_init() } @@ -11325,15 +11815,15 @@ func file_daemon_proto_init() { (*RefreshVTXOsRequest_All)(nil), } file_daemon_proto_msgTypes[52].OneofWrappers = []any{} - file_daemon_proto_msgTypes[64].OneofWrappers = []any{ + file_daemon_proto_msgTypes[69].OneofWrappers = []any{ (*LeaveDestination_Address)(nil), (*LeaveDestination_PkScript)(nil), } - file_daemon_proto_msgTypes[65].OneofWrappers = []any{ + file_daemon_proto_msgTypes[70].OneofWrappers = []any{ (*LeaveVTXOsRequest_Outpoints)(nil), (*LeaveVTXOsRequest_All)(nil), } - file_daemon_proto_msgTypes[67].OneofWrappers = []any{ + file_daemon_proto_msgTypes[72].OneofWrappers = []any{ (*SendOnChainRequest_AmountSat)(nil), (*SendOnChainRequest_SweepAll)(nil), } @@ -11342,8 +11832,8 @@ func file_daemon_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_daemon_proto_rawDesc), len(file_daemon_proto_rawDesc)), - NumEnums: 11, - NumMessages: 120, + NumEnums: 12, + NumMessages: 125, NumExtensions: 0, NumServices: 1, }, diff --git a/waverpc/daemon.pb.gw.go b/waverpc/daemon.pb.gw.go index ab521202c..ac73f3d9a 100644 --- a/waverpc/daemon.pb.gw.go +++ b/waverpc/daemon.pb.gw.go @@ -683,6 +683,60 @@ func local_request_DaemonService_SubmitForfeitParticipantSignatures_0(ctx contex return msg, metadata, err } +func request_DaemonService_ListPendingTreeSigningRequests_0(ctx context.Context, marshaler runtime.Marshaler, client DaemonServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListPendingTreeSigningRequestsRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.ListPendingTreeSigningRequests(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_DaemonService_ListPendingTreeSigningRequests_0(ctx context.Context, marshaler runtime.Marshaler, server DaemonServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListPendingTreeSigningRequestsRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.ListPendingTreeSigningRequests(ctx, &protoReq) + return msg, metadata, err +} + +func request_DaemonService_SubmitTreeSignatures_0(ctx context.Context, marshaler runtime.Marshaler, client DaemonServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq SubmitTreeSignaturesRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.SubmitTreeSignatures(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_DaemonService_SubmitTreeSignatures_0(ctx context.Context, marshaler runtime.Marshaler, server DaemonServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq SubmitTreeSignaturesRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.SubmitTreeSignatures(ctx, &protoReq) + return msg, metadata, err +} + func request_DaemonService_LeaveVTXOs_0(ctx context.Context, marshaler runtime.Marshaler, client DaemonServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq LeaveVTXOsRequest @@ -1732,6 +1786,46 @@ func RegisterDaemonServiceHandlerServer(ctx context.Context, mux *runtime.ServeM } forward_DaemonService_SubmitForfeitParticipantSignatures_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_DaemonService_ListPendingTreeSigningRequests_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) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/waverpc.DaemonService/ListPendingTreeSigningRequests", runtime.WithHTTPPathPattern("/v1/daemon/list-pending-tree-signing-requests")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DaemonService_ListPendingTreeSigningRequests_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_DaemonService_ListPendingTreeSigningRequests_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_DaemonService_SubmitTreeSignatures_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) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/waverpc.DaemonService/SubmitTreeSignatures", runtime.WithHTTPPathPattern("/v1/daemon/submit-tree-signatures")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DaemonService_SubmitTreeSignatures_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_DaemonService_SubmitTreeSignatures_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_DaemonService_LeaveVTXOs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2587,6 +2681,40 @@ func RegisterDaemonServiceHandlerClient(ctx context.Context, mux *runtime.ServeM } forward_DaemonService_SubmitForfeitParticipantSignatures_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_DaemonService_ListPendingTreeSigningRequests_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) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/waverpc.DaemonService/ListPendingTreeSigningRequests", runtime.WithHTTPPathPattern("/v1/daemon/list-pending-tree-signing-requests")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DaemonService_ListPendingTreeSigningRequests_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_ListPendingTreeSigningRequests_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_DaemonService_SubmitTreeSignatures_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) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/waverpc.DaemonService/SubmitTreeSignatures", runtime.WithHTTPPathPattern("/v1/daemon/submit-tree-signatures")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DaemonService_SubmitTreeSignatures_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_SubmitTreeSignatures_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_DaemonService_LeaveVTXOs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2972,6 +3100,8 @@ var ( pattern_DaemonService_RefreshCustomVTXOs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "refresh-custom-vtxos"}, "")) pattern_DaemonService_ListPendingForfeitParticipantSignatureRequests_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "list-pending-forfeit-participant-signature-requests"}, "")) pattern_DaemonService_SubmitForfeitParticipantSignatures_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "submit-forfeit-participant-signatures"}, "")) + pattern_DaemonService_ListPendingTreeSigningRequests_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "list-pending-tree-signing-requests"}, "")) + pattern_DaemonService_SubmitTreeSignatures_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "submit-tree-signatures"}, "")) pattern_DaemonService_LeaveVTXOs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "leave-vtxos"}, "")) pattern_DaemonService_SendOnChain_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "send-onchain"}, "")) pattern_DaemonService_Board_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "daemon", "board"}, "")) @@ -3020,6 +3150,8 @@ var ( forward_DaemonService_RefreshCustomVTXOs_0 = runtime.ForwardResponseMessage forward_DaemonService_ListPendingForfeitParticipantSignatureRequests_0 = runtime.ForwardResponseMessage forward_DaemonService_SubmitForfeitParticipantSignatures_0 = runtime.ForwardResponseMessage + forward_DaemonService_ListPendingTreeSigningRequests_0 = runtime.ForwardResponseMessage + forward_DaemonService_SubmitTreeSignatures_0 = runtime.ForwardResponseMessage forward_DaemonService_LeaveVTXOs_0 = runtime.ForwardResponseMessage forward_DaemonService_SendOnChain_0 = runtime.ForwardResponseMessage forward_DaemonService_Board_0 = runtime.ForwardResponseMessage diff --git a/waverpc/daemon.proto b/waverpc/daemon.proto index 6c5dd30b7..8c50e0de6 100644 --- a/waverpc/daemon.proto +++ b/waverpc/daemon.proto @@ -146,6 +146,24 @@ service DaemonService { SubmitForfeitParticipantSignaturesRequest) returns (SubmitForfeitParticipantSignaturesResponse); + // ListPendingTreeSigningRequests returns pending MuSig2 VTXO-tree signing + // requests for cosigner keys marked as externally signed (for example an + // aggregate FROST key the client controls off-box). Each request is one + // round of the two-round MuSig2 ceremony for one transaction session: + // round NONCE asks for a fresh public nonce, round PARTIAL_SIG asks for a + // partial signature over the given sighash under the operator-aggregated + // combined nonce. Callers poll this endpoint and answer with + // SubmitTreeSignatures. The private key never enters the daemon. + rpc ListPendingTreeSigningRequests (ListPendingTreeSigningRequestsRequest) + returns (ListPendingTreeSigningRequestsResponse); + + // SubmitTreeSignatures supplies the external cosigner's material for one + // pending tree-signing request. The request_id must be copied from the + // listed pending request; the daemon uses it to wake the blocked round FSM + // that is waiting for that exact session's nonce or partial signature. + rpc SubmitTreeSignatures (SubmitTreeSignaturesRequest) + returns (SubmitTreeSignaturesResponse); + // LeaveVTXOs queues one or more VTXOs for cooperative leave // (offboard) in the next round. Each VTXO is forfeited and the // forfeited amount (minus the quoted per-input operator fee) @@ -1511,6 +1529,100 @@ message SubmitForfeitParticipantSignaturesRequest { message SubmitForfeitParticipantSignaturesResponse { } +// TreeSigningRound distinguishes the two rounds of the MuSig2 tree-signing +// ceremony that an external cosigner participates in. +enum TreeSigningRound { + // TREE_SIGNING_ROUND_UNSPECIFIED is the zero value and is never emitted. + TREE_SIGNING_ROUND_UNSPECIFIED = 0; + + // TREE_SIGNING_ROUND_NONCE asks the external party for a fresh public + // nonce for one transaction session (round one). + TREE_SIGNING_ROUND_NONCE = 1; + + // TREE_SIGNING_ROUND_PARTIAL_SIG asks the external party for a partial + // signature over the request's sighash under its aggregate_nonce (round + // two). The party must sign under the exact secret nonce it committed to + // in the matching NONCE request for the same session_id. + TREE_SIGNING_ROUND_PARTIAL_SIG = 2; +} + +// PendingTreeSigningRequest is one blocking MuSig2 tree-signing request for an +// external cosigner key. It carries everything the external party needs to +// independently produce the requested nonce or partial signature. +message PendingTreeSigningRequest { + // request_id is the stable digest of this request. Echo it in + // SubmitTreeSignatures so the daemon can wake the blocked round FSM. + bytes request_id = 1; + + // sequence is the monotonic cursor for paging the pending request stream. + uint64 sequence = 2; + + // round selects which round of the ceremony this request is for. + TreeSigningRound round = 3; + + // round_id is the 16-byte round identifier this signing material belongs + // to. + bytes round_id = 4; + + // cosigner_pubkey is the 33-byte compressed public key of the external + // cosigner this material is requested for. + bytes cosigner_pubkey = 5; + + // session_id is the 32-byte per-transaction MuSig2 session identifier. It + // is stable across the NONCE and PARTIAL_SIG rounds for one transaction. + bytes session_id = 6; + + // cosigners is the full ordered MuSig2 participant set (the external + // cosigner plus the operator), each a 33-byte compressed public key. + repeated bytes cosigners = 7; + + // sweep_tapscript_root is the taproot tweak applied to the aggregate key + // (the VTXO tree's sweep tapscript root). It changes the aggregate key and + // therefore the signature. + bytes sweep_tapscript_root = 8; + + // sighash is the 32-byte taproot sighash the partial signature must cover. + // Set only on PARTIAL_SIG requests. + bytes sighash = 9; + + // aggregate_nonce is the 66-byte operator-aggregated combined nonce for + // this session. Set only on PARTIAL_SIG requests. + bytes aggregate_nonce = 10; +} + +message ListPendingTreeSigningRequestsRequest { + // after_sequence returns requests with a larger sequence. Zero starts at + // the beginning of the daemon-local pending request stream. + uint64 after_sequence = 1; + + // limit caps the number of returned requests. Zero uses a daemon default. + uint32 limit = 2; +} + +message ListPendingTreeSigningRequestsResponse { + repeated PendingTreeSigningRequest requests = 1; + uint64 next_sequence = 2; +} + +message SubmitTreeSignaturesRequest { + // request_id identifies the pending request being answered. It must match + // a request_id previously returned by ListPendingTreeSigningRequests. + bytes request_id = 1; + + // round must match the listed request's round. + TreeSigningRound round = 2; + + // public_nonce is the 66-byte MuSig2 public nonce. Set on NONCE requests. + bytes public_nonce = 3; + + // partial_signature is the serialized MuSig2 partial signature. Set on + // PARTIAL_SIG requests. + bytes partial_signature = 4; +} + +message SubmitTreeSignaturesResponse { +} + // LeaveDestination describes where a single leave output should land. // Unlike Output (used for VTXO sends), leave destinations are on-chain // and carry no VTXO-shape constraints: any standard address or @@ -1654,6 +1766,23 @@ message BoardRequest { // the Board through the wallet's self-Tell on startup until the // round adopts or the user fires a fresh Board. bool no_persist = 2; + + // vtxo_policy_template optionally pins the arkscript policy for every + // boarded VTXO output produced by this request. When empty, the daemon + // synthesizes the standard 2-of-2 collaborative policy with a freshly + // derived owner key (the legacy behavior). When supplied, the boarded + // outputs adopt this policy verbatim, letting a client board directly + // into a custom-owned VTXO (for example one owned by an external FROST + // aggregate key) without a follow-up refresh. The template must validate + // against the operator's terms, and it is persisted with the board intent + // so restart replay recreates the same custom output. + bytes vtxo_policy_template = 3; + + // pk_script optionally pins the taproot output script for the boarded + // VTXOs. It is only valid alongside vtxo_policy_template, and when set it + // must match the script derived from that template. Leaving it empty lets + // the daemon derive the script from the template. + bytes pk_script = 4; } message BoardResponse { diff --git a/waverpc/daemon.yaml b/waverpc/daemon.yaml index 35eae2647..79821fc95 100644 --- a/waverpc/daemon.yaml +++ b/waverpc/daemon.yaml @@ -75,6 +75,12 @@ http: - selector: waverpc.DaemonService.SubmitForfeitParticipantSignatures post: /v1/daemon/submit-forfeit-participant-signatures body: "*" + - selector: waverpc.DaemonService.ListPendingTreeSigningRequests + post: /v1/daemon/list-pending-tree-signing-requests + body: "*" + - selector: waverpc.DaemonService.SubmitTreeSignatures + post: /v1/daemon/submit-tree-signatures + body: "*" - selector: waverpc.DaemonService.LeaveVTXOs post: /v1/daemon/leave-vtxos body: "*" diff --git a/waverpc/daemon_grpc.pb.go b/waverpc/daemon_grpc.pb.go index aea18a9d8..d2a2fea10 100644 --- a/waverpc/daemon_grpc.pb.go +++ b/waverpc/daemon_grpc.pb.go @@ -43,6 +43,8 @@ const ( DaemonService_RefreshCustomVTXOs_FullMethodName = "/waverpc.DaemonService/RefreshCustomVTXOs" DaemonService_ListPendingForfeitParticipantSignatureRequests_FullMethodName = "/waverpc.DaemonService/ListPendingForfeitParticipantSignatureRequests" DaemonService_SubmitForfeitParticipantSignatures_FullMethodName = "/waverpc.DaemonService/SubmitForfeitParticipantSignatures" + DaemonService_ListPendingTreeSigningRequests_FullMethodName = "/waverpc.DaemonService/ListPendingTreeSigningRequests" + DaemonService_SubmitTreeSignatures_FullMethodName = "/waverpc.DaemonService/SubmitTreeSignatures" DaemonService_LeaveVTXOs_FullMethodName = "/waverpc.DaemonService/LeaveVTXOs" DaemonService_SendOnChain_FullMethodName = "/waverpc.DaemonService/SendOnChain" DaemonService_Board_FullMethodName = "/waverpc.DaemonService/Board" @@ -174,6 +176,20 @@ type DaemonServiceClient interface { // operator key, callers may submit an empty signature set to acknowledge // and unblock the request. SubmitForfeitParticipantSignatures(ctx context.Context, in *SubmitForfeitParticipantSignaturesRequest, opts ...grpc.CallOption) (*SubmitForfeitParticipantSignaturesResponse, error) + // ListPendingTreeSigningRequests returns pending MuSig2 VTXO-tree signing + // requests for cosigner keys marked as externally signed (for example an + // aggregate FROST key the client controls off-box). Each request is one + // round of the two-round MuSig2 ceremony for one transaction session: + // round NONCE asks for a fresh public nonce, round PARTIAL_SIG asks for a + // partial signature over the given sighash under the operator-aggregated + // combined nonce. Callers poll this endpoint and answer with + // SubmitTreeSignatures. The private key never enters the daemon. + ListPendingTreeSigningRequests(ctx context.Context, in *ListPendingTreeSigningRequestsRequest, opts ...grpc.CallOption) (*ListPendingTreeSigningRequestsResponse, error) + // SubmitTreeSignatures supplies the external cosigner's material for one + // pending tree-signing request. The request_id must be copied from the + // listed pending request; the daemon uses it to wake the blocked round FSM + // that is waiting for that exact session's nonce or partial signature. + SubmitTreeSignatures(ctx context.Context, in *SubmitTreeSignaturesRequest, opts ...grpc.CallOption) (*SubmitTreeSignaturesResponse, error) // LeaveVTXOs queues one or more VTXOs for cooperative leave // (offboard) in the next round. Each VTXO is forfeited and the // forfeited amount (minus the quoted per-input operator fee) @@ -509,6 +525,26 @@ func (c *daemonServiceClient) SubmitForfeitParticipantSignatures(ctx context.Con return out, nil } +func (c *daemonServiceClient) ListPendingTreeSigningRequests(ctx context.Context, in *ListPendingTreeSigningRequestsRequest, opts ...grpc.CallOption) (*ListPendingTreeSigningRequestsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListPendingTreeSigningRequestsResponse) + err := c.cc.Invoke(ctx, DaemonService_ListPendingTreeSigningRequests_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *daemonServiceClient) SubmitTreeSignatures(ctx context.Context, in *SubmitTreeSignaturesRequest, opts ...grpc.CallOption) (*SubmitTreeSignaturesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SubmitTreeSignaturesResponse) + err := c.cc.Invoke(ctx, DaemonService_SubmitTreeSignatures_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *daemonServiceClient) LeaveVTXOs(ctx context.Context, in *LeaveVTXOsRequest, opts ...grpc.CallOption) (*LeaveVTXOsResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(LeaveVTXOsResponse) @@ -836,6 +872,20 @@ type DaemonServiceServer interface { // operator key, callers may submit an empty signature set to acknowledge // and unblock the request. SubmitForfeitParticipantSignatures(context.Context, *SubmitForfeitParticipantSignaturesRequest) (*SubmitForfeitParticipantSignaturesResponse, error) + // ListPendingTreeSigningRequests returns pending MuSig2 VTXO-tree signing + // requests for cosigner keys marked as externally signed (for example an + // aggregate FROST key the client controls off-box). Each request is one + // round of the two-round MuSig2 ceremony for one transaction session: + // round NONCE asks for a fresh public nonce, round PARTIAL_SIG asks for a + // partial signature over the given sighash under the operator-aggregated + // combined nonce. Callers poll this endpoint and answer with + // SubmitTreeSignatures. The private key never enters the daemon. + ListPendingTreeSigningRequests(context.Context, *ListPendingTreeSigningRequestsRequest) (*ListPendingTreeSigningRequestsResponse, error) + // SubmitTreeSignatures supplies the external cosigner's material for one + // pending tree-signing request. The request_id must be copied from the + // listed pending request; the daemon uses it to wake the blocked round FSM + // that is waiting for that exact session's nonce or partial signature. + SubmitTreeSignatures(context.Context, *SubmitTreeSignaturesRequest) (*SubmitTreeSignaturesResponse, error) // LeaveVTXOs queues one or more VTXOs for cooperative leave // (offboard) in the next round. Each VTXO is forfeited and the // forfeited amount (minus the quoted per-input operator fee) @@ -1003,6 +1053,12 @@ func (UnimplementedDaemonServiceServer) ListPendingForfeitParticipantSignatureRe func (UnimplementedDaemonServiceServer) SubmitForfeitParticipantSignatures(context.Context, *SubmitForfeitParticipantSignaturesRequest) (*SubmitForfeitParticipantSignaturesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SubmitForfeitParticipantSignatures not implemented") } +func (UnimplementedDaemonServiceServer) ListPendingTreeSigningRequests(context.Context, *ListPendingTreeSigningRequestsRequest) (*ListPendingTreeSigningRequestsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListPendingTreeSigningRequests not implemented") +} +func (UnimplementedDaemonServiceServer) SubmitTreeSignatures(context.Context, *SubmitTreeSignaturesRequest) (*SubmitTreeSignaturesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SubmitTreeSignatures not implemented") +} func (UnimplementedDaemonServiceServer) LeaveVTXOs(context.Context, *LeaveVTXOsRequest) (*LeaveVTXOsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method LeaveVTXOs not implemented") } @@ -1519,6 +1575,42 @@ func _DaemonService_SubmitForfeitParticipantSignatures_Handler(srv interface{}, return interceptor(ctx, in, info, handler) } +func _DaemonService_ListPendingTreeSigningRequests_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListPendingTreeSigningRequestsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DaemonServiceServer).ListPendingTreeSigningRequests(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DaemonService_ListPendingTreeSigningRequests_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DaemonServiceServer).ListPendingTreeSigningRequests(ctx, req.(*ListPendingTreeSigningRequestsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DaemonService_SubmitTreeSignatures_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SubmitTreeSignaturesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DaemonServiceServer).SubmitTreeSignatures(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DaemonService_SubmitTreeSignatures_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DaemonServiceServer).SubmitTreeSignatures(ctx, req.(*SubmitTreeSignaturesRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _DaemonService_LeaveVTXOs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(LeaveVTXOsRequest) if err := dec(in); err != nil { @@ -1993,6 +2085,14 @@ var DaemonService_ServiceDesc = grpc.ServiceDesc{ MethodName: "SubmitForfeitParticipantSignatures", Handler: _DaemonService_SubmitForfeitParticipantSignatures_Handler, }, + { + MethodName: "ListPendingTreeSigningRequests", + Handler: _DaemonService_ListPendingTreeSigningRequests_Handler, + }, + { + MethodName: "SubmitTreeSignatures", + Handler: _DaemonService_SubmitTreeSignatures_Handler, + }, { MethodName: "LeaveVTXOs", Handler: _DaemonService_LeaveVTXOs_Handler, diff --git a/waverpc/daemon_mailboxrpc.pb.go b/waverpc/daemon_mailboxrpc.pb.go index 3e9b37b18..63f967a11 100644 --- a/waverpc/daemon_mailboxrpc.pb.go +++ b/waverpc/daemon_mailboxrpc.pb.go @@ -72,6 +72,10 @@ type DaemonServiceMailboxServer interface { ListPendingForfeitParticipantSignatureRequests(ctx context.Context, req *ListPendingForfeitParticipantSignatureRequestsRequest) (*ListPendingForfeitParticipantSignatureRequestsResponse, error) // SubmitForfeitParticipantSignatures handles SubmitForfeitParticipantSignatures. SubmitForfeitParticipantSignatures(ctx context.Context, req *SubmitForfeitParticipantSignaturesRequest) (*SubmitForfeitParticipantSignaturesResponse, error) + // ListPendingTreeSigningRequests handles ListPendingTreeSigningRequests. + ListPendingTreeSigningRequests(ctx context.Context, req *ListPendingTreeSigningRequestsRequest) (*ListPendingTreeSigningRequestsResponse, error) + // SubmitTreeSignatures handles SubmitTreeSignatures. + SubmitTreeSignatures(ctx context.Context, req *SubmitTreeSignaturesRequest) (*SubmitTreeSignaturesResponse, error) // LeaveVTXOs handles LeaveVTXOs. LeaveVTXOs(ctx context.Context, req *LeaveVTXOsRequest) (*LeaveVTXOsResponse, error) // SendOnChain handles SendOnChain. @@ -358,6 +362,26 @@ func RegisterDaemonServiceMailboxServer(r rpc.Router, impl DaemonServiceMailboxS return impl.SubmitForfeitParticipantSignatures(ctx, req) }) + r.Handle("waverpc.DaemonService", "ListPendingTreeSigningRequests", func() proto.Message { + return &ListPendingTreeSigningRequestsRequest{} + }, func(ctx context.Context, msg proto.Message) (proto.Message, error) { + req, ok := msg.(*ListPendingTreeSigningRequestsRequest) + if !ok { + return nil, fmt.Errorf("unexpected request type: %T", msg) + } + + return impl.ListPendingTreeSigningRequests(ctx, req) + }) + r.Handle("waverpc.DaemonService", "SubmitTreeSignatures", func() proto.Message { + return &SubmitTreeSignaturesRequest{} + }, func(ctx context.Context, msg proto.Message) (proto.Message, error) { + req, ok := msg.(*SubmitTreeSignaturesRequest) + if !ok { + return nil, fmt.Errorf("unexpected request type: %T", msg) + } + + return impl.SubmitTreeSignatures(ctx, req) + }) r.Handle("waverpc.DaemonService", "LeaveVTXOs", func() proto.Message { return &LeaveVTXOsRequest{} }, func(ctx context.Context, msg proto.Message) (proto.Message, error) { @@ -1122,6 +1146,52 @@ func (c *DaemonServiceMailboxClient) SubmitForfeitParticipantSignatures(ctx cont return resp, nil } +// ListPendingTreeSigningRequests calls the ListPendingTreeSigningRequests RPC. +func (c *DaemonServiceMailboxClient) ListPendingTreeSigningRequests(ctx context.Context, req *ListPendingTreeSigningRequestsRequest, opts ...rpc.RPCOptions) (*ListPendingTreeSigningRequestsResponse, error) { + var opt rpc.RPCOptions + if len(opts) > 0 { + opt = opts[0] + } + + result, err := c.C.SendRPC(ctx, rpc.ServiceMethod{ + Service: "waverpc.DaemonService", + Method: "ListPendingTreeSigningRequests", + }, req, opt) + if err != nil { + return nil, err + } + + resp := new(ListPendingTreeSigningRequestsResponse) + if err := c.C.AwaitRPC(ctx, result.CorrelationID, resp); err != nil { + return nil, err + } + + return resp, nil +} + +// SubmitTreeSignatures calls the SubmitTreeSignatures RPC. +func (c *DaemonServiceMailboxClient) SubmitTreeSignatures(ctx context.Context, req *SubmitTreeSignaturesRequest, opts ...rpc.RPCOptions) (*SubmitTreeSignaturesResponse, error) { + var opt rpc.RPCOptions + if len(opts) > 0 { + opt = opts[0] + } + + result, err := c.C.SendRPC(ctx, rpc.ServiceMethod{ + Service: "waverpc.DaemonService", + Method: "SubmitTreeSignatures", + }, req, opt) + if err != nil { + return nil, err + } + + resp := new(SubmitTreeSignaturesResponse) + if err := c.C.AwaitRPC(ctx, result.CorrelationID, resp); err != nil { + return nil, err + } + + return resp, nil +} + // LeaveVTXOs calls the LeaveVTXOs RPC. func (c *DaemonServiceMailboxClient) LeaveVTXOs(ctx context.Context, req *LeaveVTXOsRequest, opts ...rpc.RPCOptions) (*LeaveVTXOsResponse, error) { var opt rpc.RPCOptions