From 91781e22d391f6068ed985e66681f65690c112f7 Mon Sep 17 00:00:00 2001 From: louisinger Date: Wed, 1 Apr 2026 16:51:07 +0200 Subject: [PATCH 01/16] finalize swept pending tx --- internal/infrastructure/db/service.go | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/internal/infrastructure/db/service.go b/internal/infrastructure/db/service.go index 7bd098e0e..d32f6c735 100644 --- a/internal/infrastructure/db/service.go +++ b/internal/infrastructure/db/service.go @@ -521,7 +521,7 @@ func (s *service) updateProjectionsAfterOffchainTxEvents(events []domain.Event) } log.Debugf("spent %d vtxos", len(spentVtxos)) case offchainTx.IsFinalized(): - txid, _, outs, err := s.txDecoder.DecodeTx(offchainTx.ArkTx) + txid, ins, outs, err := s.txDecoder.DecodeTx(offchainTx.ArkTx) if err != nil { log.WithError(err).Warn("failed to decode ark tx") return @@ -533,6 +533,23 @@ func (s *service) updateProjectionsAfterOffchainTxEvents(events []domain.Event) return } + txSwept := false + // if the tx is expired at finalization step, it may be possible the new outputs should be marked swept + // it depends if the inputs are swept or not + if offchainTx.ExpiryTimestamp > 0 && + time.Now().After(time.Unix(offchainTx.ExpiryTimestamp, 0)) { + inputVtxos, err := s.vtxoStore.GetVtxos(ctx, ins) + // if an error happened, we assume the vtxo is swept. it should never happen but it's to avoid skipping adding vtxo to db + txSwept = err != nil + + for _, inputVtxo := range inputVtxos { + if inputVtxo.Swept { + txSwept = true + break + } + } + } + // once the offchain tx is finalized, the user signed the checkpoint txs // thus, we can create the new vtxos in the db. newVtxos := make([]domain.Vtxo, 0, len(outs)) @@ -548,7 +565,10 @@ func (s *service) updateProjectionsAfterOffchainTxEvents(events []domain.Event) continue } - isDust := script.IsSubDustScript(out.PkScript) + outputSwept := txSwept + if !outputSwept { + outputSwept = script.IsSubDustScript(out.PkScript) + } newVtxos = append(newVtxos, domain.Vtxo{ Outpoint: domain.Outpoint{ @@ -565,7 +585,7 @@ func (s *service) updateProjectionsAfterOffchainTxEvents(events []domain.Event) // mark the vtxo as "swept" if it is below dust limit to prevent it from being spent again in a future offchain tx // the only way to spend a swept vtxo is by collecting enough dust to cover the minSettlementVtxoAmount and then settle. // because sub-dust vtxos are using OP_RETURN output script, they can't be unilaterally exited. - Swept: isDust, + Swept: outputSwept, Assets: assets[uint32(outIndex)], }) } From 3890387ae440f0b805ce876041977736e14ca7a2 Mon Sep 17 00:00:00 2001 From: Bob Smith <5396652+bitcoin-coder-bob@users.noreply.github.com> Date: Thu, 2 Apr 2026 15:20:32 -0400 Subject: [PATCH 02/16] add tests for finalize pending tx projection --- internal/infrastructure/db/service_test.go | 193 +++++++++++++++++++++ 1 file changed, 193 insertions(+) diff --git a/internal/infrastructure/db/service_test.go b/internal/infrastructure/db/service_test.go index 06a44ed47..9424a8f98 100644 --- a/internal/infrastructure/db/service_test.go +++ b/internal/infrastructure/db/service_test.go @@ -2024,6 +2024,199 @@ func randomTx() string { return b64 } +type mockTxDecoder struct { + decodeFn func(tx string) (string, []ports.TxIn, []ports.TxOut, error) +} + +func (m *mockTxDecoder) DecodeTx(tx string) (string, []ports.TxIn, []ports.TxOut, error) { + return m.decodeFn(tx) +} + +// taprootPkScript returns a 34-byte taproot pkscript (OP_1 + PUSH32 + key). +func taprootPkScript(pubkeyHex string) []byte { + pk, _ := hex.DecodeString(pubkeyHex) + script := make([]byte, 34) + script[0] = 0x51 // OP_1 + script[1] = 0x20 // PUSH32 + copy(script[2:], pk) + return script +} + +// TestFinalizePendingTxProjection tests the projection handler that runs when +// an offchain tx is finalized (Requested -> Accepted -> Finalized). +// +// When finalization happens after the tx's expiry timestamp has passed, the +// handler needs to check whether the input vtxos have been swept on-chain by +// the server. If any input is swept, the newly created output vtxos must also +// be marked as swept (they can't be spent on-chain since their inputs are gone). +// +// Two cases: +// - Input vtxos were swept by the server -> output vtxos must be marked swept. +// - Input vtxos were NOT swept (round expired but server hasn't reclaimed yet) +// -> output vtxos should NOT be marked swept. +func TestFinalizePendingTxProjection(t *testing.T) { + outputPkScript := taprootPkScript(pubkey) + + checkpointTxid1 := randomString(32) + checkpointTxid2 := randomString(32) + rootCommitmentTxid := randomString(32) + commitmentTxid := randomString(32) + + // The mock decoder is swapped per-subtest to return unique outpoints. + decoder := &mockTxDecoder{} + + tests := []struct { + name string + inputSwept bool + expectSwept bool + }{ + { + // The server already swept the inputs on-chain (round expired and + // the server reclaimed the funds). Finalizing the offchain tx at + // this point should propagate the swept status to the outputs. + name: "finalize_pending_tx_after_swept_by_server", + inputSwept: true, + expectSwept: true, + }, + { + // The round expired but the server has NOT swept the inputs yet. + // The outputs are still valid on-chain so they should not be + // marked as swept. + name: "finalize_pending_tx_after_expired_not_swept", + inputSwept: false, + expectSwept: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Fresh db per subtest for clean isolation. + dbDir := t.TempDir() + svc, err := db.NewService(db.ServiceConfig{ + EventStoreType: "badger", + DataStoreType: "sqlite", + EventStoreConfig: []interface{}{"", nil}, + DataStoreConfig: []interface{}{dbDir}, + }, decoder) + require.NoError(t, err) + defer svc.Close() + + ctx := context.Background() + + // Generate unique input/output outpoints per subtest. + in1 := domain.Outpoint{Txid: randomString(32), VOut: 0} + in2 := domain.Outpoint{Txid: randomString(32), VOut: 0} + outTxid := randomString(32) + + // Configure the mock decoder to map the ark tx to our test + // inputs and outputs. The projection handler calls DecodeTx on + // the finalized ark tx to discover which vtxos are consumed + // (inputs) and which are created (outputs). + decoder.decodeFn = func(tx string) (string, []ports.TxIn, []ports.TxOut, error) { + return outTxid, []ports.TxIn{in1, in2}, []ports.TxOut{ + {Amount: 1000, PkScript: outputPkScript}, + }, nil + } + + // Pre-populate the input vtxos in the store. The Swept flag + // simulates whether the server has already swept them on-chain. + inputVtxos := []domain.Vtxo{ + { + Outpoint: in1, + PubKey: pubkey, + Amount: 500, + Swept: tt.inputSwept, + RootCommitmentTxid: rootCommitmentTxid, + CommitmentTxids: []string{rootCommitmentTxid}, + }, + { + Outpoint: in2, + PubKey: pubkey, + Amount: 500, + Swept: tt.inputSwept, + RootCommitmentTxid: rootCommitmentTxid, + CommitmentTxids: []string{rootCommitmentTxid}, + }, + } + err = svc.Vtxos().AddVtxos(ctx, inputVtxos) + require.NoError(t, err) + + // The expiry timestamp is in the past so the projection handler + // will enter the "expired at finalization" code path and check + // whether the input vtxos are swept. + expiredTimestamp := time.Now().Add(-1 * time.Hour).Unix() + txId := randomString(32) + + // Walk the offchain tx through its full lifecycle: + // Requested -> Accepted (with expired timestamp) -> Finalized. + // Saving these events triggers the projection handler async. + events := []domain.Event{ + domain.OffchainTxRequested{ + OffchainTxEvent: domain.OffchainTxEvent{ + Id: txId, + Type: domain.EventTypeOffchainTxRequested, + }, + ArkTx: "mock_ark_tx", + UnsignedCheckpointTxs: map[string]string{ + checkpointTxid1: "unsigned1", + checkpointTxid2: "unsigned2", + }, + StartingTimestamp: time.Now().Unix(), + }, + domain.OffchainTxAccepted{ + OffchainTxEvent: domain.OffchainTxEvent{ + Id: txId, + Type: domain.EventTypeOffchainTxAccepted, + }, + FinalArkTx: "mock_final_ark_tx", + SignedCheckpointTxs: map[string]string{ + checkpointTxid1: "signed1", + checkpointTxid2: "signed2", + }, + CommitmentTxids: map[string]string{ + checkpointTxid1: rootCommitmentTxid, + checkpointTxid2: commitmentTxid, + }, + RootCommitmentTxid: rootCommitmentTxid, + ExpiryTimestamp: expiredTimestamp, + }, + domain.OffchainTxFinalized{ + OffchainTxEvent: domain.OffchainTxEvent{ + Id: txId, + Type: domain.EventTypeOffchainTxFinalized, + }, + FinalCheckpointTxs: map[string]string{ + checkpointTxid1: "final1", + checkpointTxid2: "final2", + }, + Timestamp: time.Now().Unix(), + }, + } + + err = svc.Events().Save(ctx, domain.OffchainTxTopic, txId, events) + require.NoError(t, err) + + // The projection handler runs asynchronously via a goroutine, so + // poll until the output vtxo appears in the store. + require.Eventually(t, func() bool { + vtxos, err := svc.Vtxos().GetVtxos(ctx, []domain.Outpoint{ + {Txid: outTxid, VOut: 0}, + }) + return err == nil && len(vtxos) > 0 + }, 5*time.Second, 100*time.Millisecond) + + // Verify the output vtxo's Swept flag matches expectations. + outputVtxos, err := svc.Vtxos().GetVtxos(ctx, []domain.Outpoint{ + {Txid: outTxid, VOut: 0}, + }) + require.NoError(t, err) + require.Len(t, outputVtxos, 1) + require.Equal(t, tt.expectSwept, outputVtxos[0].Swept, + "expected Swept=%v for output vtxo", tt.expectSwept) + }) + } +} + func checkVtxos(t *testing.T, expectedVtxos, gotVtxos []domain.Vtxo) { sort.SliceStable(expectedVtxos, func(i, j int) bool { return expectedVtxos[i].Txid < expectedVtxos[j].Txid From 088acf541c023ce963e512088ab14b3a73e8b52e Mon Sep 17 00:00:00 2001 From: Bob Smith <5396652+bitcoin-coder-bob@users.noreply.github.com> Date: Thu, 2 Apr 2026 15:29:57 -0400 Subject: [PATCH 03/16] validate taprootPkScript test helper input --- internal/infrastructure/db/service_test.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/internal/infrastructure/db/service_test.go b/internal/infrastructure/db/service_test.go index 9424a8f98..e59a2849a 100644 --- a/internal/infrastructure/db/service_test.go +++ b/internal/infrastructure/db/service_test.go @@ -2033,8 +2033,15 @@ func (m *mockTxDecoder) DecodeTx(tx string) (string, []ports.TxIn, []ports.TxOut } // taprootPkScript returns a 34-byte taproot pkscript (OP_1 + PUSH32 + key). -func taprootPkScript(pubkeyHex string) []byte { - pk, _ := hex.DecodeString(pubkeyHex) +func taprootPkScript(t *testing.T, pubkeyHex string) []byte { + t.Helper() + pk, err := hex.DecodeString(pubkeyHex) + if err != nil { + t.Fatalf("taprootPkScript: invalid hex %q: %v", pubkeyHex, err) + } + if len(pk) != 32 { + t.Fatalf("taprootPkScript: expected 32-byte key, got %d bytes", len(pk)) + } script := make([]byte, 34) script[0] = 0x51 // OP_1 script[1] = 0x20 // PUSH32 @@ -2055,7 +2062,7 @@ func taprootPkScript(pubkeyHex string) []byte { // - Input vtxos were NOT swept (round expired but server hasn't reclaimed yet) // -> output vtxos should NOT be marked swept. func TestFinalizePendingTxProjection(t *testing.T) { - outputPkScript := taprootPkScript(pubkey) + outputPkScript := taprootPkScript(t, pubkey) checkpointTxid1 := randomString(32) checkpointTxid2 := randomString(32) From a5d829bcc9266f9c255a22ad88d99864382c9d1f Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Fri, 3 Apr 2026 20:00:32 +0200 Subject: [PATCH 04/16] Revert and add tests --- internal/infrastructure/db/service_test.go | 200 -------------- internal/test/e2e/e2e_test.go | 298 +++++++++++++++++++++ 2 files changed, 298 insertions(+), 200 deletions(-) diff --git a/internal/infrastructure/db/service_test.go b/internal/infrastructure/db/service_test.go index e59a2849a..06a44ed47 100644 --- a/internal/infrastructure/db/service_test.go +++ b/internal/infrastructure/db/service_test.go @@ -2024,206 +2024,6 @@ func randomTx() string { return b64 } -type mockTxDecoder struct { - decodeFn func(tx string) (string, []ports.TxIn, []ports.TxOut, error) -} - -func (m *mockTxDecoder) DecodeTx(tx string) (string, []ports.TxIn, []ports.TxOut, error) { - return m.decodeFn(tx) -} - -// taprootPkScript returns a 34-byte taproot pkscript (OP_1 + PUSH32 + key). -func taprootPkScript(t *testing.T, pubkeyHex string) []byte { - t.Helper() - pk, err := hex.DecodeString(pubkeyHex) - if err != nil { - t.Fatalf("taprootPkScript: invalid hex %q: %v", pubkeyHex, err) - } - if len(pk) != 32 { - t.Fatalf("taprootPkScript: expected 32-byte key, got %d bytes", len(pk)) - } - script := make([]byte, 34) - script[0] = 0x51 // OP_1 - script[1] = 0x20 // PUSH32 - copy(script[2:], pk) - return script -} - -// TestFinalizePendingTxProjection tests the projection handler that runs when -// an offchain tx is finalized (Requested -> Accepted -> Finalized). -// -// When finalization happens after the tx's expiry timestamp has passed, the -// handler needs to check whether the input vtxos have been swept on-chain by -// the server. If any input is swept, the newly created output vtxos must also -// be marked as swept (they can't be spent on-chain since their inputs are gone). -// -// Two cases: -// - Input vtxos were swept by the server -> output vtxos must be marked swept. -// - Input vtxos were NOT swept (round expired but server hasn't reclaimed yet) -// -> output vtxos should NOT be marked swept. -func TestFinalizePendingTxProjection(t *testing.T) { - outputPkScript := taprootPkScript(t, pubkey) - - checkpointTxid1 := randomString(32) - checkpointTxid2 := randomString(32) - rootCommitmentTxid := randomString(32) - commitmentTxid := randomString(32) - - // The mock decoder is swapped per-subtest to return unique outpoints. - decoder := &mockTxDecoder{} - - tests := []struct { - name string - inputSwept bool - expectSwept bool - }{ - { - // The server already swept the inputs on-chain (round expired and - // the server reclaimed the funds). Finalizing the offchain tx at - // this point should propagate the swept status to the outputs. - name: "finalize_pending_tx_after_swept_by_server", - inputSwept: true, - expectSwept: true, - }, - { - // The round expired but the server has NOT swept the inputs yet. - // The outputs are still valid on-chain so they should not be - // marked as swept. - name: "finalize_pending_tx_after_expired_not_swept", - inputSwept: false, - expectSwept: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Fresh db per subtest for clean isolation. - dbDir := t.TempDir() - svc, err := db.NewService(db.ServiceConfig{ - EventStoreType: "badger", - DataStoreType: "sqlite", - EventStoreConfig: []interface{}{"", nil}, - DataStoreConfig: []interface{}{dbDir}, - }, decoder) - require.NoError(t, err) - defer svc.Close() - - ctx := context.Background() - - // Generate unique input/output outpoints per subtest. - in1 := domain.Outpoint{Txid: randomString(32), VOut: 0} - in2 := domain.Outpoint{Txid: randomString(32), VOut: 0} - outTxid := randomString(32) - - // Configure the mock decoder to map the ark tx to our test - // inputs and outputs. The projection handler calls DecodeTx on - // the finalized ark tx to discover which vtxos are consumed - // (inputs) and which are created (outputs). - decoder.decodeFn = func(tx string) (string, []ports.TxIn, []ports.TxOut, error) { - return outTxid, []ports.TxIn{in1, in2}, []ports.TxOut{ - {Amount: 1000, PkScript: outputPkScript}, - }, nil - } - - // Pre-populate the input vtxos in the store. The Swept flag - // simulates whether the server has already swept them on-chain. - inputVtxos := []domain.Vtxo{ - { - Outpoint: in1, - PubKey: pubkey, - Amount: 500, - Swept: tt.inputSwept, - RootCommitmentTxid: rootCommitmentTxid, - CommitmentTxids: []string{rootCommitmentTxid}, - }, - { - Outpoint: in2, - PubKey: pubkey, - Amount: 500, - Swept: tt.inputSwept, - RootCommitmentTxid: rootCommitmentTxid, - CommitmentTxids: []string{rootCommitmentTxid}, - }, - } - err = svc.Vtxos().AddVtxos(ctx, inputVtxos) - require.NoError(t, err) - - // The expiry timestamp is in the past so the projection handler - // will enter the "expired at finalization" code path and check - // whether the input vtxos are swept. - expiredTimestamp := time.Now().Add(-1 * time.Hour).Unix() - txId := randomString(32) - - // Walk the offchain tx through its full lifecycle: - // Requested -> Accepted (with expired timestamp) -> Finalized. - // Saving these events triggers the projection handler async. - events := []domain.Event{ - domain.OffchainTxRequested{ - OffchainTxEvent: domain.OffchainTxEvent{ - Id: txId, - Type: domain.EventTypeOffchainTxRequested, - }, - ArkTx: "mock_ark_tx", - UnsignedCheckpointTxs: map[string]string{ - checkpointTxid1: "unsigned1", - checkpointTxid2: "unsigned2", - }, - StartingTimestamp: time.Now().Unix(), - }, - domain.OffchainTxAccepted{ - OffchainTxEvent: domain.OffchainTxEvent{ - Id: txId, - Type: domain.EventTypeOffchainTxAccepted, - }, - FinalArkTx: "mock_final_ark_tx", - SignedCheckpointTxs: map[string]string{ - checkpointTxid1: "signed1", - checkpointTxid2: "signed2", - }, - CommitmentTxids: map[string]string{ - checkpointTxid1: rootCommitmentTxid, - checkpointTxid2: commitmentTxid, - }, - RootCommitmentTxid: rootCommitmentTxid, - ExpiryTimestamp: expiredTimestamp, - }, - domain.OffchainTxFinalized{ - OffchainTxEvent: domain.OffchainTxEvent{ - Id: txId, - Type: domain.EventTypeOffchainTxFinalized, - }, - FinalCheckpointTxs: map[string]string{ - checkpointTxid1: "final1", - checkpointTxid2: "final2", - }, - Timestamp: time.Now().Unix(), - }, - } - - err = svc.Events().Save(ctx, domain.OffchainTxTopic, txId, events) - require.NoError(t, err) - - // The projection handler runs asynchronously via a goroutine, so - // poll until the output vtxo appears in the store. - require.Eventually(t, func() bool { - vtxos, err := svc.Vtxos().GetVtxos(ctx, []domain.Outpoint{ - {Txid: outTxid, VOut: 0}, - }) - return err == nil && len(vtxos) > 0 - }, 5*time.Second, 100*time.Millisecond) - - // Verify the output vtxo's Swept flag matches expectations. - outputVtxos, err := svc.Vtxos().GetVtxos(ctx, []domain.Outpoint{ - {Txid: outTxid, VOut: 0}, - }) - require.NoError(t, err) - require.Len(t, outputVtxos, 1) - require.Equal(t, tt.expectSwept, outputVtxos[0].Swept, - "expected Swept=%v for output vtxo", tt.expectSwept) - }) - } -} - func checkVtxos(t *testing.T, expectedVtxos, gotVtxos []domain.Vtxo) { sort.SliceStable(expectedVtxos, func(i, j int) bool { return expectedVtxos[i].Txid < expectedVtxos[j].Txid diff --git a/internal/test/e2e/e2e_test.go b/internal/test/e2e/e2e_test.go index 3d93e7af0..703a9a8de 100644 --- a/internal/test/e2e/e2e_test.go +++ b/internal/test/e2e/e2e_test.go @@ -895,6 +895,8 @@ func TestOffchainTx(t *testing.T) { ) }) + // In this test, Alice submits a tx and then fetches the pending tx by proviving an intent + // to finalize it. t.Run("finalize pending tx", func(t *testing.T) { ctx := t.Context() explorer, err := mempool_explorer.NewExplorer( @@ -1022,6 +1024,302 @@ func TestOffchainTx(t *testing.T) { require.Equal(t, txid, incomingFunds[0].Txid) }) + // In these tests, Alice submits an offchain tx and waits for the inputs to be swept before + // finalizing it. + // Covers both cases, the one where the inputs are swept by the server, and the other one, + // where they are expired but not yet swept. + // In both cases, the server should allow the finalization but the new vtxos should be marked + // as swept. + t.Run("finalize pending swept tx", func(t *testing.T) { + t.Run("vtxo already swept", func(t *testing.T) { + ctx := t.Context() + explorer, err := mempool_explorer.NewExplorer( + "http://localhost:3000", arklib.BitcoinRegTest, + mempool_explorer.WithTracker(false), + ) + require.NoError(t, err) + + alice, aliceWallet, _, arkSvc := setupArkSDKwithPublicKey(t) + t.Cleanup(func() { alice.Stop() }) + t.Cleanup(func() { arkSvc.Close() }) + + vtxo := faucetOffchain(t, alice, 0.00021) + + finalizedPendingTxs, err := alice.FinalizePendingTxs(ctx, nil) + require.NoError(t, err) + require.Empty(t, finalizedPendingTxs) + + _, offchainAddresses, _, _, err := aliceWallet.GetAddresses(ctx) + require.NoError(t, err) + require.NotEmpty(t, offchainAddresses) + offchainAddress := offchainAddresses[0] + + serverParams, err := arkSvc.GetInfo(ctx) + require.NoError(t, err) + + vtxoScript, err := script.ParseVtxoScript(offchainAddress.Tapscripts) + require.NoError(t, err) + forfeitClosures := vtxoScript.ForfeitClosures() + require.Len(t, forfeitClosures, 1) + closure := forfeitClosures[0] + + scriptBytes, err := closure.Script() + require.NoError(t, err) + + _, vtxoTapTree, err := vtxoScript.TapTree() + require.NoError(t, err) + + merkleProof, err := vtxoTapTree.GetTaprootMerkleProof( + txscript.NewBaseTapLeaf(scriptBytes).TapHash(), + ) + require.NoError(t, err) + + ctrlBlock, err := txscript.ParseControlBlock(merkleProof.ControlBlock) + require.NoError(t, err) + + tapscript := &waddrmgr.Tapscript{ + ControlBlock: ctrlBlock, + RevealedScript: merkleProof.Script, + } + + checkpointTapscript, err := hex.DecodeString(serverParams.CheckpointTapscript) + require.NoError(t, err) + + vtxoHash, err := chainhash.NewHashFromStr(vtxo.Txid) + require.NoError(t, err) + + addr, err := arklib.DecodeAddressV0(offchainAddress.Address) + require.NoError(t, err) + pkscript, err := addr.GetPkScript() + require.NoError(t, err) + + ptx, checkpointsPtx, err := offchain.BuildTxs( + []offchain.VtxoInput{ + { + Outpoint: &wire.OutPoint{ + Hash: *vtxoHash, + Index: vtxo.VOut, + }, + Tapscript: tapscript, + Amount: int64(vtxo.Amount), + RevealedTapscripts: offchainAddress.Tapscripts, + }, + }, + []*wire.TxOut{ + { + Value: int64(vtxo.Amount), + PkScript: pkscript, + }, + }, + checkpointTapscript, + ) + require.NoError(t, err) + + encodedCheckpoints := make([]string, 0, len(checkpointsPtx)) + for _, checkpoint := range checkpointsPtx { + encoded, err := checkpoint.B64Encode() + require.NoError(t, err) + encodedCheckpoints = append(encodedCheckpoints, encoded) + } + + // sign the ark transaction + encodedArkTx, err := ptx.B64Encode() + require.NoError(t, err) + signedArkTx, err := aliceWallet.SignTransaction( + ctx, + explorer, + encodedArkTx, + ) + require.NoError(t, err) + + txid, _, _, err := arkSvc.SubmitTx(ctx, signedArkTx, encodedCheckpoints) + require.NoError(t, err) + require.NotEmpty(t, txid) + + // Make the vtxo expire + err = generateBlocks(21) + require.NoError(t, err) + + // Givetime to the server to sweep the vtxo + time.Sleep(30 * time.Second) + + // Ensure the vtxo is pending and swept + scriptStr := hex.EncodeToString(pkscript) + resp, err := alice.Indexer().GetVtxos( + ctx, indexer.WithScripts([]string{scriptStr}), indexer.WithPendingOnly(), + ) + require.NoError(t, err) + require.NotNil(t, resp) + require.NotEmpty(t, resp.Vtxos) + require.True(t, resp.Vtxos[0].Spent) + require.True(t, resp.Vtxos[0].Swept) + + var incomingFunds []types.Vtxo + var incomingErr error + wg := &sync.WaitGroup{} + wg.Go(func() { + incomingFunds, incomingErr = alice.NotifyIncomingFunds(ctx, offchainAddress.Address) + }) + + // Finalize the pending tx and ensure the new vtxo is marked as swept + finalizedTxIds, err := alice.FinalizePendingTxs(ctx, nil) + require.NoError(t, err) + require.NotEmpty(t, finalizedTxIds) + require.Equal(t, 1, len(finalizedTxIds)) + require.Equal(t, txid, finalizedTxIds[0]) + + wg.Wait() + require.NoError(t, incomingErr) + require.NotEmpty(t, incomingFunds) + require.Len(t, incomingFunds, 1) + require.Equal(t, txid, incomingFunds[0].Txid) + require.True(t, incomingFunds[0].Swept) + }) + + t.Run("vtxo expired but not swept", func(t *testing.T) { + ctx := t.Context() + explorer, err := mempool_explorer.NewExplorer( + "http://localhost:3000", arklib.BitcoinRegTest, + mempool_explorer.WithTracker(false), + ) + require.NoError(t, err) + + alice, aliceWallet, _, arkSvc := setupArkSDKwithPublicKey(t) + t.Cleanup(func() { alice.Stop() }) + t.Cleanup(func() { arkSvc.Close() }) + + vtxo := faucetOffchain(t, alice, 0.00021) + + finalizedPendingTxs, err := alice.FinalizePendingTxs(ctx, nil) + require.NoError(t, err) + require.Empty(t, finalizedPendingTxs) + + _, offchainAddresses, _, _, err := aliceWallet.GetAddresses(ctx) + require.NoError(t, err) + require.NotEmpty(t, offchainAddresses) + offchainAddress := offchainAddresses[0] + + serverParams, err := arkSvc.GetInfo(ctx) + require.NoError(t, err) + + vtxoScript, err := script.ParseVtxoScript(offchainAddress.Tapscripts) + require.NoError(t, err) + forfeitClosures := vtxoScript.ForfeitClosures() + require.Len(t, forfeitClosures, 1) + closure := forfeitClosures[0] + + scriptBytes, err := closure.Script() + require.NoError(t, err) + + _, vtxoTapTree, err := vtxoScript.TapTree() + require.NoError(t, err) + + merkleProof, err := vtxoTapTree.GetTaprootMerkleProof( + txscript.NewBaseTapLeaf(scriptBytes).TapHash(), + ) + require.NoError(t, err) + + ctrlBlock, err := txscript.ParseControlBlock(merkleProof.ControlBlock) + require.NoError(t, err) + + tapscript := &waddrmgr.Tapscript{ + ControlBlock: ctrlBlock, + RevealedScript: merkleProof.Script, + } + + checkpointTapscript, err := hex.DecodeString(serverParams.CheckpointTapscript) + require.NoError(t, err) + + vtxoHash, err := chainhash.NewHashFromStr(vtxo.Txid) + require.NoError(t, err) + + addr, err := arklib.DecodeAddressV0(offchainAddress.Address) + require.NoError(t, err) + pkscript, err := addr.GetPkScript() + require.NoError(t, err) + + ptx, checkpointsPtx, err := offchain.BuildTxs( + []offchain.VtxoInput{ + { + Outpoint: &wire.OutPoint{ + Hash: *vtxoHash, + Index: vtxo.VOut, + }, + Tapscript: tapscript, + Amount: int64(vtxo.Amount), + RevealedTapscripts: offchainAddress.Tapscripts, + }, + }, + []*wire.TxOut{ + { + Value: int64(vtxo.Amount), + PkScript: pkscript, + }, + }, + checkpointTapscript, + ) + require.NoError(t, err) + + encodedCheckpoints := make([]string, 0, len(checkpointsPtx)) + for _, checkpoint := range checkpointsPtx { + encoded, err := checkpoint.B64Encode() + require.NoError(t, err) + encodedCheckpoints = append(encodedCheckpoints, encoded) + } + + // sign the ark transaction + encodedArkTx, err := ptx.B64Encode() + require.NoError(t, err) + signedArkTx, err := aliceWallet.SignTransaction( + ctx, + explorer, + encodedArkTx, + ) + require.NoError(t, err) + + txid, _, _, err := arkSvc.SubmitTx(ctx, signedArkTx, encodedCheckpoints) + require.NoError(t, err) + require.NotEmpty(t, txid) + + // Make the vtxo expire + err = generateBlocks(21) + require.NoError(t, err) + + // Don't give time to the server to mark the vtxo as swept + // Ensure the vtxo is pending but not swept yet + scriptStr := hex.EncodeToString(pkscript) + resp, err := alice.Indexer().GetVtxos( + ctx, indexer.WithScripts([]string{scriptStr}), indexer.WithPendingOnly(), + ) + require.NoError(t, err) + require.NotNil(t, resp) + require.NotEmpty(t, resp.Vtxos) + require.True(t, resp.Vtxos[0].Spent) + require.False(t, resp.Vtxos[0].Swept) + + var incomingFunds []types.Vtxo + var incomingErr error + wg := &sync.WaitGroup{} + wg.Go(func() { + incomingFunds, incomingErr = alice.NotifyIncomingFunds(ctx, offchainAddress.Address) + }) + + // Finalize the pending tx and ensure the new vtxo is still marked as swept + finalizedTxIds, err := alice.FinalizePendingTxs(ctx, nil) + require.NoError(t, err) + require.NotEmpty(t, finalizedTxIds) + require.Equal(t, 1, len(finalizedTxIds)) + require.Equal(t, txid, finalizedTxIds[0]) + + wg.Wait() + require.NoError(t, incomingErr) + require.NotEmpty(t, incomingFunds) + require.Len(t, incomingFunds, 1) + require.Equal(t, txid, incomingFunds[0].Txid) + require.True(t, incomingFunds[0].Swept) + }) + }) + // In this test, we ensure that a tx with too many OP_RETURN outputs gets rejected. // The server is configured with a max of 3 OP_RETURN outputs, so submitting 4 should fail. t.Run("too many op return outputs", func(t *testing.T) { From 721c66f74e649ef6842d709aae76876b31e99534 Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Wed, 8 Apr 2026 16:52:21 +0200 Subject: [PATCH 05/16] Cleaup delays in config --- README.md | 4 +-- docker-compose.regtest.yml | 1 - envs/arkd.dev.env | 2 -- envs/arkd.light.env | 4 +-- internal/config/config.go | 72 +++++++++++++------------------------- pkg/ark-lib/locktime.go | 4 ++- 6 files changed, 30 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 126edde6d..7503a6def 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ The `arkd` server can be configured using environment variables. | `ARKD_LIVE_STORE_TYPE` | Cache service type (redis, inmemory) | `redis` | | `ARKD_REDIS_URL` | Redis db connection url if `ARKD_LIVE_STORE_TYPE` is set to `redis` | - | | `ARKD_REDIS_NUM_OF_RETRIES` | Maximum number of retries for Redis write operations in case of conflicts | - | -| `ARKD_VTXO_TREE_EXPIRY` | VTXO tree expiry in seconds | `604672` (7 days) | +| `ARKD_VTXO_TREE_EXPIRY` | VTXO tree expiry in seconds. Values below `512` are allowed only on regtest | `604672` (7 days) | | `ARKD_UNILATERAL_EXIT_DELAY` | Unilateral exit delay in seconds | `86400` (24 hours) | | `ARKD_BOARDING_EXIT_DELAY` | Boarding exit delay in seconds | `7776000` (3 months) | | `ARKD_ESPLORA_URL` | Esplora API URL | `https://blockstream.info/api` | @@ -92,7 +92,6 @@ The `arkd` server can be configured using environment variables. | `ARKD_VTXO_MIN_AMOUNT` | The minimum allowed amount for vtxos | `-1` (dust) | | `ARKD_BAN_DURATION` | Ban duration in seconds | `300` (5 minutes) | | `ARKD_BAN_THRESHOLD` | Number of crimes to trigger a ban | `3` | -| `ARKD_SCHEDULER_TYPE` | Scheduler type (gocron, block) | `gocron` | | `ARKD_CHECKPOINT_EXIT_DELAY` | Checkpoint exit delay in seconds | `86400` (24 hours) | | `ARKD_TLS_EXTRA_IP` | Extra IP addresses for TLS (comma-separated) | - | | `ARKD_TLS_EXTRA_DOMAIN` | Extra domains for TLS (comma-separated) | - | @@ -105,7 +104,6 @@ The `arkd` server can be configured using environment variables. | `ARKD_SCHEDULED_SESSION_MAX_ROUND_PARTICIPANTS_COUNT` | Max participants for scheduled sessions | - | | `ARKD_OTEL_COLLECTOR_ENDPOINT` | OpenTelemetry collector endpoint | - | | `ARKD_OTEL_PUSH_INTERVAL` | OpenTelemetry push interval in seconds | `10` | -| `ARKD_ALLOW_CSV_BLOCK_TYPE` | Allow CSV block type | `false` | | `ARKD_HEARTBEAT_INTERVAL` | Heartbeat interval in seconds | `60` | | `ARKD_ROUND_REPORT_ENABLED` | Enable round report service | `false` | diff --git a/docker-compose.regtest.yml b/docker-compose.regtest.yml index 562ee309f..e6fd3d8bd 100644 --- a/docker-compose.regtest.yml +++ b/docker-compose.regtest.yml @@ -88,7 +88,6 @@ services: - ARKD_LOG_LEVEL=6 - ARKD_NO_MACAROONS=true - ARKD_VTXO_TREE_EXPIRY=20 - - ARKD_SCHEDULER_TYPE=block - ARKD_UNILATERAL_EXIT_DELAY=512 - ARKD_BOARDING_EXIT_DELAY=1024 - ARKD_CHECKPOINT_EXIT_DELAY=10 diff --git a/envs/arkd.dev.env b/envs/arkd.dev.env index d8f74c8e0..1c856a1d5 100644 --- a/envs/arkd.dev.env +++ b/envs/arkd.dev.env @@ -1,6 +1,5 @@ ARKD_LOG_LEVEL=5 ARKD_NO_MACAROONS=true -ARKD_SCHEDULER_TYPE=block ARKD_VTXO_TREE_EXPIRY=20 ARKD_CHECKPOINT_EXIT_DELAY=10 ARKD_UNILATERAL_EXIT_DELAY=512 @@ -12,7 +11,6 @@ ARKD_PG_DB_AUTOCREATE=true ARKD_PG_DB_URL=postgresql://postgres@127.0.0.1:5432/projection?sslmode=disable ARKD_PG_EVENT_DB_URL=postgresql://postgres@127.0.0.1:5432/event?sslmode=disable ARKD_REDIS_URL=redis://localhost:6379/0 -ARKD_ALLOW_CSV_BLOCK_TYPE=true ARKD_VTXO_MIN_AMOUNT=1 ARKD_BAN_THRESHOLD=1 ARKD_ONCHAIN_OUTPUT_FEE=100 diff --git a/envs/arkd.light.env b/envs/arkd.light.env index a0ab6964d..c26c5b6b6 100644 --- a/envs/arkd.light.env +++ b/envs/arkd.light.env @@ -1,6 +1,5 @@ ARKD_LOG_LEVEL=5 ARKD_NO_MACAROONS=true -ARKD_VTXO_TREE_EXPIRY=512 ARKD_UNILATERAL_EXIT_DELAY=512 ARKD_BOARDING_EXIT_DELAY=1024 ARKD_DATADIR=./data/regtest @@ -9,8 +8,9 @@ ARKD_WALLET_ADDR=127.0.0.1:6060 ARKD_LIVE_STORE_TYPE=inmemory ARKD_DB_TYPE=sqlite ARKD_EVENT_DB_TYPE=badger -ARKD_ALLOW_CSV_BLOCK_TYPE=true ARKD_SESSION_DURATION=10 ARKD_VTXO_MIN_AMOUNT=1 ARKD_BAN_THRESHOLD=1 ARKD_ONCHAIN_OUTPUT_FEE=100 +ARKD_VTXO_TREE_EXPIRY=20 +ARKD_CHECKPOINT_EXIT_DELAY=10 diff --git a/internal/config/config.go b/internal/config/config.go index b99b42648..41fe14db2 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -44,10 +44,6 @@ var ( "sqlite": {}, "postgres": {}, } - supportedSchedulers = supportedType{ - "gocron": {}, - "block": {}, - } supportedTxBuilders = supportedType{ "covenantless": {}, } @@ -82,7 +78,6 @@ type Config struct { SessionDuration int64 BanDuration int64 BanThreshold int64 // number of crimes to trigger a ban - SchedulerType string TxBuilderType string LiveStoreType string RedisUrl string @@ -95,7 +90,6 @@ type Config struct { CheckpointExitDelay arklib.RelativeLocktime BoardingExitDelay arklib.RelativeLocktime NoteUriPrefix string - AllowCSVBlockType bool HeartbeatInterval int64 VtxoNoCsvValidationCutoffDate int64 @@ -175,7 +169,6 @@ var ( DbUrl = "PG_DB_URL" PostgresAutoCreateDB = "PG_DB_AUTOCREATE" EventDbUrl = "PG_EVENT_DB_URL" - SchedulerType = "SCHEDULER_TYPE" TxBuilderType = "TX_BUILDER_TYPE" LiveStoreType = "LIVE_STORE_TYPE" RedisUrl = "REDIS_URL" @@ -212,7 +205,6 @@ var ( VtxoMaxAmount = "VTXO_MAX_AMOUNT" UtxoMinAmount = "UTXO_MIN_AMOUNT" VtxoMinAmount = "VTXO_MIN_AMOUNT" - AllowCSVBlockType = "ALLOW_CSV_BLOCK_TYPE" HeartbeatInterval = "HEARTBEAT_INTERVAL" RoundReportServiceEnabled = "ROUND_REPORT_ENABLED" SettlementMinExpiryGap = "SETTLEMENT_MIN_EXPIRY_GAP" @@ -234,7 +226,6 @@ var ( DefaultAdminPort = 7071 defaultDbType = "postgres" defaultEventDbType = "postgres" - defaultSchedulerType = "gocron" defaultTxBuilderType = "covenantless" defaultLiveStoreType = "redis" defaultRedisTxNumOfRetries = 10 @@ -251,7 +242,6 @@ var ( defaultUtxoMinAmount = -1 // -1 means native dust limit (default) defaultVtxoMinAmount = -1 // -1 means native dust limit (default) defaultVtxoMaxAmount = -1 // -1 means no limit (default) - defaultAllowCSVBlockType = false defaultRoundMaxParticipantsCount = 128 defaultRoundMinParticipantsCount = 1 @@ -281,7 +271,6 @@ func LoadConfig() (*Config, error) { viper.SetDefault(BanDuration, defaultBanDuration) viper.SetDefault(BanThreshold, defaultBanThreshold) viper.SetDefault(VtxoTreeExpiry, defaultVtxoTreeExpiry) - viper.SetDefault(SchedulerType, defaultSchedulerType) viper.SetDefault(EventDbType, defaultEventDbType) viper.SetDefault(TxBuilderType, defaultTxBuilderType) viper.SetDefault(UnilateralExitDelay, defaultUnilateralExitDelay) @@ -299,7 +288,6 @@ func LoadConfig() (*Config, error) { viper.SetDefault(VtxoMinAmount, defaultVtxoMinAmount) viper.SetDefault(LiveStoreType, defaultLiveStoreType) viper.SetDefault(RedisTxNumOfRetries, defaultRedisTxNumOfRetries) - viper.SetDefault(AllowCSVBlockType, defaultAllowCSVBlockType) viper.SetDefault(OtelPushInterval, defaultOtelPushInterval) viper.SetDefault(HeartbeatInterval, defaultHeartbeatInterval) viper.SetDefault(RoundReportServiceEnabled, defaultRoundReportServiceEnabled) @@ -341,11 +329,6 @@ func LoadConfig() (*Config, error) { } } - allowCSVBlockType := viper.GetBool(AllowCSVBlockType) - if viper.GetString(SchedulerType) == "block" { - allowCSVBlockType = true - } - signerAddr := viper.GetString(SignerAddr) if signerAddr == "" { signerAddr = viper.GetString(WalletAddr) @@ -368,7 +351,6 @@ func LoadConfig() (*Config, error) { AdminPort: adminPort, EventDbType: viper.GetString(EventDbType), DbType: viper.GetString(DbType), - SchedulerType: viper.GetString(SchedulerType), TxBuilderType: viper.GetString(TxBuilderType), LiveStoreType: viper.GetString(LiveStoreType), RedisUrl: redisUrl, @@ -416,7 +398,6 @@ func LoadConfig() (*Config, error) { UtxoMinAmount: viper.GetInt64(UtxoMinAmount), VtxoMaxAmount: viper.GetInt64(VtxoMaxAmount), VtxoMinAmount: viper.GetInt64(VtxoMinAmount), - AllowCSVBlockType: allowCSVBlockType, RoundReportServiceEnabled: viper.GetBool(RoundReportServiceEnabled), SettlementMinExpiryGap: viper.GetInt64(SettlementMinExpiryGap), MaxTxWeight: viper.GetUint64(MaxTxWeight), @@ -459,12 +440,6 @@ func (c *Config) Validate() error { if !supportedDbs.supports(c.DbType) { return fmt.Errorf("db type not supported, please select one of: %s", supportedDbs) } - if !supportedSchedulers.supports(c.SchedulerType) { - return fmt.Errorf( - "scheduler type not supported, please select one of: %s", - supportedSchedulers, - ) - } if !supportedTxBuilders.supports(c.TxBuilderType) { return fmt.Errorf( "tx builder type not supported, please select one of: %s", @@ -492,24 +467,7 @@ func (c *Config) Validate() error { if c.BanThreshold < 1 { log.Debugf("autoban is disabled") } - if c.VtxoTreeExpiry.Type == arklib.LocktimeTypeBlock { - if c.SchedulerType != "block" { - return fmt.Errorf( - "scheduler type must be block if vtxo tree expiry is expressed in blocks", - ) - } - if !c.AllowCSVBlockType { - return fmt.Errorf( - "CSV block type must be allowed if vtxo tree expiry is expressed in blocks", - ) - } - } else { // seconds - if c.SchedulerType != "gocron" { - return fmt.Errorf( - "scheduler type must be gocron if vtxo tree expiry is expressed in seconds", - ) - } - + if c.VtxoTreeExpiry.Type == arklib.LocktimeTypeSecond { // vtxo tree expiry must be a multiple of 512 if expressed in seconds if c.VtxoTreeExpiry.Value%minAllowedSequence != 0 { c.VtxoTreeExpiry.Value -= c.VtxoTreeExpiry.Value % minAllowedSequence @@ -539,6 +497,11 @@ func (c *Config) Validate() error { ) } + // Ensure vtxo tree expiry and checkpoint exit delay are of the same type + if c.CheckpointExitDelay.Type != c.VtxoTreeExpiry.Type { + return fmt.Errorf("checkpoint and vtxo tree locktimes must be of the same type") + } + if c.CheckpointExitDelay.Type == arklib.LocktimeTypeSecond { if c.CheckpointExitDelay.Value%minAllowedSequence != 0 { c.CheckpointExitDelay.Value -= c.CheckpointExitDelay.Value % minAllowedSequence @@ -642,6 +605,19 @@ func (c *Config) Validate() error { if err := c.alertsService(); err != nil { return err } + + // Enforce that if the network is not regtest, the locktimes must be expressed in seconds. + // These checks must be done after the wallet service is initialized, as it is needed to + // determine the network. + if c.VtxoTreeExpiry.Type == arklib.LocktimeTypeBlock && + c.network.Name != arklib.BitcoinRegTest.Name { + return fmt.Errorf("vtxo tree expiry expressed in blocks is allowed only on regtest") + } + if c.CheckpointExitDelay.Type == arklib.LocktimeTypeBlock && + c.network.Name != arklib.BitcoinRegTest.Name { + return fmt.Errorf("checkpoint exit delay expressed in blocks is allowed only on regtest") + } + return nil } @@ -825,10 +801,10 @@ func (c *Config) liveStoreService() error { func (c *Config) schedulerService() error { var svc ports.SchedulerService var err error - switch c.SchedulerType { - case "gocron": + switch c.VtxoTreeExpiry.Type { + case arklib.LocktimeTypeSecond: svc = timescheduler.NewScheduler() - case "block": + case arklib.LocktimeTypeBlock: svc, err = blockscheduler.NewScheduler(c.EsploraURL) default: err = fmt.Errorf("unknown scheduler type") @@ -861,11 +837,11 @@ func (c *Config) appService() error { if err := c.txBuilderService(); err != nil { return err } - roundReportSvc, err := c.RoundReportService() if err != nil { return err } + allowCSVBlockType := c.VtxoTreeExpiry.Type == arklib.LocktimeTypeBlock svc, err := application.NewService( c.wallet, c.signer, c.repo, c.txBuilder, c.scanner, @@ -875,7 +851,7 @@ func (c *Config) appService() error { c.SessionDuration, c.RoundMinParticipantsCount, c.RoundMaxParticipantsCount, c.UtxoMaxAmount, c.UtxoMinAmount, c.VtxoMaxAmount, c.VtxoMinAmount, c.BanDuration, c.BanThreshold, c.MaxTxWeight, c.AssetTxMaxWeightRatio, - *c.network, c.AllowCSVBlockType, c.NoteUriPrefix, + *c.network, allowCSVBlockType, c.NoteUriPrefix, ssStartTime, ssEndTime, ssPeriod, ssDuration, c.ScheduledSessionMinRoundParticipantsCount, c.ScheduledSessionMaxRoundParticipantsCount, c.SettlementMinExpiryGap, diff --git a/pkg/ark-lib/locktime.go b/pkg/ark-lib/locktime.go index eb97b83c4..867dda201 100644 --- a/pkg/ark-lib/locktime.go +++ b/pkg/ark-lib/locktime.go @@ -16,7 +16,9 @@ const ( SECONDS_MAX = SEQUENCE_LOCKTIME_MASK << SEQUENCE_LOCKTIME_GRANULARITY SEQUENCE_LOCKTIME_DISABLE_FLAG = 1 << 31 - SECONDS_PER_BLOCK = 10 * 60 // 10 minutes + // SECONDS_PER_BLOCK is used to convert block-based locktimes to seconds. + // The value of 1 sec/block is used so that number of blocks refers to number of seconds. + SECONDS_PER_BLOCK = 1 // before this value, nLocktime is interpreted as blockheight nLocktimeMinSeconds = 500_000_000 From 0c3cbe4f5f674ca31df0def9f811ce4833dce114 Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Wed, 8 Apr 2026 17:15:18 +0200 Subject: [PATCH 06/16] Fix marking new vtxo as swept if inputs are swept or expired + Fix sleeping times in tests --- internal/core/application/service.go | 17 +++++++++++++++++ internal/infrastructure/db/service.go | 26 +++++++++----------------- internal/test/e2e/e2e_test.go | 18 ++++++++++-------- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/internal/core/application/service.go b/internal/core/application/service.go index 849be1988..79bbae9cb 100644 --- a/internal/core/application/service.go +++ b/internal/core/application/service.go @@ -369,6 +369,23 @@ func (s *service) registerEventHandlers() { return } + // Make sure to mark new vtxos as swept if any of the spent inputs is swept as well or + // expired + sweptIns := false + now := time.Now() + for _, vtxo := range spentVtxos { + if vtxo.Swept || now.After(time.Unix(vtxo.ExpiresAt, 0)) { + sweptIns = true + break + } + } + + if sweptIns { + for i := range newVtxos { + newVtxos[i].Swept = true + } + } + checkpointTxsByOutpoint := make(map[string]TxData) for txid, tx := range offchainTx.CheckpointTxs { // nolint diff --git a/internal/infrastructure/db/service.go b/internal/infrastructure/db/service.go index d32f6c735..70a9b9bb7 100644 --- a/internal/infrastructure/db/service.go +++ b/internal/infrastructure/db/service.go @@ -521,7 +521,7 @@ func (s *service) updateProjectionsAfterOffchainTxEvents(events []domain.Event) } log.Debugf("spent %d vtxos", len(spentVtxos)) case offchainTx.IsFinalized(): - txid, ins, outs, err := s.txDecoder.DecodeTx(offchainTx.ArkTx) + txid, _, outs, err := s.txDecoder.DecodeTx(offchainTx.ArkTx) if err != nil { log.WithError(err).Warn("failed to decode ark tx") return @@ -534,22 +534,14 @@ func (s *service) updateProjectionsAfterOffchainTxEvents(events []domain.Event) } txSwept := false - // if the tx is expired at finalization step, it may be possible the new outputs should be marked swept - // it depends if the inputs are swept or not - if offchainTx.ExpiryTimestamp > 0 && - time.Now().After(time.Unix(offchainTx.ExpiryTimestamp, 0)) { - inputVtxos, err := s.vtxoStore.GetVtxos(ctx, ins) - // if an error happened, we assume the vtxo is swept. it should never happen but it's to avoid skipping adding vtxo to db - txSwept = err != nil - - for _, inputVtxo := range inputVtxos { - if inputVtxo.Swept { - txSwept = true - break - } - } - } - + batch, err := s.roundStore.GetRoundWithCommitmentTxid(ctx, offchainTx.RootCommitmentTxId) + // We consider the tx swept if: + // - there is an error fetching the batch (this is just fallback, should never happen) + // - the batch is swept + // - the tx expired (meaning one or all its inputs expired and are already swept or about + // to be swept) + txSwept = err != nil || (batch != nil && len(batch.SweepTxs) > 0) || + time.Now().After(time.Unix(offchainTx.ExpiryTimestamp, 0)) // once the offchain tx is finalized, the user signed the checkpoint txs // thus, we can create the new vtxos in the db. newVtxos := make([]domain.Vtxo, 0, len(outs)) diff --git a/internal/test/e2e/e2e_test.go b/internal/test/e2e/e2e_test.go index 703a9a8de..ec37f3965 100644 --- a/internal/test/e2e/e2e_test.go +++ b/internal/test/e2e/e2e_test.go @@ -1141,7 +1141,7 @@ func TestOffchainTx(t *testing.T) { require.NoError(t, err) // Givetime to the server to sweep the vtxo - time.Sleep(30 * time.Second) + time.Sleep(15 * time.Second) // Ensure the vtxo is pending and swept scriptStr := hex.EncodeToString(pkscript) @@ -1281,6 +1281,9 @@ func TestOffchainTx(t *testing.T) { require.NoError(t, err) require.NotEmpty(t, txid) + // Make the tx expire (the tx has 20 block expiration converted to 20 seconds in timestamp) + time.Sleep(30 * time.Second) + // Make the vtxo expire err = generateBlocks(21) require.NoError(t, err) @@ -2760,9 +2763,8 @@ func TestReactToFraud(t *testing.T) { require.NotEmpty(t, res.Txid) wg.Wait() - time.Sleep(time.Second) + time.Sleep(3 * time.Second) - time.Sleep(2 * time.Second) spendable, _, err := alice.ListVtxos(ctx) require.NoError(t, err) require.NotEmpty(t, spendable) @@ -3132,7 +3134,7 @@ func TestSweep(t *testing.T) { require.NoError(t, err) // give time for the server to process the sweep - time.Sleep(20 * time.Second) + time.Sleep(10 * time.Second) // verify that the checkpoint output has been put onchain // and that the VTXO has been swept @@ -3219,7 +3221,7 @@ func TestSweep(t *testing.T) { require.NoError(t, err) // Wait for server to process the sweep - time.Sleep(20 * time.Second) + time.Sleep(10 * time.Second) spendable, _, err := alice.ListVtxos(ctx) require.NoError(t, err) @@ -3364,7 +3366,7 @@ func TestSweep(t *testing.T) { require.NoError(t, err) // Wait for server to process the sweep - time.Sleep(30 * time.Second) + time.Sleep(10 * time.Second) // alice vtxos should not be swept yet aliceVtxos, _, err := alice.ListVtxos(ctx) @@ -3402,7 +3404,7 @@ func TestSweep(t *testing.T) { require.NoError(t, err) // give time for the server to process the sweep and indexer to sync the vtxo table - time.Sleep(60 * time.Second) + time.Sleep(10 * time.Second) // verify that all vtxos have been swept aliceVtxos, _, err = alice.ListVtxos(ctx) @@ -3467,7 +3469,7 @@ func TestSweep(t *testing.T) { require.NoError(t, err) // Wait for server to attempt the sweep (it should fail due to dust amount) - time.Sleep(25 * time.Second) + time.Sleep(10 * time.Second) // Verify the vtxo is not swept yet (automatic sweep failed) spendable, _, err := alice.ListVtxos(ctx) From eb676b4a4648c1ba3d92dbf1d5c20f70363c758c Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Wed, 8 Apr 2026 21:08:53 +0200 Subject: [PATCH 07/16] Fixes --- internal/core/application/service.go | 3 +-- internal/test/e2e/e2e_test.go | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/internal/core/application/service.go b/internal/core/application/service.go index 79bbae9cb..a2a4845a7 100644 --- a/internal/core/application/service.go +++ b/internal/core/application/service.go @@ -372,9 +372,8 @@ func (s *service) registerEventHandlers() { // Make sure to mark new vtxos as swept if any of the spent inputs is swept as well or // expired sweptIns := false - now := time.Now() for _, vtxo := range spentVtxos { - if vtxo.Swept || now.After(time.Unix(vtxo.ExpiresAt, 0)) { + if vtxo.Swept || !s.sweeper.scheduler.AfterNow(vtxo.ExpiresAt) { sweptIns = true break } diff --git a/internal/test/e2e/e2e_test.go b/internal/test/e2e/e2e_test.go index ec37f3965..0818069ca 100644 --- a/internal/test/e2e/e2e_test.go +++ b/internal/test/e2e/e2e_test.go @@ -3220,8 +3220,8 @@ func TestSweep(t *testing.T) { err = generateBlocks(30) require.NoError(t, err) - // Wait for server to process the sweep - time.Sleep(10 * time.Second) + // Wait for server to process the sweep (needs extra time after restart) + time.Sleep(20 * time.Second) spendable, _, err := alice.ListVtxos(ctx) require.NoError(t, err) From c0a95757f4c316fe627c1f19cbcade04644357a0 Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Thu, 9 Apr 2026 19:03:36 +0200 Subject: [PATCH 08/16] Fixes --- docker-compose.regtest.yml | 5 +- envs/arkd.dev.env | 5 +- envs/arkd.light.env | 5 +- internal/config/config.go | 112 ++++++++++++++++----------- internal/core/application/service.go | 9 ++- internal/test/e2e/e2e_test.go | 16 ++-- 6 files changed, 90 insertions(+), 62 deletions(-) diff --git a/docker-compose.regtest.yml b/docker-compose.regtest.yml index e6fd3d8bd..1f9c55e5a 100644 --- a/docker-compose.regtest.yml +++ b/docker-compose.regtest.yml @@ -88,8 +88,9 @@ services: - ARKD_LOG_LEVEL=6 - ARKD_NO_MACAROONS=true - ARKD_VTXO_TREE_EXPIRY=20 - - ARKD_UNILATERAL_EXIT_DELAY=512 - - ARKD_BOARDING_EXIT_DELAY=1024 + - ARKD_UNILATERAL_EXIT_DELAY=10 + - ARKD_PUBLIC_UNILATERAL_EXIT_DELAY=10 + - ARKD_BOARDING_EXIT_DELAY=30 - ARKD_CHECKPOINT_EXIT_DELAY=10 - ARKD_DATADIR=./data/regtest - ARKD_WALLET_ADDR=arkd-wallet:6060 diff --git a/envs/arkd.dev.env b/envs/arkd.dev.env index 1c856a1d5..642bf4dcf 100644 --- a/envs/arkd.dev.env +++ b/envs/arkd.dev.env @@ -2,8 +2,9 @@ ARKD_LOG_LEVEL=5 ARKD_NO_MACAROONS=true ARKD_VTXO_TREE_EXPIRY=20 ARKD_CHECKPOINT_EXIT_DELAY=10 -ARKD_UNILATERAL_EXIT_DELAY=512 -ARKD_BOARDING_EXIT_DELAY=1024 +ARKD_UNILATERAL_EXIT_DELAY=10 +ARKD_PUBLIC_UNILATERAL_EXIT_DELAY=10 +ARKD_BOARDING_EXIT_DELAY=30 ARKD_DATADIR=./data/regtest ARKD_ESPLORA_URL=http://localhost:3000 ARKD_WALLET_ADDR=127.0.0.1:6060 diff --git a/envs/arkd.light.env b/envs/arkd.light.env index c26c5b6b6..65b3a434c 100644 --- a/envs/arkd.light.env +++ b/envs/arkd.light.env @@ -1,7 +1,8 @@ ARKD_LOG_LEVEL=5 ARKD_NO_MACAROONS=true -ARKD_UNILATERAL_EXIT_DELAY=512 -ARKD_BOARDING_EXIT_DELAY=1024 +ARKD_UNILATERAL_EXIT_DELAY=10 +ARKD_PUBLIC_UNILATERAL_EXIT_DELAY=10 +ARKD_BOARDING_EXIT_DELAY=30 ARKD_DATADIR=./data/regtest ARKD_ESPLORA_URL=http://localhost:3000 ARKD_WALLET_ADDR=127.0.0.1:6060 diff --git a/internal/config/config.go b/internal/config/config.go index 41fe14db2..c8c1dadfc 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -467,39 +467,46 @@ func (c *Config) Validate() error { if c.BanThreshold < 1 { log.Debugf("autoban is disabled") } - if c.VtxoTreeExpiry.Type == arklib.LocktimeTypeSecond { - // vtxo tree expiry must be a multiple of 512 if expressed in seconds - if c.VtxoTreeExpiry.Value%minAllowedSequence != 0 { - c.VtxoTreeExpiry.Value -= c.VtxoTreeExpiry.Value % minAllowedSequence - log.Infof( - "vtxo tree expiry must be a multiple of %d, rounded to %d", - minAllowedSequence, c.VtxoTreeExpiry, - ) - } - } - // Make sure the public unilateral exit delay type matches the internal one - if c.PublicUnilateralExitDelay.Type != c.UnilateralExitDelay.Type { + // Ensure vtxo tree expiry and checkpoint exit delay are of the same type + if c.CheckpointExitDelay.Type != c.VtxoTreeExpiry.Type { return fmt.Errorf( - "public unilateral exit delay and unilateral exit delay must have the same type", + "all delays must be above or below value 512 " + + "(checkpoint exit delay and vtxo tree expiry type mismatch)", ) } - if c.UnilateralExitDelay.Type == arklib.LocktimeTypeBlock { + if c.UnilateralExitDelay.Type != c.VtxoTreeExpiry.Type { + return fmt.Errorf( + "all delays must be above or below value 512 " + + "(unilateral exit delay and vtxo tree expiry type mismatch)", + ) + } + if c.BoardingExitDelay.Type != c.VtxoTreeExpiry.Type { return fmt.Errorf( - "invalid unilateral exit delay, must at least %d", minAllowedSequence, + "all delays must be above or below value 512 " + + "(boarding exit delay and vtxo tree expiry type mismatch)", ) } - if c.BoardingExitDelay.Type == arklib.LocktimeTypeBlock { + // Make sure the public unilateral exit delay type matches the internal one + if c.PublicUnilateralExitDelay.Type != c.UnilateralExitDelay.Type { return fmt.Errorf( - "invalid boarding exit delay, must at least %d", minAllowedSequence, + "public unilateral exit delay and unilateral exit delay must have the same type", ) } - // Ensure vtxo tree expiry and checkpoint exit delay are of the same type - if c.CheckpointExitDelay.Type != c.VtxoTreeExpiry.Type { - return fmt.Errorf("checkpoint and vtxo tree locktimes must be of the same type") + // Round seconds-based delays to multiples of minAllowedSequence (BIP68 requirement). + // Block-based delays don't need rounding. + if c.VtxoTreeExpiry.Type == arklib.LocktimeTypeSecond { + // vtxo tree expiry must be a multiple of 512 if expressed in seconds + if c.VtxoTreeExpiry.Value%minAllowedSequence != 0 { + c.VtxoTreeExpiry.Value -= c.VtxoTreeExpiry.Value % minAllowedSequence + log.Infof( + "vtxo tree expiry must be a multiple of %d, rounded to %d", + minAllowedSequence, c.VtxoTreeExpiry, + ) + } } if c.CheckpointExitDelay.Type == arklib.LocktimeTypeSecond { @@ -512,28 +519,34 @@ func (c *Config) Validate() error { } } - if c.UnilateralExitDelay.Value%minAllowedSequence != 0 { - c.UnilateralExitDelay.Value -= c.UnilateralExitDelay.Value % minAllowedSequence - log.Infof( - "unilateral exit delay must be a multiple of %d, rounded to %d", - minAllowedSequence, c.UnilateralExitDelay, - ) + if c.UnilateralExitDelay.Type == arklib.LocktimeTypeSecond { + if c.UnilateralExitDelay.Value%minAllowedSequence != 0 { + c.UnilateralExitDelay.Value -= c.UnilateralExitDelay.Value % minAllowedSequence + log.Infof( + "unilateral exit delay must be a multiple of %d, rounded to %d", + minAllowedSequence, c.UnilateralExitDelay, + ) + } } - if c.PublicUnilateralExitDelay.Value%minAllowedSequence != 0 { - c.PublicUnilateralExitDelay.Value -= c.PublicUnilateralExitDelay.Value % minAllowedSequence - log.Infof( - "public unilateral exit delay must be a multiple of %d, rounded to %d", - minAllowedSequence, c.PublicUnilateralExitDelay.Value, - ) + if c.PublicUnilateralExitDelay.Type == arklib.LocktimeTypeSecond { + if c.PublicUnilateralExitDelay.Value%minAllowedSequence != 0 { + c.PublicUnilateralExitDelay.Value -= c.PublicUnilateralExitDelay.Value % minAllowedSequence + log.Infof( + "public unilateral exit delay must be a multiple of %d, rounded to %d", + minAllowedSequence, c.PublicUnilateralExitDelay.Value, + ) + } } - if c.BoardingExitDelay.Value%minAllowedSequence != 0 { - c.BoardingExitDelay.Value -= c.BoardingExitDelay.Value % minAllowedSequence - log.Infof( - "boarding exit delay must be a multiple of %d, rounded to %d", - minAllowedSequence, c.BoardingExitDelay, - ) + if c.BoardingExitDelay.Type == arklib.LocktimeTypeSecond { + if c.BoardingExitDelay.Value%minAllowedSequence != 0 { + c.BoardingExitDelay.Value -= c.BoardingExitDelay.Value % minAllowedSequence + log.Infof( + "boarding exit delay must be a multiple of %d, rounded to %d", + minAllowedSequence, c.BoardingExitDelay, + ) + } } if c.UnilateralExitDelay == c.BoardingExitDelay { @@ -609,13 +622,22 @@ func (c *Config) Validate() error { // Enforce that if the network is not regtest, the locktimes must be expressed in seconds. // These checks must be done after the wallet service is initialized, as it is needed to // determine the network. - if c.VtxoTreeExpiry.Type == arklib.LocktimeTypeBlock && - c.network.Name != arklib.BitcoinRegTest.Name { - return fmt.Errorf("vtxo tree expiry expressed in blocks is allowed only on regtest") - } - if c.CheckpointExitDelay.Type == arklib.LocktimeTypeBlock && - c.network.Name != arklib.BitcoinRegTest.Name { - return fmt.Errorf("checkpoint exit delay expressed in blocks is allowed only on regtest") + if c.network.Name != arklib.BitcoinRegTest.Name { + if c.VtxoTreeExpiry.Type == arklib.LocktimeTypeBlock { + return fmt.Errorf("vtxo tree expiry expressed in blocks is allowed only on regtest") + } + if c.CheckpointExitDelay.Type == arklib.LocktimeTypeBlock { + return fmt.Errorf("checkpoint exit delay expressed in blocks is allowed only on regtest") + } + if c.UnilateralExitDelay.Type == arklib.LocktimeTypeBlock { + return fmt.Errorf("unilateral exit delay expressed in blocks is allowed only on regtest") + } + if c.PublicUnilateralExitDelay.Type == arklib.LocktimeTypeBlock { + return fmt.Errorf("public unilateral exit delay expressed in blocks is allowed only on regtest") + } + if c.BoardingExitDelay.Type == arklib.LocktimeTypeBlock { + return fmt.Errorf("boarding exit delay expressed in blocks is allowed only on regtest") + } } return nil diff --git a/internal/core/application/service.go b/internal/core/application/service.go index a2a4845a7..87929fc62 100644 --- a/internal/core/application/service.go +++ b/internal/core/application/service.go @@ -370,10 +370,12 @@ func (s *service) registerEventHandlers() { } // Make sure to mark new vtxos as swept if any of the spent inputs is swept as well or - // expired + // expired. ExpiresAt is always a Unix timestamp (set by Round.ExpiryTimestamp), + // so we compare it with time.Now() directly. sweptIns := false + now := time.Now() for _, vtxo := range spentVtxos { - if vtxo.Swept || !s.sweeper.scheduler.AfterNow(vtxo.ExpiresAt) { + if vtxo.Swept || now.After(time.Unix(vtxo.ExpiresAt, 0)) { sweptIns = true break } @@ -602,6 +604,7 @@ func (s *service) SubmitOffchainTx( // index by ark input index for asset packet validation assetInputs := make(map[int][]domain.AssetDenomination) + now := time.Now() // Loop over the inputs of the given ark tx to ensure the order of inputs is preserved when // rebuilding the txs. @@ -707,7 +710,7 @@ func (s *service) SubmitOffchainTx( "%s already unrolled", vtxo.Outpoint, ).WithMetadata(errors.VtxoMetadata{VtxoOutpoint: vtxoOutpoint}) } - if vtxo.Swept || !s.sweeper.scheduler.AfterNow(vtxo.ExpiresAt) { + if vtxo.Swept || now.After(time.Unix(vtxo.ExpiresAt, 0)) { // if we reach this point, it means vtxo.Spent = false so the vtxo is recoverable return nil, errors.VTXO_RECOVERABLE.New("%s is recoverable", vtxo.Outpoint). WithMetadata(errors.VtxoMetadata{VtxoOutpoint: vtxoOutpoint}) diff --git a/internal/test/e2e/e2e_test.go b/internal/test/e2e/e2e_test.go index 0818069ca..d22041b98 100644 --- a/internal/test/e2e/e2e_test.go +++ b/internal/test/e2e/e2e_test.go @@ -272,7 +272,7 @@ func TestUnilateralExit(t *testing.T) { err = generateBlocks(1) require.NoError(t, err) - time.Sleep(10 * time.Second) + time.Sleep(5 * time.Second) balance, err = alice.Balance(t.Context()) require.NoError(t, err) @@ -349,7 +349,7 @@ func TestUnilateralExit(t *testing.T) { err = generateBlocks(1) require.NoError(t, err) - time.Sleep(8 * time.Second) + time.Sleep(5 * time.Second) // Bob now just needs to wait for the unilateral exit delay to spend the unrolled VTXOs bobBalance, err = bob.Balance(t.Context()) @@ -1140,7 +1140,7 @@ func TestOffchainTx(t *testing.T) { err = generateBlocks(21) require.NoError(t, err) - // Givetime to the server to sweep the vtxo + // Give time to the server to sweep the vtxo time.Sleep(15 * time.Second) // Ensure the vtxo is pending and swept @@ -3366,7 +3366,7 @@ func TestSweep(t *testing.T) { require.NoError(t, err) // Wait for server to process the sweep - time.Sleep(10 * time.Second) + time.Sleep(30 * time.Second) // alice vtxos should not be swept yet aliceVtxos, _, err := alice.ListVtxos(ctx) @@ -3404,7 +3404,7 @@ func TestSweep(t *testing.T) { require.NoError(t, err) // give time for the server to process the sweep and indexer to sync the vtxo table - time.Sleep(10 * time.Second) + time.Sleep(60 * time.Second) // verify that all vtxos have been swept aliceVtxos, _, err = alice.ListVtxos(ctx) @@ -5124,7 +5124,7 @@ func TestAsset(t *testing.T) { // reports no errors, proving the fanout survived the churn. func TestTxListenerChurn(t *testing.T) { const ( - testDuration = 30 * time.Second + testDuration = 15 * time.Second churnWorkers = 8 txProducerDelay = 200 * time.Millisecond minimumTxEvents = 1 @@ -5402,11 +5402,11 @@ func TestTxListenerChurn(t *testing.T) { // events, and no sentinel errors are recorded. func TestEventListenerChurn(t *testing.T) { const ( - testDuration = 40 * time.Second + testDuration = 19 * time.Second churnWorkers = 16 participantsCount = 4 producerLoopDelay = 250 * time.Millisecond - roundTimeout = 20 * time.Second + roundTimeout = 11 * time.Second minimumRounds = 1 ) From b90d34c78e498e8449785991b3714eb7ca4d2329 Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Thu, 9 Apr 2026 19:09:25 +0200 Subject: [PATCH 09/16] Fix config and update deps --- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ internal/config/config.go | 12 +++++++++--- pkg/ark-cli/go.mod | 5 ++++- pkg/ark-cli/go.sum | 24 ++++++++++++------------ pkg/arkd-wallet/go.mod | 12 ++++++------ pkg/arkd-wallet/go.sum | 24 ++++++++++++------------ pkg/client-lib/go.mod | 6 +++--- pkg/client-lib/go.sum | 24 ++++++++++++------------ pkg/kvdb/go.mod | 10 +++++----- pkg/kvdb/go.sum | 24 ++++++++++++------------ pkg/macaroons/go.mod | 10 +++++----- pkg/macaroons/go.sum | 24 ++++++++++++------------ 13 files changed, 110 insertions(+), 101 deletions(-) diff --git a/go.mod b/go.mod index 2d740ae98..951abaa79 100644 --- a/go.mod +++ b/go.mod @@ -50,16 +50,16 @@ require ( github.com/timshannon/badgerhold/v4 v4.0.3 github.com/urfave/cli/v2 v2.27.4 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 - go.opentelemetry.io/otel v1.40.0 + go.opentelemetry.io/otel v1.43.0 go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 go.opentelemetry.io/otel/log v0.14.0 - go.opentelemetry.io/otel/metric v1.40.0 - go.opentelemetry.io/otel/sdk v1.40.0 + go.opentelemetry.io/otel/metric v1.43.0 + go.opentelemetry.io/otel/sdk v1.43.0 go.opentelemetry.io/otel/sdk/log v0.14.0 - go.opentelemetry.io/otel/sdk/metric v1.40.0 - go.opentelemetry.io/otel/trace v1.40.0 + go.opentelemetry.io/otel/sdk/metric v1.43.0 + go.opentelemetry.io/otel/trace v1.43.0 google.golang.org/grpc v1.79.3 gopkg.in/macaroon-bakery.v2 v2.3.0 gopkg.in/macaroon.v2 v2.1.0 @@ -235,7 +235,7 @@ require ( golang.org/x/crypto v0.48.0 // indirect golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect golang.org/x/net v0.51.0 - golang.org/x/sys v0.41.0 // indirect + golang.org/x/sys v0.42.0 // indirect golang.org/x/text v0.34.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 3f695fcfb..40a3ee5d4 100644 --- a/go.sum +++ b/go.sum @@ -586,8 +586,8 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.5 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= -go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= -go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0 h1:9y5sHvAxWzft1WQ4BwqcvA+IFVUJ1Ya75mSAUnFEVwE= @@ -600,18 +600,18 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 h1:wVZXI go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0/go.mod h1:khvBS2IggMFNwZK/6lEeHg/W57h/IX6J4URh57fuI40= go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= -go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= -go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= -go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= -go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= -go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= -go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= -go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= -go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -717,8 +717,8 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= diff --git a/internal/config/config.go b/internal/config/config.go index c8c1dadfc..337fd3fdf 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -627,13 +627,19 @@ func (c *Config) Validate() error { return fmt.Errorf("vtxo tree expiry expressed in blocks is allowed only on regtest") } if c.CheckpointExitDelay.Type == arklib.LocktimeTypeBlock { - return fmt.Errorf("checkpoint exit delay expressed in blocks is allowed only on regtest") + return fmt.Errorf( + "checkpoint exit delay expressed in blocks is allowed only on regtest", + ) } if c.UnilateralExitDelay.Type == arklib.LocktimeTypeBlock { - return fmt.Errorf("unilateral exit delay expressed in blocks is allowed only on regtest") + return fmt.Errorf( + "unilateral exit delay expressed in blocks is allowed only on regtest", + ) } if c.PublicUnilateralExitDelay.Type == arklib.LocktimeTypeBlock { - return fmt.Errorf("public unilateral exit delay expressed in blocks is allowed only on regtest") + return fmt.Errorf( + "public unilateral exit delay expressed in blocks is allowed only on regtest", + ) } if c.BoardingExitDelay.Type == arklib.LocktimeTypeBlock { return fmt.Errorf("boarding exit delay expressed in blocks is allowed only on regtest") diff --git a/pkg/ark-cli/go.mod b/pkg/ark-cli/go.mod index 676327317..126e7e5ba 100644 --- a/pkg/ark-cli/go.mod +++ b/pkg/ark-cli/go.mod @@ -75,11 +75,14 @@ require ( github.com/stretchr/testify v1.11.1 // indirect github.com/vulpemventures/go-bip32 v0.0.0-20200624192635-867c159da4d7 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect golang.org/x/crypto v0.48.0 // indirect golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect golang.org/x/net v0.51.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.41.0 // indirect + golang.org/x/sys v0.42.0 // indirect golang.org/x/text v0.34.0 // indirect google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect diff --git a/pkg/ark-cli/go.sum b/pkg/ark-cli/go.sum index b9dd7b4c9..5e4866906 100644 --- a/pkg/ark-cli/go.sum +++ b/pkg/ark-cli/go.sum @@ -352,20 +352,20 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= -go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1 h1:ofMbch7i29qIUf7VtF+r0HRF6ac0SBaPSziSsKp7wkk= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs= -go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= -go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= -go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= -go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= -go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= -go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= -go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= -go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v0.9.0 h1:C0g6TWmQYvjKRnljRULLWUVJGy8Uvu0NEL/5frY2/t4= go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -404,8 +404,8 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/arkd-wallet/go.mod b/pkg/arkd-wallet/go.mod index e21cd49df..fbae9c51c 100644 --- a/pkg/arkd-wallet/go.mod +++ b/pkg/arkd-wallet/go.mod @@ -21,15 +21,15 @@ require ( github.com/spf13/viper v1.20.1 github.com/timshannon/badgerhold/v4 v4.0.3 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 - go.opentelemetry.io/otel v1.40.0 + go.opentelemetry.io/otel v1.43.0 go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 go.opentelemetry.io/otel/log v0.14.0 - go.opentelemetry.io/otel/metric v1.40.0 - go.opentelemetry.io/otel/sdk v1.40.0 + go.opentelemetry.io/otel/metric v1.43.0 + go.opentelemetry.io/otel/sdk v1.43.0 go.opentelemetry.io/otel/sdk/log v0.14.0 - go.opentelemetry.io/otel/sdk/metric v1.40.0 + go.opentelemetry.io/otel/sdk/metric v1.43.0 golang.org/x/net v0.51.0 google.golang.org/grpc v1.79.3 ) @@ -134,7 +134,7 @@ require ( go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 // indirect - go.opentelemetry.io/otel/trace v1.40.0 + go.opentelemetry.io/otel/trace v1.43.0 go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect @@ -142,7 +142,7 @@ require ( golang.org/x/crypto v0.48.0 golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.41.0 // indirect + golang.org/x/sys v0.42.0 // indirect golang.org/x/term v0.40.0 // indirect golang.org/x/text v0.34.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect diff --git a/pkg/arkd-wallet/go.sum b/pkg/arkd-wallet/go.sum index 524f1ab8f..477ed2af3 100644 --- a/pkg/arkd-wallet/go.sum +++ b/pkg/arkd-wallet/go.sum @@ -525,8 +525,8 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= -go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= -go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0 h1:9y5sHvAxWzft1WQ4BwqcvA+IFVUJ1Ya75mSAUnFEVwE= @@ -539,18 +539,18 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 h1:wVZXI go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0/go.mod h1:khvBS2IggMFNwZK/6lEeHg/W57h/IX6J4URh57fuI40= go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= -go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= -go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= -go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= -go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= -go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= -go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= -go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= -go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -675,8 +675,8 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/pkg/client-lib/go.mod b/pkg/client-lib/go.mod index 9b4613d30..a8919ae96 100644 --- a/pkg/client-lib/go.mod +++ b/pkg/client-lib/go.mod @@ -102,16 +102,16 @@ require ( go.etcd.io/etcd/client/v3 v3.5.15 // indirect go.etcd.io/etcd/server/v3 v3.5.15 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect - go.opentelemetry.io/otel v1.40.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect golang.org/x/net v0.51.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.41.0 // indirect + golang.org/x/sys v0.42.0 // indirect golang.org/x/term v0.40.0 // indirect golang.org/x/text v0.34.0 // indirect golang.org/x/time v0.6.0 // indirect diff --git a/pkg/client-lib/go.sum b/pkg/client-lib/go.sum index a23970ef9..ea600866b 100644 --- a/pkg/client-lib/go.sum +++ b/pkg/client-lib/go.sum @@ -450,20 +450,20 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= -go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs= -go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= -go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= -go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= -go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= -go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= -go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= -go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= -go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -579,8 +579,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/pkg/kvdb/go.mod b/pkg/kvdb/go.mod index 8a3157899..f5e4f9f12 100644 --- a/pkg/kvdb/go.mod +++ b/pkg/kvdb/go.mod @@ -60,12 +60,12 @@ require ( go.etcd.io/etcd/raft/v3 v3.5.15 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect - go.opentelemetry.io/otel v1.40.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 // indirect - go.opentelemetry.io/otel/metric v1.40.0 // indirect - go.opentelemetry.io/otel/sdk v1.40.0 // indirect - go.opentelemetry.io/otel/trace v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect @@ -73,7 +73,7 @@ require ( golang.org/x/mod v0.31.0 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.42.0 // indirect golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.6.0 // indirect golang.org/x/tools v0.40.0 // indirect diff --git a/pkg/kvdb/go.sum b/pkg/kvdb/go.sum index 4bc2f1f8a..9a52941a3 100644 --- a/pkg/kvdb/go.sum +++ b/pkg/kvdb/go.sum @@ -173,20 +173,20 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= -go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs= -go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= -go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= -go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= -go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= -go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= -go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= -go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= -go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -249,8 +249,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/pkg/macaroons/go.mod b/pkg/macaroons/go.mod index 33c9ac703..82b6c17f6 100644 --- a/pkg/macaroons/go.mod +++ b/pkg/macaroons/go.mod @@ -79,12 +79,12 @@ require ( go.etcd.io/etcd/server/v3 v3.5.15 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect - go.opentelemetry.io/otel v1.40.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 // indirect - go.opentelemetry.io/otel/metric v1.40.0 // indirect - go.opentelemetry.io/otel/sdk v1.40.0 // indirect - go.opentelemetry.io/otel/trace v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect @@ -93,7 +93,7 @@ require ( golang.org/x/mod v0.32.0 // indirect golang.org/x/net v0.51.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.41.0 // indirect + golang.org/x/sys v0.42.0 // indirect golang.org/x/text v0.34.0 // indirect golang.org/x/time v0.6.0 // indirect golang.org/x/tools v0.41.0 // indirect diff --git a/pkg/macaroons/go.sum b/pkg/macaroons/go.sum index 5afc9b8d4..b3cf05325 100644 --- a/pkg/macaroons/go.sum +++ b/pkg/macaroons/go.sum @@ -265,20 +265,20 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= -go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs= -go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= -go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= -go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= -go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= -go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= -go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= -go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= -go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -358,8 +358,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= From 27dddfc0c8ed1d0efbe21aff00a840ad6bb97c98 Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Thu, 9 Apr 2026 21:05:00 +0200 Subject: [PATCH 10/16] Revert --- internal/test/e2e/e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/test/e2e/e2e_test.go b/internal/test/e2e/e2e_test.go index d22041b98..fffa83b04 100644 --- a/internal/test/e2e/e2e_test.go +++ b/internal/test/e2e/e2e_test.go @@ -3134,7 +3134,7 @@ func TestSweep(t *testing.T) { require.NoError(t, err) // give time for the server to process the sweep - time.Sleep(10 * time.Second) + time.Sleep(20 * time.Second) // verify that the checkpoint output has been put onchain // and that the VTXO has been swept From 646d8ea47ddba9523bddc7ba17049a3a8b28b2d2 Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:17:24 +0200 Subject: [PATCH 11/16] Update dev configs and e2e tests --- docker-compose.regtest.yml | 6 ++-- envs/arkd.dev.env | 6 ++-- envs/arkd.light.env | 6 ++-- internal/test/e2e/e2e_test.go | 54 +++++++++++++++++------------------ 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/docker-compose.regtest.yml b/docker-compose.regtest.yml index 1f9c55e5a..faa7cbd65 100644 --- a/docker-compose.regtest.yml +++ b/docker-compose.regtest.yml @@ -87,9 +87,9 @@ services: environment: - ARKD_LOG_LEVEL=6 - ARKD_NO_MACAROONS=true - - ARKD_VTXO_TREE_EXPIRY=20 - - ARKD_UNILATERAL_EXIT_DELAY=10 - - ARKD_PUBLIC_UNILATERAL_EXIT_DELAY=10 + - ARKD_VTXO_TREE_EXPIRY=40 + - ARKD_UNILATERAL_EXIT_DELAY=20 + - ARKD_PUBLIC_UNILATERAL_EXIT_DELAY=20 - ARKD_BOARDING_EXIT_DELAY=30 - ARKD_CHECKPOINT_EXIT_DELAY=10 - ARKD_DATADIR=./data/regtest diff --git a/envs/arkd.dev.env b/envs/arkd.dev.env index 642bf4dcf..d51678a02 100644 --- a/envs/arkd.dev.env +++ b/envs/arkd.dev.env @@ -1,9 +1,9 @@ ARKD_LOG_LEVEL=5 ARKD_NO_MACAROONS=true -ARKD_VTXO_TREE_EXPIRY=20 +ARKD_VTXO_TREE_EXPIRY=40 ARKD_CHECKPOINT_EXIT_DELAY=10 -ARKD_UNILATERAL_EXIT_DELAY=10 -ARKD_PUBLIC_UNILATERAL_EXIT_DELAY=10 +ARKD_UNILATERAL_EXIT_DELAY=20 +ARKD_PUBLIC_UNILATERAL_EXIT_DELAY=20 ARKD_BOARDING_EXIT_DELAY=30 ARKD_DATADIR=./data/regtest ARKD_ESPLORA_URL=http://localhost:3000 diff --git a/envs/arkd.light.env b/envs/arkd.light.env index 65b3a434c..d5062c3f8 100644 --- a/envs/arkd.light.env +++ b/envs/arkd.light.env @@ -1,7 +1,7 @@ ARKD_LOG_LEVEL=5 ARKD_NO_MACAROONS=true -ARKD_UNILATERAL_EXIT_DELAY=10 -ARKD_PUBLIC_UNILATERAL_EXIT_DELAY=10 +ARKD_UNILATERAL_EXIT_DELAY=20 +ARKD_PUBLIC_UNILATERAL_EXIT_DELAY=20 ARKD_BOARDING_EXIT_DELAY=30 ARKD_DATADIR=./data/regtest ARKD_ESPLORA_URL=http://localhost:3000 @@ -13,5 +13,5 @@ ARKD_SESSION_DURATION=10 ARKD_VTXO_MIN_AMOUNT=1 ARKD_BAN_THRESHOLD=1 ARKD_ONCHAIN_OUTPUT_FEE=100 -ARKD_VTXO_TREE_EXPIRY=20 +ARKD_VTXO_TREE_EXPIRY=40 ARKD_CHECKPOINT_EXIT_DELAY=10 diff --git a/internal/test/e2e/e2e_test.go b/internal/test/e2e/e2e_test.go index fffa83b04..f12a27014 100644 --- a/internal/test/e2e/e2e_test.go +++ b/internal/test/e2e/e2e_test.go @@ -272,7 +272,7 @@ func TestUnilateralExit(t *testing.T) { err = generateBlocks(1) require.NoError(t, err) - time.Sleep(5 * time.Second) + time.Sleep(10 * time.Second) balance, err = alice.Balance(t.Context()) require.NoError(t, err) @@ -349,7 +349,7 @@ func TestUnilateralExit(t *testing.T) { err = generateBlocks(1) require.NoError(t, err) - time.Sleep(5 * time.Second) + time.Sleep(8 * time.Second) // Bob now just needs to wait for the unilateral exit delay to spend the unrolled VTXOs bobBalance, err = bob.Balance(t.Context()) @@ -1137,11 +1137,11 @@ func TestOffchainTx(t *testing.T) { require.NotEmpty(t, txid) // Make the vtxo expire - err = generateBlocks(21) + err = generateBlocks(41) require.NoError(t, err) // Give time to the server to sweep the vtxo - time.Sleep(15 * time.Second) + time.Sleep(30 * time.Second) // Ensure the vtxo is pending and swept scriptStr := hex.EncodeToString(pkscript) @@ -1281,11 +1281,11 @@ func TestOffchainTx(t *testing.T) { require.NoError(t, err) require.NotEmpty(t, txid) - // Make the tx expire (the tx has 20 block expiration converted to 20 seconds in timestamp) - time.Sleep(30 * time.Second) + // Make the tx expire (the tx has 40 block expiration converted to 40 seconds in timestamp) + time.Sleep(50 * time.Second) // Make the vtxo expire - err = generateBlocks(21) + err = generateBlocks(41) require.NoError(t, err) // Don't give time to the server to mark the vtxo as swept @@ -2621,7 +2621,7 @@ func TestReactToFraud(t *testing.T) { bumpAndBroadcastTx(t, parentTx, expl) } - err = generateBlocks(30) + err = generateBlocks(50) require.NoError(t, err) // Give time for the server to detect and process the fraud @@ -2910,7 +2910,7 @@ func TestReactToFraud(t *testing.T) { } // give time for the server to detect and process the fraud - err = generateBlocks(30) + err = generateBlocks(50) require.NoError(t, err) // make sure the vtxo of bob is not redeemed @@ -2962,7 +2962,7 @@ func TestSweep(t *testing.T) { wg.Done() }() - // Settle the boarding utxo to create a new batch output expiring in 20 blocks + // Settle the boarding utxo to create a new batch output expiring in 40 blocks _, err = alice.Settle(ctx) require.NoError(t, err) @@ -2996,8 +2996,8 @@ func TestSweep(t *testing.T) { } }() - // Generate 30 blocks to expire the batch output - err = generateBlocks(30) + // Generate 50 blocks to expire the batch output + err = generateBlocks(50) require.NoError(t, err) // wait for sweep event from the stream @@ -3197,7 +3197,7 @@ func TestSweep(t *testing.T) { wg.Done() }() - // Settle the boarding utxo to create a new batch output expiring in 20 blocks + // Settle the boarding utxo to create a new batch output expiring in 40 blocks _, err = alice.Settle(ctx) require.NoError(t, err) @@ -3216,8 +3216,8 @@ func TestSweep(t *testing.T) { err = restartArkd() require.NoError(t, err) - // Generate 30 blocks to expire the batch output - err = generateBlocks(30) + // Generate 50 blocks to expire the batch output + err = generateBlocks(50) require.NoError(t, err) // Wait for server to process the sweep (needs extra time after restart) @@ -3323,7 +3323,7 @@ func TestSweep(t *testing.T) { require.Empty(t, balance.OnchainBalance.LockedAmount) // confirm the commitment tx (time t) - // sweeper schedules a sweep task at t+20 blocks + // sweeper schedules a sweep task at t+40 blocks err = generateBlocks(1) require.NoError(t, err) @@ -3335,7 +3335,7 @@ func TestSweep(t *testing.T) { // t + 1 to confirm the first unroll tx // split the root batch in two, "reset" the CSV - // sweeper schedules 2 sweep tasks at t+20+1 and t+20+1 + // sweeper schedules 2 sweep tasks at t+40+1 and t+40+1 err = generateBlocks(1) require.NoError(t, err) @@ -3343,7 +3343,7 @@ func TestSweep(t *testing.T) { time.Sleep(5 * time.Second) // wait 10 blocks to unroll again - // at this point, batches expires in 11 blocks + // at this point, batches expires in 31 blocks err = generateBlocks(10) require.NoError(t, err) @@ -3354,15 +3354,15 @@ func TestSweep(t *testing.T) { time.Sleep(2 * time.Second) // split one of the batches in two, "reset" the CSV - // 1 expires in 10 blocks, the other in 20 blocks + // 1 expires in 20 blocks, the other in 40 blocks err = generateBlocks(1) require.NoError(t, err) // give time for the server to process the unroll time.Sleep(2 * time.Second) - // Generate 11 blocks to expire the first batch outputs - err = generateBlocks(11) + // Generate 21 blocks to expire the first batch outputs + err = generateBlocks(21) require.NoError(t, err) // Wait for server to process the sweep @@ -3454,7 +3454,7 @@ func TestSweep(t *testing.T) { wg.Done() }() - // Settle the boarding utxo to create a new batch output expiring in 20 blocks + // Settle the boarding utxo to create a new batch output expiring in 40 blocks res, err := alice.Settle(ctx) require.NoError(t, err) require.NotNil(t, res) @@ -3464,8 +3464,8 @@ func TestSweep(t *testing.T) { require.Len(t, incomingFunds, 1) vtxo := incomingFunds[0] - // Generate 30 blocks to expire the batch output - err = generateBlocks(30) + // Generate 50 blocks to expire the batch output + err = generateBlocks(50) require.NoError(t, err) // Wait for server to attempt the sweep (it should fail due to dust amount) @@ -5124,7 +5124,7 @@ func TestAsset(t *testing.T) { // reports no errors, proving the fanout survived the churn. func TestTxListenerChurn(t *testing.T) { const ( - testDuration = 15 * time.Second + testDuration = 30 * time.Second churnWorkers = 8 txProducerDelay = 200 * time.Millisecond minimumTxEvents = 1 @@ -5402,11 +5402,11 @@ func TestTxListenerChurn(t *testing.T) { // events, and no sentinel errors are recorded. func TestEventListenerChurn(t *testing.T) { const ( - testDuration = 19 * time.Second + testDuration = 40 * time.Second churnWorkers = 16 participantsCount = 4 producerLoopDelay = 250 * time.Millisecond - roundTimeout = 11 * time.Second + roundTimeout = 20 * time.Second minimumRounds = 1 ) From 5da30212bb91fac89177447e314a5873df684840 Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Fri, 10 Apr 2026 02:55:07 +0200 Subject: [PATCH 12/16] Fixes --- internal/test/e2e/e2e_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/test/e2e/e2e_test.go b/internal/test/e2e/e2e_test.go index f12a27014..6d0c4dbf9 100644 --- a/internal/test/e2e/e2e_test.go +++ b/internal/test/e2e/e2e_test.go @@ -1608,7 +1608,7 @@ func TestDelegateRefresh(t *testing.T) { exitLocktime := arklib.RelativeLocktime{ Type: arklib.LocktimeTypeBlock, - Value: 10, + Value: 20, } delegationVtxoScript := script.TapscriptsVtxoScript{ @@ -1811,7 +1811,7 @@ func TestDelegateRefresh(t *testing.T) { signedPartialForfeitTx, err := alice.SignTransaction(ctx, b64partialForfeitTx) require.NoError(t, err) - // 10 blocks later, Bob registers Alice's intent, signs the tree and submit, + // 11 blocks later, Bob registers Alice's intent, signs the tree and submit, // completes the forfeit tx by adding the connector, signs and finally submits it to complete // the batch session in behalf of Alice err = generateBlocks(11) @@ -3361,8 +3361,8 @@ func TestSweep(t *testing.T) { // give time for the server to process the unroll time.Sleep(2 * time.Second) - // Generate 21 blocks to expire the first batch outputs - err = generateBlocks(21) + // Generate 30 blocks to expire the first batch outputs + err = generateBlocks(30) require.NoError(t, err) // Wait for server to process the sweep From 14fb4c7c66861585f1bda803606d28fe6691fea4 Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Fri, 10 Apr 2026 11:54:43 +0200 Subject: [PATCH 13/16] Add vtxo.IsExpired() + tests --- internal/core/application/service.go | 9 +- internal/core/domain/vtxo.go | 7 +- internal/core/domain/vtxo_test.go | 220 +++++++++++++++++++++++++++ 3 files changed, 229 insertions(+), 7 deletions(-) create mode 100644 internal/core/domain/vtxo_test.go diff --git a/internal/core/application/service.go b/internal/core/application/service.go index 87929fc62..9f0e739a6 100644 --- a/internal/core/application/service.go +++ b/internal/core/application/service.go @@ -370,12 +370,10 @@ func (s *service) registerEventHandlers() { } // Make sure to mark new vtxos as swept if any of the spent inputs is swept as well or - // expired. ExpiresAt is always a Unix timestamp (set by Round.ExpiryTimestamp), - // so we compare it with time.Now() directly. + // expired. sweptIns := false - now := time.Now() for _, vtxo := range spentVtxos { - if vtxo.Swept || now.After(time.Unix(vtxo.ExpiresAt, 0)) { + if vtxo.Swept || vtxo.IsExpired() { sweptIns = true break } @@ -604,7 +602,6 @@ func (s *service) SubmitOffchainTx( // index by ark input index for asset packet validation assetInputs := make(map[int][]domain.AssetDenomination) - now := time.Now() // Loop over the inputs of the given ark tx to ensure the order of inputs is preserved when // rebuilding the txs. @@ -710,7 +707,7 @@ func (s *service) SubmitOffchainTx( "%s already unrolled", vtxo.Outpoint, ).WithMetadata(errors.VtxoMetadata{VtxoOutpoint: vtxoOutpoint}) } - if vtxo.Swept || now.After(time.Unix(vtxo.ExpiresAt, 0)) { + if vtxo.Swept || vtxo.IsExpired() { // if we reach this point, it means vtxo.Spent = false so the vtxo is recoverable return nil, errors.VTXO_RECOVERABLE.New("%s is recoverable", vtxo.Outpoint). WithMetadata(errors.VtxoMetadata{VtxoOutpoint: vtxoOutpoint}) diff --git a/internal/core/domain/vtxo.go b/internal/core/domain/vtxo.go index 3f1cb731b..65123a54f 100644 --- a/internal/core/domain/vtxo.go +++ b/internal/core/domain/vtxo.go @@ -6,6 +6,7 @@ import ( "fmt" "strconv" "strings" + "time" "github.com/arkade-os/arkd/pkg/ark-lib/asset" "github.com/arkade-os/arkd/pkg/ark-lib/script" @@ -67,7 +68,7 @@ func (v Vtxo) IsNote() bool { } func (v Vtxo) RequiresForfeit() bool { - return !v.Swept && !v.IsNote() + return !v.Swept && !v.IsExpired() && !v.IsNote() } func (v Vtxo) IsSettled() bool { @@ -89,3 +90,7 @@ func (v Vtxo) OutputScript() ([]byte, error) { } return script.P2TRScript(pubkey) } + +func (v Vtxo) IsExpired() bool { + return time.Now().After(time.Unix(v.ExpiresAt, 0)) +} diff --git a/internal/core/domain/vtxo_test.go b/internal/core/domain/vtxo_test.go new file mode 100644 index 000000000..3e58b3c67 --- /dev/null +++ b/internal/core/domain/vtxo_test.go @@ -0,0 +1,220 @@ +package domain_test + +import ( + "encoding/hex" + "testing" + "time" + + "github.com/arkade-os/arkd/internal/core/domain" + "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/stretchr/testify/require" +) + +const validVtxoPubkey = "25a43cecfa0e1b1a4f72d64ad15f4cfa7a84d0723e8511c969aa543638ea9967" + +func TestOutpoint(t *testing.T) { + t.Run("FromString", func(t *testing.T) { + t.Run("valid", func(t *testing.T) { + original := domain.Outpoint{Txid: "0123456789abcdef", VOut: 42} + var parsed domain.Outpoint + err := parsed.FromString(original.String()) + require.NoError(t, err) + require.Equal(t, original, parsed) + }) + + t.Run("invalid", func(t *testing.T) { + fixtures := []struct { + name string + s string + }{ + {"empty", ""}, + {"no separator", "abcdef"}, + {"too many separators", "abcdef:1:2"}, + {"non numeric vout", "abcdef:xyz"}, + {"negative vout", "abcdef:-1"}, + } + for _, f := range fixtures { + t.Run(f.name, func(t *testing.T) { + var op domain.Outpoint + err := op.FromString(f.s) + require.Error(t, err) + }) + } + }) + }) +} + +func TestVtxo_IsNote(t *testing.T) { + fixtures := []struct { + name string + vtxo domain.Vtxo + isNote bool + }{ + { + name: "should be true", + vtxo: domain.Vtxo{}, + isNote: true, + }, + { + name: "should be false", + vtxo: domain.Vtxo{ + CommitmentTxids: []string{"txid1"}, + RootCommitmentTxid: "rootid", + }, + isNote: false, + }, + } + for _, f := range fixtures { + t.Run(f.name, func(t *testing.T) { + require.Equal(t, f.isNote, f.vtxo.IsNote()) + }) + } +} + +func TestVtxo_IsSettled(t *testing.T) { + fixtures := []struct { + name string + vtxo domain.Vtxo + isSettled bool + }{ + { + name: "should be true", + vtxo: domain.Vtxo{SettledBy: "commitment-txid"}, + isSettled: true, + }, + { + name: "should be false", + vtxo: domain.Vtxo{}, + isSettled: false, + }, + } + for _, f := range fixtures { + t.Run(f.name, func(t *testing.T) { + require.Equal(t, f.isSettled, f.vtxo.IsSettled()) + }) + } +} + +func TestVtxo_IsExpired(t *testing.T) { + fixtures := []struct { + name string + vtxo domain.Vtxo + isExpired bool + }{ + { + name: "should be true", + vtxo: domain.Vtxo{ExpiresAt: time.Now().Add(-time.Hour).Unix()}, + isExpired: true, + }, + { + name: "should be false", + vtxo: domain.Vtxo{ExpiresAt: time.Now().Add(time.Hour).Unix()}, + isExpired: false, + }, + } + for _, f := range fixtures { + t.Run(f.name, func(t *testing.T) { + require.Equal(t, f.isExpired, f.vtxo.IsExpired()) + }) + } +} + +func TestVtxo_RequiresForfeit(t *testing.T) { + futureExpiry := time.Now().Add(time.Hour).Unix() + pastExpiry := time.Now().Add(-time.Hour).Unix() + + fixtures := []struct { + name string + vtxo domain.Vtxo + requiresForfeit bool + }{ + { + name: "should be true", + vtxo: domain.Vtxo{ + CommitmentTxids: []string{"txid1"}, + ExpiresAt: futureExpiry, + }, + requiresForfeit: true, + }, + { + name: "should be false (swept)", + vtxo: domain.Vtxo{ + CommitmentTxids: []string{"txid1"}, + ExpiresAt: futureExpiry, + Swept: true, + }, + requiresForfeit: false, + }, + { + name: "should be false (expired)", + vtxo: domain.Vtxo{ + CommitmentTxids: []string{"txid1"}, + ExpiresAt: pastExpiry, + }, + requiresForfeit: false, + }, + { + name: "should be false (note)", + vtxo: domain.Vtxo{ + ExpiresAt: futureExpiry, + }, + requiresForfeit: false, + }, + } + for _, f := range fixtures { + t.Run(f.name, func(t *testing.T) { + require.Equal(t, f.requiresForfeit, f.vtxo.RequiresForfeit()) + }) + } +} + +func TestVtxo_TapKey(t *testing.T) { + t.Run("valid", func(t *testing.T) { + v := domain.Vtxo{PubKey: validVtxoPubkey} + key, err := v.TapKey() + require.NoError(t, err) + require.NotNil(t, key) + + expected, err := hex.DecodeString(validVtxoPubkey) + require.NoError(t, err) + parsed, err := schnorr.ParsePubKey(expected) + require.NoError(t, err) + require.True(t, key.IsEqual(parsed)) + }) + + t.Run("invalid", func(t *testing.T) { + fixtures := []struct { + name string + vtxo domain.Vtxo + }{ + {"invalid hex", domain.Vtxo{PubKey: "not-hex"}}, + {"invalid pubkey length", domain.Vtxo{PubKey: "abcd"}}, + } + + for _, f := range fixtures { + t.Run(f.name, func(t *testing.T) { + _, err := f.vtxo.TapKey() + require.Error(t, err) + }) + } + }) +} + +func TestVtxo_OutputScript(t *testing.T) { + t.Run("valid", func(t *testing.T) { + v := domain.Vtxo{PubKey: validVtxoPubkey} + pkScript, err := v.OutputScript() + require.NoError(t, err) + require.NotEmpty(t, pkScript) + // P2TR script: OP_1 <32-byte x-only pubkey> = 34 bytes total + require.Len(t, pkScript, 34) + require.Equal(t, byte(0x51), pkScript[0]) // OP_1 + require.Equal(t, byte(0x20), pkScript[1]) // push 32 bytes + }) + + t.Run("invalid", func(t *testing.T) { + v := domain.Vtxo{PubKey: "not-hex"} + _, err := v.OutputScript() + require.Error(t, err) + }) +} From f7ee039abcf892cdaaeecf36aae7990d0c07156d Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Fri, 10 Apr 2026 11:58:32 +0200 Subject: [PATCH 14/16] Drop allowCSVBlockType arg from app factory func --- internal/config/config.go | 3 +-- internal/core/application/service.go | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 337fd3fdf..31d4ca81d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -869,7 +869,6 @@ func (c *Config) appService() error { if err != nil { return err } - allowCSVBlockType := c.VtxoTreeExpiry.Type == arklib.LocktimeTypeBlock svc, err := application.NewService( c.wallet, c.signer, c.repo, c.txBuilder, c.scanner, @@ -879,7 +878,7 @@ func (c *Config) appService() error { c.SessionDuration, c.RoundMinParticipantsCount, c.RoundMaxParticipantsCount, c.UtxoMaxAmount, c.UtxoMinAmount, c.VtxoMaxAmount, c.VtxoMinAmount, c.BanDuration, c.BanThreshold, c.MaxTxWeight, c.AssetTxMaxWeightRatio, - *c.network, allowCSVBlockType, c.NoteUriPrefix, + *c.network, c.NoteUriPrefix, ssStartTime, ssEndTime, ssPeriod, ssDuration, c.ScheduledSessionMinRoundParticipantsCount, c.ScheduledSessionMaxRoundParticipantsCount, c.SettlementMinExpiryGap, diff --git a/internal/core/application/service.go b/internal/core/application/service.go index 9f0e739a6..1733999a8 100644 --- a/internal/core/application/service.go +++ b/internal/core/application/service.go @@ -117,9 +117,7 @@ func NewService( sessionDuration, roundMinParticipantsCount, roundMaxParticipantsCount, utxoMaxAmount, utxoMinAmount, vtxoMaxAmount, vtxoMinAmount, banDuration, banThreshold int64, maxTxWeight uint64, assetTxMaxWeightRatio float64, - network arklib.Network, - allowCSVBlockType bool, - noteUriPrefix string, + network arklib.Network, noteUriPrefix string, scheduledSessionStartTime, scheduledSessionEndTime time.Time, scheduledSessionPeriod, scheduledSessionDuration time.Duration, scheduledSessionRoundMinParticipantsCount, scheduledSessionRoundMaxParticipantsCount int64, @@ -171,6 +169,8 @@ func NewService( roundReportSvc = roundReportUnimplemented{} } + allowCSVBlockType := vtxoTreeExpiry.Type == arklib.LocktimeTypeBlock + ctx, cancel := context.WithCancel(ctx) svc := &service{ From cdfdf8168142df12293e1f00f7a20289293e93a3 Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Fri, 10 Apr 2026 14:07:56 +0200 Subject: [PATCH 15/16] Fix unit tests --- internal/core/domain/round_test.go | 18 ++++++-- .../live-store/live_store_test.go | 2 +- .../covenantless/testdata/fixtures.json | 45 ++++++++++++------- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/internal/core/domain/round_test.go b/internal/core/domain/round_test.go index 6e44b03cd..ed4207e12 100644 --- a/internal/core/domain/round_test.go +++ b/internal/core/domain/round_test.go @@ -3,6 +3,7 @@ package domain_test import ( "fmt" "testing" + "time" "github.com/arkade-os/arkd/internal/core/domain" "github.com/arkade-os/arkd/pkg/ark-lib/tree" @@ -26,6 +27,7 @@ var ( Amount: 2000, CommitmentTxids: []string{txid}, RootCommitmentTxid: txid, + ExpiresAt: time.Now().Add(time.Hour).Unix(), }, }, Receivers: []domain.Receiver{ @@ -58,6 +60,7 @@ var ( Amount: 1000, CommitmentTxids: []string{txid}, RootCommitmentTxid: txid, + ExpiresAt: time.Now().Add(time.Hour).Unix(), }, { Outpoint: domain.Outpoint{ @@ -68,6 +71,7 @@ var ( Amount: 1000, CommitmentTxids: []string{txid}, RootCommitmentTxid: txid, + ExpiresAt: time.Now().Add(time.Hour).Unix(), }, }, Receivers: []domain.Receiver{{ @@ -493,11 +497,13 @@ func testEndFinalization(t *testing.T) { intentsById[p.Id] = p } fixtures := []struct { + name string round *domain.Round forfeitTxs []domain.ForfeitTx expectedErr string }{ { + name: "missing forfeit txs", round: &domain.Round{ Id: "0", Stage: domain.Stage{ @@ -509,6 +515,7 @@ func testEndFinalization(t *testing.T) { expectedErr: "missing list of signed forfeit txs", }, { + name: "invalid stage (undefined)", round: &domain.Round{ Id: "0", }, @@ -516,6 +523,7 @@ func testEndFinalization(t *testing.T) { expectedErr: "not in a valid stage to end finalization", }, { + name: "invalid stage (registration)", round: &domain.Round{ Id: "0", Stage: domain.Stage{ @@ -526,6 +534,7 @@ func testEndFinalization(t *testing.T) { expectedErr: "not in a valid stage to end finalization", }, { + name: "invalid stage (failed)", round: &domain.Round{ Id: "0", Stage: domain.Stage{ @@ -542,6 +551,7 @@ func testEndFinalization(t *testing.T) { expectedErr: "not in a valid stage to end finalization", }, { + name: "already finalized", round: &domain.Round{ Id: "0", Stage: domain.Stage{ @@ -560,9 +570,11 @@ func testEndFinalization(t *testing.T) { } for _, f := range fixtures { - events, err := f.round.EndFinalization(f.forfeitTxs, finalCommitmentTx) - require.EqualError(t, err, f.expectedErr) - require.Empty(t, events) + t.Run(f.name, func(t *testing.T) { + events, err := f.round.EndFinalization(f.forfeitTxs, finalCommitmentTx) + require.EqualError(t, err, f.expectedErr) + require.Empty(t, events) + }) } }) }) diff --git a/internal/infrastructure/live-store/live_store_test.go b/internal/infrastructure/live-store/live_store_test.go index 385f542d2..f1a45acb6 100644 --- a/internal/infrastructure/live-store/live_store_test.go +++ b/internal/infrastructure/live-store/live_store_test.go @@ -30,7 +30,7 @@ import ( var ( connectorsJSON = `[{"Tx":"cHNidP8BAOwDAAAAAcXuArkhSrxO59ox0sKDFr0zZzeJuIImgzIGH5oiKx63AQAAAAD/////BU0BAAAAAAAAIlEgi4HF8ZcskHEBwLNQ0RGozbmmCAa/9vDJHzC4sxeZDhFNAQAAAAAAACJRIIuBxfGXLJBxAcCzUNERqM25pggGv/bwyR8wuLMXmQ4RTQEAAAAAAAAiUSCLgcXxlyyQcQHAs1DREajNuaYIBr/28MkfMLizF5kOEU0BAAAAAAAAIlEgi4HF8ZcskHEBwLNQ0RGozbmmCAa/9vDJHzC4sxeZDhEAAAAAAAAAAARRAk5zAAAAAAAMY29zaWduZXIAAAAAIQKLgcXxlyyQcQHAs1DREajNuaYIBr/28MkfMLizF5kOEQAAAAAAAA==","Children":{"0":"5e1eae3436fa3175eb238b3cc22cfccd17ec32c8f6cfd911e03f58f83b05fd7b","1":"8c8c00c0b0966880a8e9dacd8e266f3ddf938e817c7bd40295bddc5e45d900ea","2":"584408db5ed86cd5c51e2f6f027fa40a6584c3c91b8103d45ae36bc55d8a7329","3":"cbeecbaa2cd83534762c7720b29ad8e4fd9bca7e6d1a26a41a2fe0f48ef7bd6f"}},{"Tx":"cHNidP8BAGsDAAAAASE8O6xJeYeQ6L6Z4CHN1ndN3as+fOX/CPvGJ4tcn/e0AAAAAAD/////Ak0BAAAAAAAAIlEgi4HF8ZcskHEBwLNQ0RGozbmmCAa/9vDJHzC4sxeZDhEAAAAAAAAAAARRAk5zAAAAAAAMY29zaWduZXIAAAAAIQKLgcXxlyyQcQHAs1DREajNuaYIBr/28MkfMLizF5kOEQAAAA==","Children":{}},{"Tx":"cHNidP8BAGsDAAAAASE8O6xJeYeQ6L6Z4CHN1ndN3as+fOX/CPvGJ4tcn/e0AQAAAAD/////Ak0BAAAAAAAAIlEgi4HF8ZcskHEBwLNQ0RGozbmmCAa/9vDJHzC4sxeZDhEAAAAAAAAAAARRAk5zAAAAAAAMY29zaWduZXIAAAAAIQKLgcXxlyyQcQHAs1DREajNuaYIBr/28MkfMLizF5kOEQAAAA==","Children":{}},{"Tx":"cHNidP8BAGsDAAAAASE8O6xJeYeQ6L6Z4CHN1ndN3as+fOX/CPvGJ4tcn/e0AgAAAAD/////Ak0BAAAAAAAAIlEgi4HF8ZcskHEBwLNQ0RGozbmmCAa/9vDJHzC4sxeZDhEAAAAAAAAAAARRAk5zAAAAAAAMY29zaWduZXIAAAAAIQKLgcXxlyyQcQHAs1DREajNuaYIBr/28MkfMLizF5kOEQAAAA==","Children":{}},{"Tx":"cHNidP8BAGsDAAAAASE8O6xJeYeQ6L6Z4CHN1ndN3as+fOX/CPvGJ4tcn/e0AwAAAAD/////Ak0BAAAAAAAAIlEgi4HF8ZcskHEBwLNQ0RGozbmmCAa/9vDJHzC4sxeZDhEAAAAAAAAAAARRAk5zAAAAAAAMY29zaWduZXIAAAAAIQKLgcXxlyyQcQHAs1DREajNuaYIBr/28MkfMLizF5kOEQAAAA==","Children":{}}]` - intentsJSON = `[{"Id":"d4d1735d-05d1-493c-ac3a-b0bb634a50fe","Inputs":[{"Txid":"79e74bf97b34450d69780778522087504e5340dd71c7454b017c01e3d3bfb8ab","VOut":0,"Amount":5000,"PubKey":"7086d72a8ddacc9e6e0451d92133ef583d6748a4726b632a94f26df8c802ac24","RootCommitmentTxid":"2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96","CommitmentTxids":["2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96"],"SpentBy":"","Spent":false,"Unrolled":false,"Swept":false,"ExpireAt":199,"Preconfirmed": true,"CreatedAt":1749818677},{"Txid":"c4ae17ae1d95ec2a6adf07166e8daddee3b0f345fb1981f4af5a866517e2d198","VOut":1,"Amount":99997000,"PubKey":"7086d72a8ddacc9e6e0451d92133ef583d6748a4726b632a94f26df8c802ac24","RootCommitmentTxid":"2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96","CommitmentTxids":["2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96"],"SpentBy":"","Spent":false,"Unrolled":false,"Swept":false,"ExpireAt":199,"Preconfirmed":true,"CreatedAt":1749818677}],"Receivers":[{"Amount":100002000,"OnchainAddress":"","PubKey":"7086d72a8ddacc9e6e0451d92133ef583d6748a4726b632a94f26df8c802ac24"}]},{"Id":"6eef6c69-179c-4fe8-b183-e79637838255","Inputs":[{"Txid":"79e74bf97b34450d69780778522087504e5340dd71c7454b017c01e3d3bfb8ab","VOut":1,"Amount":99995000,"PubKey":"7594c9acd996ccf667431769bb4b238b29a9ed32b73f39185c121cf770aa0a63","RootCommitmentTxid":"2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96","CommitmentTxids":["2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96"],"SpentBy":"","Spent":false,"Unrolled":false,"Swept":false,"ExpireAt":199,"Preconfirmed":true,"CreatedAt":1749818677},{"Txid":"c4ae17ae1d95ec2a6adf07166e8daddee3b0f345fb1981f4af5a866517e2d198","VOut":0,"Amount":3000,"PubKey":"7594c9acd996ccf667431769bb4b238b29a9ed32b73f39185c121cf770aa0a63","RootCommitmentTxid":"2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96","CommitmentTxids":["2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96"],"SpentBy":"","Spent":false,"Unrolled":false,"Swept":false,"ExpireAt":199,"Preconfirmed":true,"CreatedAt":1749818677}],"Receivers":[{"Amount":99998000,"OnchainAddress":"","PubKey":"7594c9acd996ccf667431769bb4b238b29a9ed32b73f39185c121cf770aa0a63"}]}]` + intentsJSON = `[{"Id":"d4d1735d-05d1-493c-ac3a-b0bb634a50fe","Inputs":[{"Txid":"79e74bf97b34450d69780778522087504e5340dd71c7454b017c01e3d3bfb8ab","VOut":0,"Amount":5000,"PubKey":"7086d72a8ddacc9e6e0451d92133ef583d6748a4726b632a94f26df8c802ac24","RootCommitmentTxid":"2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96","CommitmentTxids":["2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96"],"SpentBy":"","Spent":false,"Unrolled":false,"Swept":false,"ExpiresAt":253402300799,"Preconfirmed": true,"CreatedAt":1749818677},{"Txid":"c4ae17ae1d95ec2a6adf07166e8daddee3b0f345fb1981f4af5a866517e2d198","VOut":1,"Amount":99997000,"PubKey":"7086d72a8ddacc9e6e0451d92133ef583d6748a4726b632a94f26df8c802ac24","RootCommitmentTxid":"2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96","CommitmentTxids":["2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96"],"SpentBy":"","Spent":false,"Unrolled":false,"Swept":false,"ExpiresAt":253402300799,"Preconfirmed":true,"CreatedAt":1749818677}],"Receivers":[{"Amount":100002000,"OnchainAddress":"","PubKey":"7086d72a8ddacc9e6e0451d92133ef583d6748a4726b632a94f26df8c802ac24"}]},{"Id":"6eef6c69-179c-4fe8-b183-e79637838255","Inputs":[{"Txid":"79e74bf97b34450d69780778522087504e5340dd71c7454b017c01e3d3bfb8ab","VOut":1,"Amount":99995000,"PubKey":"7594c9acd996ccf667431769bb4b238b29a9ed32b73f39185c121cf770aa0a63","RootCommitmentTxid":"2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96","CommitmentTxids":["2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96"],"SpentBy":"","Spent":false,"Unrolled":false,"Swept":false,"ExpiresAt":253402300799,"Preconfirmed":true,"CreatedAt":1749818677},{"Txid":"c4ae17ae1d95ec2a6adf07166e8daddee3b0f345fb1981f4af5a866517e2d198","VOut":0,"Amount":3000,"PubKey":"7594c9acd996ccf667431769bb4b238b29a9ed32b73f39185c121cf770aa0a63","RootCommitmentTxid":"2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96","CommitmentTxids":["2c6bffc1ce2da7e40f37043b7940b548b9b93f474e17c7fd84c8090c054afc96"],"SpentBy":"","Spent":false,"Unrolled":false,"Swept":false,"ExpiresAt":253402300799,"Preconfirmed":true,"CreatedAt":1749818677}],"Receivers":[{"Amount":99998000,"OnchainAddress":"","PubKey":"7594c9acd996ccf667431769bb4b238b29a9ed32b73f39185c121cf770aa0a63"}]}]` tx1 = "cHNidP8BAIgDAAAAAnv9BTv4WD/gEdnP9sgy7BfN/CzCPIsj63Ux+jY0rh5eAAAAAAD/////q7i/0+MBfAFLRcdx3UBTTlCHIFJ4B3hpDUU0e/lL53kAAAAAAP////8C1RQAAAAAAAAWABQrwBxZxFNQ+DSDSqacn20LIQKLrQAAAAAAAAAABFECTnMAAAAAAAEBK00BAAAAAAAAIlEgi4HF8ZcskHEBwLNQ0RGozbmmCAa/9vDJHzC4sxeZDhEAAQEriBMAAAAAAAAiUSBwhtcqjdrMnm4EUdkhM+9YPWdIpHJrYyqU8m34yAKsJEEULyriza1giT7HPFxEqbI6St3+hZuq8XVP4ZPaJ/Mep1SL45HbEaCf+ZMY3cfCc6bLe13jWNIJgi8nTS2+Lw+zIUAMWsyNnOkGuXqv1tZryHrR2opcv1IE8y8vd0plIWjcBzC75lIIeMaV3QLOicJkpx854Hpb4hdGylSRnw9wTDBjQhXBUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsDAx+14WC2NF93SA39AJr+zuMBDbBkzxBXNHpuv/6Dnb0UgLyriza1giT7HPFxEqbI6St3+hZuq8XVP4ZPaJ/Mep1StIDaW50nxJTR9gvLAoXOmCm76EX2uxlTKpPeMF5TI/Q8jrMAAAAA=" tx2 = "cHNidP8BAIgDAAAAAm+994704C8apCYabX7Km/3k2JqyIHcsdjQ12Cyqy+7LAAAAAAD/////mNHiF2WGWq/0gRn7RfOw496tjW4WB99qKuyVHa4XrsQBAAAAAP////8Cldb1BQAAAAAWABQrwBxZxFNQ+DSDSqacn20LIQKLrQAAAAAAAAAABFECTnMAAAAAAAEBK00BAAAAAAAAIlEgi4HF8ZcskHEBwLNQ0RGozbmmCAa/9vDJHzC4sxeZDhEAAQErSNX1BQAAAAAiUSBwhtcqjdrMnm4EUdkhM+9YPWdIpHJrYyqU8m34yAKsJEEULyriza1giT7HPFxEqbI6St3+hZuq8XVP4ZPaJ/Mep1SL45HbEaCf+ZMY3cfCc6bLe13jWNIJgi8nTS2+Lw+zIUASzdEkMZS1M3JBzp2N/ky+nki8GRJ5WpQY/7UZLI8AuFe0+26NmFuwbCdABpfu0vbRcwgKOS+9B3Fot0jlBLP5QhXBUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsDAx+14WC2NF93SA39AJr+zuMBDbBkzxBXNHpuv/6Dnb0UgLyriza1giT7HPFxEqbI6St3+hZuq8XVP4ZPaJ/Mep1StIDaW50nxJTR9gvLAoXOmCm76EX2uxlTKpPeMF5TI/Q8jrMAAAAA=" tx3 = "cHNidP8BAIgDAAAAAuoA2UVe3L2VAtR7fIGOk989byaOzdrpqIBolrDAAIyMAAAAAAD/////q7i/0+MBfAFLRcdx3UBTTlCHIFJ4B3hpDUU0e/lL53kBAAAAAP////8Cxc71BQAAAAAWABQrwBxZxFNQ+DSDSqacn20LIQKLrQAAAAAAAAAABFECTnMAAAAAAAEBK00BAAAAAAAAIlEgi4HF8ZcskHEBwLNQ0RGozbmmCAa/9vDJHzC4sxeZDhEAAQEreM31BQAAAAAiUSB1lMms2ZbM9mdDF2m7SyOLKantMrc/ORhcEhz3cKoKY0EU+oyaCbRsXuhY4jloSwu3Ipx9OPH8BbPj7wTd/21OWk4MjR6TYePp/0T4p433ieP80aFTXXPgoCOHPjELdrL+AUDpuqwgR4YEuiemShPyiNdDm0AX1aj0sm1E5JUWApXGIahSpPpWhImz2GlO+PMJHdVNXEKXoDePj91v6H6PK1a0QRQ2ludJ8SU0fYLywKFzpgpu+hF9rsZUyqT3jBeUyP0PIwyNHpNh4+n/RPinjfeJ4/zRoVNdc+CgI4c+MQt2sv4BQInUzArzkE6X+bP/eCF7F1PzaedGuM4wtX5roc9fOZ1Ja0XTErh5GUWMdZUGaqIDBlbggnPZjidgCFpV1DlEry5CFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wOlm8s7rZPsauycdJTy6UH8o1nvcz68gOYxt8V80njVkRSAvKuLNrWCJPsc8XESpsjpK3f6Fm6rxdU/hk9on8x6nVK0gNpbnSfElNH2C8sChc6YKbvoRfa7GVMqk94wXlMj9DyOswAd0YXB0cmVlcwIBwCgDAgBAsnUgNpbnSfElNH2C8sChc6YKbvoRfa7GVMqk94wXlMj9DyOsAcBEIC8q4s2tYIk+xzxcRKmyOkrd/oWbqvF1T+GT2ifzHqdUrSA2ludJ8SU0fYLywKFzpgpu+hF9rsZUyqT3jBeUyP0PI6wAAAA=" diff --git a/internal/infrastructure/tx-builder/covenantless/testdata/fixtures.json b/internal/infrastructure/tx-builder/covenantless/testdata/fixtures.json index 8882aa234..79110c62f 100644 --- a/internal/infrastructure/tx-builder/covenantless/testdata/fixtures.json +++ b/internal/infrastructure/tx-builder/covenantless/testdata/fixtures.json @@ -12,7 +12,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 1100, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 } ], "receivers": [ @@ -37,7 +38,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 1100, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 } ], "receivers": [ @@ -66,7 +68,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 1100, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 } ], "receivers": [ @@ -89,7 +92,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 1100, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 } ], "receivers": [ @@ -112,7 +116,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 1100, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 } ], "receivers": [ @@ -141,7 +146,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 1000, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 }, { "txid": "66a0df86fcdeb84b8877adfe0b2c556dba30305d72ddbd4c49355f6930355357", @@ -149,7 +155,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 1000, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 }, { "txid": "9913159bc7aa493ca53cbb9cbc88f97ba01137c814009dc7ef520c3fafc67909", @@ -157,7 +164,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 500, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 }, { "txid": "5e10e77a7cdedc153be5193a4b6055a7802706ded4f2a9efefe86ed2f9a6ae60", @@ -165,7 +173,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 1000, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 }, { "txid": "5e10e77a7cdedc153be5193a4b6055a7802706ded4f2a9efefe86ed2f9a6ae60", @@ -173,7 +182,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 1000, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 } ], "receivers": [ @@ -219,7 +229,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 1000, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 }, { "txid": "66a0df86fcdeb84b8877adfe0b2c556dba30305d72ddbd4c49355f6930355357", @@ -227,7 +238,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 1000, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 }, { "txid": "9913159bc7aa493ca53cbb9cbc88f97ba01137c814009dc7ef520c3fafc67909", @@ -235,7 +247,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 500, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 }, { "txid": "5e10e77a7cdedc153be5193a4b6055a7802706ded4f2a9efefe86ed2f9a6ae60", @@ -243,7 +256,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 1000, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 }, { "txid": "5e10e77a7cdedc153be5193a4b6055a7802706ded4f2a9efefe86ed2f9a6ae60", @@ -251,7 +265,8 @@ "pubkey": "0000000000000000000000000000000000000000000000000000000000000001", "amount": 1000, "rootCommitmentTxid": "0000000000000000000000000000000000000000000000000000000000000002", - "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"] + "commitmentTxids": ["0000000000000000000000000000000000000000000000000000000000000002"], + "expiresAt": 253402300799 } ], "receivers": [ From f178c0d45ad0f2f26b7117b0125606e48afee99d Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Fri, 10 Apr 2026 16:15:17 +0200 Subject: [PATCH 16/16] Fix fixture --- internal/core/domain/vtxo_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/core/domain/vtxo_test.go b/internal/core/domain/vtxo_test.go index 3e58b3c67..d3d983b46 100644 --- a/internal/core/domain/vtxo_test.go +++ b/internal/core/domain/vtxo_test.go @@ -15,7 +15,10 @@ const validVtxoPubkey = "25a43cecfa0e1b1a4f72d64ad15f4cfa7a84d0723e8511c969aa543 func TestOutpoint(t *testing.T) { t.Run("FromString", func(t *testing.T) { t.Run("valid", func(t *testing.T) { - original := domain.Outpoint{Txid: "0123456789abcdef", VOut: 42} + original := domain.Outpoint{ + Txid: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + VOut: 42, + } var parsed domain.Outpoint err := parsed.FromString(original.String()) require.NoError(t, err)