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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 2 additions & 34 deletions arkrpc/ark.pb.go

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

12 changes: 3 additions & 9 deletions arkrpc/ark.proto
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,9 @@ message GetInfoResponse {
// The minimum CSV delay (blocks) for VTXO unilateral exit paths.
uint32 vtxo_exit_delay = 6;

// The output script that clients must use for the penalty output in
// forfeit transactions.
bytes forfeit_script = 7;

// The operator key used in VTXO sweep paths.
bytes sweep_key = 8;

// The batch-wide absolute timelock (blocks) for sweep transactions.
uint32 sweep_delay = 9;
// Field numbers 7, 8 and 9 are unused: the forfeit penalty key, sweep
// key and delay are delivered per-round in round.v1.ClientBatchInfo
// instead.

// The minimum output value (satoshis) enforced for boarding/funding
// flows.
Expand Down
37 changes: 2 additions & 35 deletions daemonrpc/daemon.pb.go

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

13 changes: 3 additions & 10 deletions daemonrpc/daemon.proto
Original file line number Diff line number Diff line change
Expand Up @@ -321,16 +321,9 @@ message ServerInfo {
// vtxo_exit_delay is the minimum CSV delay for VTXO outputs.
uint32 vtxo_exit_delay = 3;

// forfeit_script is the raw serialized scriptPubKey for the penalty
// output clients must use in forfeit transactions.
bytes forfeit_script = 4;

// sweep_key is the compressed SEC-encoded public key used in VTXO
// sweep paths when present.
bytes sweep_key = 5;

// sweep_delay is the batch-wide absolute timelock in blocks.
uint32 sweep_delay = 6;
// Field numbers 4, 5 and 6 are unused: the forfeit penalty key, sweep
// key and delay are delivered per-round in round.v1.ClientBatchInfo
// instead.

// dust_limit is the minimum output value accepted by the operator.
uint64 dust_limit = 7;
Expand Down
1 change: 0 additions & 1 deletion darepod/rpc_fees_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,6 @@ func newFakeOperatorResponse(t *testing.T,
return &arkrpc.GetInfoResponse{
Pubkey: priv.PubKey().SerializeCompressed(),
VtxoExitDelay: 144,
SweepDelay: 1008,
MinOperatorFee: minOperatorFee,
}
}
Expand Down
11 changes: 4 additions & 7 deletions darepod/rpc_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,24 +594,21 @@ func (r *RPCServer) GetInfo(ctx context.Context, _ *daemonrpc.GetInfoRequest) (
return resp, nil
}

// The forfeit penalty key, sweep key and delay are no longer
// global operator terms; they are delivered per round in the
// round batch info, so they are not surfaced on this
// daemon-level ServerInfo snapshot.
resp.ServerInfo = &daemonrpc.ServerInfo{
OperatorPubkey: terms.PubKey.SerializeCompressed(),
BoardingExitDelay: terms.BoardingExitDelay,
VtxoExitDelay: terms.VTXOExitDelay,
ForfeitScript: terms.ForfeitScript,
SweepDelay: terms.SweepDelay,
DustLimit: uint64(terms.DustLimit),
MinBoardingAmount: uint64(terms.MinBoardingAmount),
MaxBoardingAmount: uint64(terms.MaxBoardingAmount),
FeeRate: uint64(terms.FeeRate),
MinOperatorFee: uint64(terms.MinOperatorFee),
MinConfirmations: terms.MinConfirmations,
}

if terms.SweepKey != nil {
resp.ServerInfo.SweepKey =
terms.SweepKey.SerializeCompressed()
}
}

return resp, nil
Expand Down
16 changes: 0 additions & 16 deletions darepod/rpc_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -931,9 +931,6 @@ func TestGetInfoIncludesServerInfo(t *testing.T) {
operatorPriv, err := btcec.NewPrivateKey()
require.NoError(t, err)

sweepPriv, err := btcec.NewPrivateKey()
require.NoError(t, err)

server := &Server{
cfg: &Config{
Network: "regtest",
Expand All @@ -948,9 +945,6 @@ func TestGetInfoIncludesServerInfo(t *testing.T) {
PubKey: operatorPriv.PubKey(),
BoardingExitDelay: 144,
VTXOExitDelay: 288,
ForfeitScript: []byte{0x51, 0x20, 0x01},
SweepKey: sweepPriv.PubKey(),
SweepDelay: 432,
DustLimit: btcutil.Amount(546),
MinBoardingAmount: btcutil.Amount(10_000),
MaxBoardingAmount: btcutil.Amount(500_000),
Expand All @@ -972,14 +966,6 @@ func TestGetInfoIncludesServerInfo(t *testing.T) {
)
require.Equal(t, uint32(144), resp.ServerInfo.BoardingExitDelay)
require.Equal(t, uint32(288), resp.ServerInfo.VtxoExitDelay)
require.Equal(
t, []byte{0x51, 0x20, 0x01}, resp.ServerInfo.ForfeitScript,
)
require.Equal(
t, sweepPriv.PubKey().SerializeCompressed(),
resp.ServerInfo.SweepKey,
)
require.Equal(t, uint32(432), resp.ServerInfo.SweepDelay)
require.Equal(t, uint64(546), resp.ServerInfo.DustLimit)
require.Equal(t, uint64(10_000),
resp.ServerInfo.MinBoardingAmount,
Expand Down Expand Up @@ -1023,8 +1009,6 @@ func TestGetInfoConcurrentOperatorTermsAccess(t *testing.T) {
PubKey: operatorPriv.PubKey(),
BoardingExitDelay: 100 + i,
VTXOExitDelay: 200 + i,
ForfeitScript: []byte{0x51, byte(i)},
SweepDelay: 300 + i,
DustLimit: btcutil.Amount(546),
MinBoardingAmount: btcutil.Amount(10_000),
MaxBoardingAmount: btcutil.Amount(500_000),
Expand Down
14 changes: 3 additions & 11 deletions darepod/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3965,21 +3965,13 @@ func (s *Server) fetchOperatorTerms(ctx context.Context) (*types.OperatorTerms,
return nil, fmt.Errorf("parse operator pubkey: %w", err)
}

var sweepKey *btcec.PublicKey
if len(resp.SweepKey) > 0 {
sweepKey, err = btcec.ParsePubKey(resp.SweepKey)
if err != nil {
return nil, fmt.Errorf("parse sweep key: %w", err)
}
}

// The forfeit penalty key, sweep key and sweep delay are no longer
// global operator terms; they are delivered per round in the batch
// info, so GetInfo no longer carries them.
terms := &types.OperatorTerms{
PubKey: pubKey,
BoardingExitDelay: resp.BoardingExitDelay,
VTXOExitDelay: resp.VtxoExitDelay,
ForfeitScript: resp.ForfeitScript,
SweepKey: sweepKey,
SweepDelay: resp.SweepDelay,
DustLimit: btcutil.Amount(resp.DustLimit),
MinBoardingAmount: btcutil.Amount(resp.MinBoardingAmount),
MaxBoardingAmount: btcutil.Amount(resp.MaxBoardingAmount),
Expand Down
15 changes: 2 additions & 13 deletions lib/types/boarding.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,6 @@ type OperatorTerms struct {
// a VTXO that has been forfeit or spent.
VTXOExitDelay uint32

// ForfeitScript is the output script that clients must use for the
// penalty output in forfeit transactions. This allows the server to
// claim forfeited funds.
ForfeitScript []byte

// SweepKey is the operator key used in VTXT sweep paths.
SweepKey *btcec.PublicKey

// SweepDelay is the batch-wide absolute timelock (blocks).
SweepDelay uint32

// DustLimit enforces minimum output value for boarding/funding flows.
DustLimit btcutil.Amount

Expand Down Expand Up @@ -394,8 +383,8 @@ type BatchOutputInfo struct {
// signing sessions for this batch output.
SignerKey *btcec.PublicKey

// Tree is the VTXO tree for this batch output.
// Tree contains SweepKey, SweepDelay, and PrevOut.
// Tree is the VTXO tree for this batch output. The tree embeds the
// per-round sweep key, sweep delay, and PrevOut.
Tree *tree.Tree
}

Expand Down
9 changes: 4 additions & 5 deletions round/actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,11 +371,10 @@ func NewRoundClientActor(cfg *RoundClientConfig) fn.Result[*RoundClientActor] {
OwnedScriptChecker: cfg.OwnedScriptChecker,
}

if err := ValidateDelayParameters(
cfg.OperatorTerms.SweepDelay, cfg.OperatorTerms.VTXOExitDelay,
); err != nil {
return fn.Err[*RoundClientActor](err)
}
// The sweep delay is no longer a global operator term: it is delivered
// per round in the batch info, so the sweep-vs-exit-delay security
// check runs per round in CommitmentTxReceivedState rather than once at
// actor construction.

if cfg.TimeoutActor == nil {
return fn.Err[*RoundClientActor](
Expand Down
2 changes: 0 additions & 2 deletions round/actor_harness_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -565,8 +565,6 @@ func newActorTestHarness(t *testing.T) *actorTestHarness {
PubKey: operatorPubKey,
BoardingExitDelay: 144,
VTXOExitDelay: 144,
SweepKey: operatorPubKey,
SweepDelay: 1008,
MinConfirmations: 1,
}

Expand Down
35 changes: 35 additions & 0 deletions round/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,41 @@ type CommitmentTxBuilt struct {
// (e.g., MaxTreeNodes limit) and passed through to
// roundpb.TreeFromProto during FromProto.
TreeOpts []roundpb.TreeFromProtoOption

// TreeCosignKey is the operator's MuSig2 cosigner key for this round's
// VTXO output tree, derived fresh per round by the server. The client
// aggregates and validates the tree against this key instead of the
// operator's global GetInfo key, so an operator key rotation does not
// change the tree key the client must agree on. Nil when talking to a
// server that predates this field; callers fall back to the global
// operator key.
TreeCosignKey *btcec.PublicKey

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a 3rd key here? So the vtxo sign key? or the tree sign key is the same for all users in a round?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addded below


// ConnectorOperatorKey is the operator key this round used to build its
// connector tree. The client reconstructs the connector tree from it
// instead of the global operator key. Nil when talking to an older
// server; callers fall back to the global operator key.
ConnectorOperatorKey *btcec.PublicKey

// SweepKey is the operator sweep key for this round's VTXO-tree sweep
// leaf, delivered per round so the client agrees with the server on the
// sweep branch even across an operator key rotation. It replaces the
// global GetInfo sweep key entirely; a well-formed round always carries
// it.
SweepKey *btcec.PublicKey

// SweepDelay is this round's batch-wide absolute-timelock in blocks for
// the VTXO-tree sweep leaf, delivered per round alongside SweepKey. It
// replaces the global GetInfo sweep delay and drives batch-expiry
// computation for VTXOs created in this round.
SweepDelay uint32

// ForfeitKey is the operator's dedicated forfeit penalty key for this
// round, delivered per round so the client builds the forfeit-tx
// penalty output (a BIP-86 key-spend to this key) the server expects
// even across an operator key rotation. It replaces the global GetInfo
// forfeit script entirely; a well-formed round always carries it.
ForfeitKey *btcec.PublicKey
}

func (e *CommitmentTxBuilt) clientEventSealed() {}
Expand Down
Loading