From 1efe5d9c7e8459287e34c9508251fa5c603fb096 Mon Sep 17 00:00:00 2001 From: Johnosezele Date: Wed, 23 Sep 2026 11:59:30 +0100 Subject: [PATCH 1/3] chore(ci): bump the Dart SDK pin to 3.13.4 Pin every setup-dart step in CI and upstream-compat to 3.13.4, and note that pin in CONTRIBUTING.md. Package SDK constraints stay at ^3.10.0 and ^3.10.1. Exclude bdk_demo build, android, and ios from the analyzer so flutter pub get and flutter analyze match current Flutter stable. --- .github/workflows/ci.yml | 10 +++++----- .github/workflows/upstream-compat.yml | 2 +- CONTRIBUTING.md | 4 ++-- bdk_demo/analysis_options.yaml | 5 +++++ 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d1ee587..0230e7c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: - name: Setup Dart uses: dart-lang/setup-dart@v1 with: - sdk: "3.10.0" + sdk: "3.13.4" - name: Install lipo (macOS) if: matrix.os == 'macos-latest' @@ -84,7 +84,7 @@ jobs: - name: Setup Dart uses: dart-lang/setup-dart@v1 with: - sdk: "3.10.0" + sdk: "3.13.4" - name: Pub get run: dart pub get @@ -119,7 +119,7 @@ jobs: - name: Setup Dart uses: dart-lang/setup-dart@v1 with: - sdk: "3.10.0" + sdk: "3.13.4" - name: Pub get (bdk_demo) working-directory: bdk_demo @@ -159,7 +159,7 @@ jobs: - name: Setup Dart uses: dart-lang/setup-dart@v1 with: - sdk: "3.10.0" + sdk: "3.13.4" - name: Pub get run: dart pub get @@ -228,7 +228,7 @@ jobs: - name: Setup Dart uses: dart-lang/setup-dart@v1 with: - sdk: "3.10.0" + sdk: "3.13.4" - name: Pub get (bdk_demo) working-directory: bdk_demo diff --git a/.github/workflows/upstream-compat.yml b/.github/workflows/upstream-compat.yml index 922d4ec..fa7712d 100644 --- a/.github/workflows/upstream-compat.yml +++ b/.github/workflows/upstream-compat.yml @@ -19,7 +19,7 @@ jobs: - name: Setup Dart uses: dart-lang/setup-dart@v1 with: - sdk: "3.10.0" + sdk: "3.13.4" - name: Pin bdk-ffi to upstream HEAD shell: bash diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8b54567..ea212f1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,8 +4,8 @@ Keep PRs focused and include the smallest checks that cover the change. ## Setup -Install Dart 3.10 or newer and Rust stable. Install Flutter stable when working -on `bdk_demo` or mobile targets. +Install Dart 3.10 or newer (CI uses 3.13.4) and Rust stable. Install Flutter +stable when working on `bdk_demo` or mobile targets. From the repository root: diff --git a/bdk_demo/analysis_options.yaml b/bdk_demo/analysis_options.yaml index 0d29021..0d87f43 100644 --- a/bdk_demo/analysis_options.yaml +++ b/bdk_demo/analysis_options.yaml @@ -7,6 +7,11 @@ # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. +analyzer: + exclude: + - build/** + - android/** + - ios/** include: package:flutter_lints/flutter.yaml linter: From 2c64cfe9fc1c97bc5be2992bdc725a543460c815 Mon Sep 17 00:00:00 2001 From: Johnosezele Date: Wed, 23 Sep 2026 12:28:47 +0100 Subject: [PATCH 2/3] chore: align local CI helpers with Dart 3.13 formatting --- test/integration/electrum_sync_test.dart | 228 +++++++------- test/integration/esplora_sync_test.dart | 226 +++++++------- .../wallet_surface_canary_test.dart | 294 +++++++++--------- 3 files changed, 362 insertions(+), 386 deletions(-) diff --git a/test/integration/electrum_sync_test.dart b/test/integration/electrum_sync_test.dart index 0336134..c99b605 100644 --- a/test/integration/electrum_sync_test.dart +++ b/test/integration/electrum_sync_test.dart @@ -35,123 +35,115 @@ String _createTempSqlitePath() { void main() { group('Electrum integration', () { - test( - 'sync, apply update, persist, and reload wallet state', - () { - final disposers = []; - final sqlitePath = _createTempSqlitePath(); - final electrumUrl = envOrThrow(electrumUrlEnv); - printOnFailure('Electrum URL: $electrumUrl'); - printOnFailure('SQLite path: $sqlitePath'); - - try { - final descriptor = buildBip84Descriptor(Network.testnet); - addDisposer(disposers, descriptor.dispose); - - final changeDescriptor = buildBip84ChangeDescriptor(Network.testnet); - addDisposer(disposers, changeDescriptor.dispose); - - final persister = Persister.newSqlite(path: sqlitePath); - addDisposer(disposers, persister.dispose); - - final wallet = Wallet( - descriptor: descriptor, - changeDescriptor: changeDescriptor, - network: Network.testnet, - persister: persister, - lookahead: defaultLookahead, - ); - addDisposer(disposers, wallet.dispose); - - final revealed = wallet.revealNextAddress( - keychain: KeychainKind.external_, - ); - addDisposer(disposers, revealed.address.dispose); - - final persistedAddressReveal = wallet.persist(persister: persister); - printOnFailure( - 'Persisted after reveal address: $persistedAddressReveal', - ); - - final checkpointBeforeSync = wallet.latestCheckpoint(); - final checkpointBeforeHeight = checkpointBeforeSync.height; - addDisposer(disposers, checkpointBeforeSync.hash.dispose); - printOnFailure( - 'Checkpoint before sync height: $checkpointBeforeHeight', - ); - - final requestBuilder = wallet.startSyncWithRevealedSpks(); - addDisposer(disposers, requestBuilder.dispose); - - final request = requestBuilder.build(); - addDisposer(disposers, request.dispose); - - final client = buildElectrumClientFromEnv(); - addDisposer(disposers, client.dispose); - - client.ping(); - final update = client.sync_( - request: request, - batchSize: 100, - fetchPrevTxouts: true, - ); - addDisposer(disposers, update.dispose); - - wallet.applyUpdate(update: update); - final persistedAfterSync = wallet.persist(persister: persister); - printOnFailure('Persisted after sync: $persistedAfterSync'); - - final checkpointAfterSync = wallet.latestCheckpoint(); - final checkpointAfterHeight = checkpointAfterSync.height; - addDisposer(disposers, checkpointAfterSync.hash.dispose); - printOnFailure( - 'Checkpoint after sync height: $checkpointAfterHeight', - ); - - expect( - checkpointAfterHeight, - greaterThanOrEqualTo(checkpointBeforeHeight), - ); - expect(checkpointAfterHeight, greaterThan(0)); - - final persistedExternalIndex = wallet.nextDerivationIndex( - keychain: KeychainKind.external_, - ); - printOnFailure( - 'Persisted external derivation index: $persistedExternalIndex', - ); - - final reloadedPersister = Persister.newSqlite(path: sqlitePath); - addDisposer(disposers, reloadedPersister.dispose); - - final reloadedWallet = Wallet.load( - descriptor: descriptor, - changeDescriptor: changeDescriptor, - persister: reloadedPersister, - lookahead: defaultLookahead, - ); - addDisposer(disposers, reloadedWallet.dispose); - - final reloadedExternalIndex = reloadedWallet.nextDerivationIndex( - keychain: KeychainKind.external_, - ); - expect(reloadedExternalIndex, equals(persistedExternalIndex)); - - final reloadedCheckpoint = reloadedWallet.latestCheckpoint(); - final reloadedCheckpointHeight = reloadedCheckpoint.height; - addDisposer(disposers, reloadedCheckpoint.hash.dispose); - printOnFailure( - 'Reloaded checkpoint height: $reloadedCheckpointHeight', - ); - expect( - reloadedCheckpointHeight, - greaterThanOrEqualTo(checkpointBeforeHeight), - ); - } finally { - disposeAll(disposers); - } - }, - skip: integrationSkipReason(requiredEnv: [electrumUrlEnv]), - ); + test('sync, apply update, persist, and reload wallet state', () { + final disposers = []; + final sqlitePath = _createTempSqlitePath(); + final electrumUrl = envOrThrow(electrumUrlEnv); + printOnFailure('Electrum URL: $electrumUrl'); + printOnFailure('SQLite path: $sqlitePath'); + + try { + final descriptor = buildBip84Descriptor(Network.testnet); + addDisposer(disposers, descriptor.dispose); + + final changeDescriptor = buildBip84ChangeDescriptor(Network.testnet); + addDisposer(disposers, changeDescriptor.dispose); + + final persister = Persister.newSqlite(path: sqlitePath); + addDisposer(disposers, persister.dispose); + + final wallet = Wallet( + descriptor: descriptor, + changeDescriptor: changeDescriptor, + network: Network.testnet, + persister: persister, + lookahead: defaultLookahead, + ); + addDisposer(disposers, wallet.dispose); + + final revealed = wallet.revealNextAddress( + keychain: KeychainKind.external_, + ); + addDisposer(disposers, revealed.address.dispose); + + final persistedAddressReveal = wallet.persist(persister: persister); + printOnFailure( + 'Persisted after reveal address: $persistedAddressReveal', + ); + + final checkpointBeforeSync = wallet.latestCheckpoint(); + final checkpointBeforeHeight = checkpointBeforeSync.height; + addDisposer(disposers, checkpointBeforeSync.hash.dispose); + printOnFailure( + 'Checkpoint before sync height: $checkpointBeforeHeight', + ); + + final requestBuilder = wallet.startSyncWithRevealedSpks(); + addDisposer(disposers, requestBuilder.dispose); + + final request = requestBuilder.build(); + addDisposer(disposers, request.dispose); + + final client = buildElectrumClientFromEnv(); + addDisposer(disposers, client.dispose); + + client.ping(); + final update = client.sync_( + request: request, + batchSize: 100, + fetchPrevTxouts: true, + ); + addDisposer(disposers, update.dispose); + + wallet.applyUpdate(update: update); + final persistedAfterSync = wallet.persist(persister: persister); + printOnFailure('Persisted after sync: $persistedAfterSync'); + + final checkpointAfterSync = wallet.latestCheckpoint(); + final checkpointAfterHeight = checkpointAfterSync.height; + addDisposer(disposers, checkpointAfterSync.hash.dispose); + printOnFailure('Checkpoint after sync height: $checkpointAfterHeight'); + + expect( + checkpointAfterHeight, + greaterThanOrEqualTo(checkpointBeforeHeight), + ); + expect(checkpointAfterHeight, greaterThan(0)); + + final persistedExternalIndex = wallet.nextDerivationIndex( + keychain: KeychainKind.external_, + ); + printOnFailure( + 'Persisted external derivation index: $persistedExternalIndex', + ); + + final reloadedPersister = Persister.newSqlite(path: sqlitePath); + addDisposer(disposers, reloadedPersister.dispose); + + final reloadedWallet = Wallet.load( + descriptor: descriptor, + changeDescriptor: changeDescriptor, + persister: reloadedPersister, + lookahead: defaultLookahead, + ); + addDisposer(disposers, reloadedWallet.dispose); + + final reloadedExternalIndex = reloadedWallet.nextDerivationIndex( + keychain: KeychainKind.external_, + ); + expect(reloadedExternalIndex, equals(persistedExternalIndex)); + + final reloadedCheckpoint = reloadedWallet.latestCheckpoint(); + final reloadedCheckpointHeight = reloadedCheckpoint.height; + addDisposer(disposers, reloadedCheckpoint.hash.dispose); + printOnFailure('Reloaded checkpoint height: $reloadedCheckpointHeight'); + expect( + reloadedCheckpointHeight, + greaterThanOrEqualTo(checkpointBeforeHeight), + ); + } finally { + disposeAll(disposers); + } + }, skip: integrationSkipReason(requiredEnv: [electrumUrlEnv])); }); } diff --git a/test/integration/esplora_sync_test.dart b/test/integration/esplora_sync_test.dart index da16e0f..a7b2d29 100644 --- a/test/integration/esplora_sync_test.dart +++ b/test/integration/esplora_sync_test.dart @@ -35,122 +35,114 @@ String _createTempSqlitePath() { void main() { group('Esplora integration', () { - test( - 'sync, apply update, persist, and reload wallet state', - () { - final disposers = []; - final sqlitePath = _createTempSqlitePath(); - final esploraUrl = envOrThrow(esploraUrlEnv); - printOnFailure('Esplora URL: $esploraUrl'); - printOnFailure('SQLite path: $sqlitePath'); - - try { - final descriptor = buildBip84Descriptor(Network.testnet); - addDisposer(disposers, descriptor.dispose); - - final changeDescriptor = buildBip84ChangeDescriptor(Network.testnet); - addDisposer(disposers, changeDescriptor.dispose); - - final persister = Persister.newSqlite(path: sqlitePath); - addDisposer(disposers, persister.dispose); - - final wallet = Wallet( - descriptor: descriptor, - changeDescriptor: changeDescriptor, - network: Network.testnet, - persister: persister, - lookahead: defaultLookahead, - ); - addDisposer(disposers, wallet.dispose); - - final revealed = wallet.revealNextAddress( - keychain: KeychainKind.external_, - ); - addDisposer(disposers, revealed.address.dispose); - - final persistedAddressReveal = wallet.persist(persister: persister); - printOnFailure( - 'Persisted after reveal address: $persistedAddressReveal', - ); - - final checkpointBeforeSync = wallet.latestCheckpoint(); - final checkpointBeforeHeight = checkpointBeforeSync.height; - addDisposer(disposers, checkpointBeforeSync.hash.dispose); - printOnFailure( - 'Checkpoint before sync height: $checkpointBeforeHeight', - ); - - final requestBuilder = wallet.startSyncWithRevealedSpks(); - addDisposer(disposers, requestBuilder.dispose); - - final request = requestBuilder.build(); - addDisposer(disposers, request.dispose); - - final client = buildEsploraClientFromEnv(); - addDisposer(disposers, client.dispose); - - final chainHeight = client.getHeight(); - printOnFailure('Esplora chain height: $chainHeight'); - expect(chainHeight, greaterThan(0)); - - final update = client.sync_(request: request, parallelRequests: 4); - addDisposer(disposers, update.dispose); - - wallet.applyUpdate(update: update); - final persistedAfterSync = wallet.persist(persister: persister); - printOnFailure('Persisted after sync: $persistedAfterSync'); - - final checkpointAfterSync = wallet.latestCheckpoint(); - final checkpointAfterHeight = checkpointAfterSync.height; - addDisposer(disposers, checkpointAfterSync.hash.dispose); - printOnFailure( - 'Checkpoint after sync height: $checkpointAfterHeight', - ); - - expect( - checkpointAfterHeight, - greaterThanOrEqualTo(checkpointBeforeHeight), - ); - expect(checkpointAfterHeight, greaterThan(0)); - - final persistedExternalIndex = wallet.nextDerivationIndex( - keychain: KeychainKind.external_, - ); - printOnFailure( - 'Persisted external derivation index: $persistedExternalIndex', - ); - - final reloadedPersister = Persister.newSqlite(path: sqlitePath); - addDisposer(disposers, reloadedPersister.dispose); - - final reloadedWallet = Wallet.load( - descriptor: descriptor, - changeDescriptor: changeDescriptor, - persister: reloadedPersister, - lookahead: defaultLookahead, - ); - addDisposer(disposers, reloadedWallet.dispose); - - final reloadedExternalIndex = reloadedWallet.nextDerivationIndex( - keychain: KeychainKind.external_, - ); - expect(reloadedExternalIndex, equals(persistedExternalIndex)); - - final reloadedCheckpoint = reloadedWallet.latestCheckpoint(); - final reloadedCheckpointHeight = reloadedCheckpoint.height; - addDisposer(disposers, reloadedCheckpoint.hash.dispose); - printOnFailure( - 'Reloaded checkpoint height: $reloadedCheckpointHeight', - ); - expect( - reloadedCheckpointHeight, - greaterThanOrEqualTo(checkpointBeforeHeight), - ); - } finally { - disposeAll(disposers); - } - }, - skip: integrationSkipReason(requiredEnv: [esploraUrlEnv]), - ); + test('sync, apply update, persist, and reload wallet state', () { + final disposers = []; + final sqlitePath = _createTempSqlitePath(); + final esploraUrl = envOrThrow(esploraUrlEnv); + printOnFailure('Esplora URL: $esploraUrl'); + printOnFailure('SQLite path: $sqlitePath'); + + try { + final descriptor = buildBip84Descriptor(Network.testnet); + addDisposer(disposers, descriptor.dispose); + + final changeDescriptor = buildBip84ChangeDescriptor(Network.testnet); + addDisposer(disposers, changeDescriptor.dispose); + + final persister = Persister.newSqlite(path: sqlitePath); + addDisposer(disposers, persister.dispose); + + final wallet = Wallet( + descriptor: descriptor, + changeDescriptor: changeDescriptor, + network: Network.testnet, + persister: persister, + lookahead: defaultLookahead, + ); + addDisposer(disposers, wallet.dispose); + + final revealed = wallet.revealNextAddress( + keychain: KeychainKind.external_, + ); + addDisposer(disposers, revealed.address.dispose); + + final persistedAddressReveal = wallet.persist(persister: persister); + printOnFailure( + 'Persisted after reveal address: $persistedAddressReveal', + ); + + final checkpointBeforeSync = wallet.latestCheckpoint(); + final checkpointBeforeHeight = checkpointBeforeSync.height; + addDisposer(disposers, checkpointBeforeSync.hash.dispose); + printOnFailure( + 'Checkpoint before sync height: $checkpointBeforeHeight', + ); + + final requestBuilder = wallet.startSyncWithRevealedSpks(); + addDisposer(disposers, requestBuilder.dispose); + + final request = requestBuilder.build(); + addDisposer(disposers, request.dispose); + + final client = buildEsploraClientFromEnv(); + addDisposer(disposers, client.dispose); + + final chainHeight = client.getHeight(); + printOnFailure('Esplora chain height: $chainHeight'); + expect(chainHeight, greaterThan(0)); + + final update = client.sync_(request: request, parallelRequests: 4); + addDisposer(disposers, update.dispose); + + wallet.applyUpdate(update: update); + final persistedAfterSync = wallet.persist(persister: persister); + printOnFailure('Persisted after sync: $persistedAfterSync'); + + final checkpointAfterSync = wallet.latestCheckpoint(); + final checkpointAfterHeight = checkpointAfterSync.height; + addDisposer(disposers, checkpointAfterSync.hash.dispose); + printOnFailure('Checkpoint after sync height: $checkpointAfterHeight'); + + expect( + checkpointAfterHeight, + greaterThanOrEqualTo(checkpointBeforeHeight), + ); + expect(checkpointAfterHeight, greaterThan(0)); + + final persistedExternalIndex = wallet.nextDerivationIndex( + keychain: KeychainKind.external_, + ); + printOnFailure( + 'Persisted external derivation index: $persistedExternalIndex', + ); + + final reloadedPersister = Persister.newSqlite(path: sqlitePath); + addDisposer(disposers, reloadedPersister.dispose); + + final reloadedWallet = Wallet.load( + descriptor: descriptor, + changeDescriptor: changeDescriptor, + persister: reloadedPersister, + lookahead: defaultLookahead, + ); + addDisposer(disposers, reloadedWallet.dispose); + + final reloadedExternalIndex = reloadedWallet.nextDerivationIndex( + keychain: KeychainKind.external_, + ); + expect(reloadedExternalIndex, equals(persistedExternalIndex)); + + final reloadedCheckpoint = reloadedWallet.latestCheckpoint(); + final reloadedCheckpointHeight = reloadedCheckpoint.height; + addDisposer(disposers, reloadedCheckpoint.hash.dispose); + printOnFailure('Reloaded checkpoint height: $reloadedCheckpointHeight'); + expect( + reloadedCheckpointHeight, + greaterThanOrEqualTo(checkpointBeforeHeight), + ); + } finally { + disposeAll(disposers); + } + }, skip: integrationSkipReason(requiredEnv: [esploraUrlEnv])); }); } diff --git a/test/integration/wallet_surface_canary_test.dart b/test/integration/wallet_surface_canary_test.dart index 2c538fb..7d99087 100644 --- a/test/integration/wallet_surface_canary_test.dart +++ b/test/integration/wallet_surface_canary_test.dart @@ -114,160 +114,152 @@ void _exerciseWalletReadSurface(Wallet wallet) { void main() { group('Workflow surface canary', () { - test( - 'electrum sync path exercises broad wallet surface', - () { - final disposers = []; - final sqlitePath = _createTempSqlitePath( - 'bdk_dart_surface_canary_electrum_', + test('electrum sync path exercises broad wallet surface', () { + final disposers = []; + final sqlitePath = _createTempSqlitePath( + 'bdk_dart_surface_canary_electrum_', + ); + + try { + final descriptor = buildBip84Descriptor(Network.testnet); + addDisposer(disposers, descriptor.dispose); + + final changeDescriptor = buildBip84ChangeDescriptor(Network.testnet); + addDisposer(disposers, changeDescriptor.dispose); + + final persister = Persister.newSqlite(path: sqlitePath); + addDisposer(disposers, persister.dispose); + + final wallet = Wallet( + descriptor: descriptor, + changeDescriptor: changeDescriptor, + network: Network.testnet, + persister: persister, + lookahead: defaultLookahead, ); + addDisposer(disposers, wallet.dispose); - try { - final descriptor = buildBip84Descriptor(Network.testnet); - addDisposer(disposers, descriptor.dispose); - - final changeDescriptor = buildBip84ChangeDescriptor(Network.testnet); - addDisposer(disposers, changeDescriptor.dispose); - - final persister = Persister.newSqlite(path: sqlitePath); - addDisposer(disposers, persister.dispose); - - final wallet = Wallet( - descriptor: descriptor, - changeDescriptor: changeDescriptor, - network: Network.testnet, - persister: persister, - lookahead: defaultLookahead, - ); - addDisposer(disposers, wallet.dispose); - - wallet.revealNextAddress(keychain: KeychainKind.external_); - wallet.persist(persister: persister); - final checkpointBeforeSync = wallet.latestCheckpoint().height; - - final requestBuilder = wallet.startSyncWithRevealedSpks(); - addDisposer(disposers, requestBuilder.dispose); - final request = requestBuilder.build(); - addDisposer(disposers, request.dispose); - - final client = buildElectrumClientFromEnv(); - addDisposer(disposers, client.dispose); - client.ping(); - - final update = client.sync_( - request: request, - batchSize: 100, - fetchPrevTxouts: true, - ); - addDisposer(disposers, update.dispose); - - final events = wallet.applyUpdateEvents(update: update); - _exerciseWalletEventSurface(events); - _exerciseWalletReadSurface(wallet); - - wallet.persist(persister: persister); - final txCountBeforeReload = wallet.transactions().length; - - final reloadedPersister = Persister.newSqlite(path: sqlitePath); - addDisposer(disposers, reloadedPersister.dispose); - final reloadedWallet = Wallet.load( - descriptor: descriptor, - changeDescriptor: changeDescriptor, - persister: reloadedPersister, - lookahead: defaultLookahead, - ); - addDisposer(disposers, reloadedWallet.dispose); - - expect( - reloadedWallet.latestCheckpoint().height, - greaterThanOrEqualTo(checkpointBeforeSync), - ); - _exerciseWalletReadSurface(reloadedWallet); - expect( - reloadedWallet.transactions().length, - equals(txCountBeforeReload), - ); - } finally { - disposeAll(disposers); - } - }, - skip: integrationSkipReason(requiredEnv: [electrumUrlEnv]), - ); - - test( - 'esplora sync path exercises broad wallet surface', - () { - final disposers = []; - final sqlitePath = _createTempSqlitePath( - 'bdk_dart_surface_canary_esplora_', + wallet.revealNextAddress(keychain: KeychainKind.external_); + wallet.persist(persister: persister); + final checkpointBeforeSync = wallet.latestCheckpoint().height; + + final requestBuilder = wallet.startSyncWithRevealedSpks(); + addDisposer(disposers, requestBuilder.dispose); + final request = requestBuilder.build(); + addDisposer(disposers, request.dispose); + + final client = buildElectrumClientFromEnv(); + addDisposer(disposers, client.dispose); + client.ping(); + + final update = client.sync_( + request: request, + batchSize: 100, + fetchPrevTxouts: true, + ); + addDisposer(disposers, update.dispose); + + final events = wallet.applyUpdateEvents(update: update); + _exerciseWalletEventSurface(events); + _exerciseWalletReadSurface(wallet); + + wallet.persist(persister: persister); + final txCountBeforeReload = wallet.transactions().length; + + final reloadedPersister = Persister.newSqlite(path: sqlitePath); + addDisposer(disposers, reloadedPersister.dispose); + final reloadedWallet = Wallet.load( + descriptor: descriptor, + changeDescriptor: changeDescriptor, + persister: reloadedPersister, + lookahead: defaultLookahead, ); + addDisposer(disposers, reloadedWallet.dispose); - try { - final descriptor = buildBip84Descriptor(Network.testnet); - addDisposer(disposers, descriptor.dispose); - - final changeDescriptor = buildBip84ChangeDescriptor(Network.testnet); - addDisposer(disposers, changeDescriptor.dispose); - - final persister = Persister.newSqlite(path: sqlitePath); - addDisposer(disposers, persister.dispose); - - final wallet = Wallet( - descriptor: descriptor, - changeDescriptor: changeDescriptor, - network: Network.testnet, - persister: persister, - lookahead: defaultLookahead, - ); - addDisposer(disposers, wallet.dispose); - - wallet.revealNextAddress(keychain: KeychainKind.external_); - wallet.persist(persister: persister); - final checkpointBeforeSync = wallet.latestCheckpoint().height; - - final requestBuilder = wallet.startSyncWithRevealedSpks(); - addDisposer(disposers, requestBuilder.dispose); - final request = requestBuilder.build(); - addDisposer(disposers, request.dispose); - - final client = buildEsploraClientFromEnv(); - addDisposer(disposers, client.dispose); - expect(client.getHeight(), greaterThan(0)); - - final update = client.sync_(request: request, parallelRequests: 4); - addDisposer(disposers, update.dispose); - - final events = wallet.applyUpdateEvents(update: update); - _exerciseWalletEventSurface(events); - _exerciseWalletReadSurface(wallet); - - wallet.persist(persister: persister); - final txCountBeforeReload = wallet.transactions().length; - - final reloadedPersister = Persister.newSqlite(path: sqlitePath); - addDisposer(disposers, reloadedPersister.dispose); - final reloadedWallet = Wallet.load( - descriptor: descriptor, - changeDescriptor: changeDescriptor, - persister: reloadedPersister, - lookahead: defaultLookahead, - ); - addDisposer(disposers, reloadedWallet.dispose); - - expect( - reloadedWallet.latestCheckpoint().height, - greaterThanOrEqualTo(checkpointBeforeSync), - ); - _exerciseWalletReadSurface(reloadedWallet); - expect( - reloadedWallet.transactions().length, - equals(txCountBeforeReload), - ); - } finally { - disposeAll(disposers); - } - }, - skip: integrationSkipReason(requiredEnv: [esploraUrlEnv]), - ); + expect( + reloadedWallet.latestCheckpoint().height, + greaterThanOrEqualTo(checkpointBeforeSync), + ); + _exerciseWalletReadSurface(reloadedWallet); + expect( + reloadedWallet.transactions().length, + equals(txCountBeforeReload), + ); + } finally { + disposeAll(disposers); + } + }, skip: integrationSkipReason(requiredEnv: [electrumUrlEnv])); + + test('esplora sync path exercises broad wallet surface', () { + final disposers = []; + final sqlitePath = _createTempSqlitePath( + 'bdk_dart_surface_canary_esplora_', + ); + + try { + final descriptor = buildBip84Descriptor(Network.testnet); + addDisposer(disposers, descriptor.dispose); + + final changeDescriptor = buildBip84ChangeDescriptor(Network.testnet); + addDisposer(disposers, changeDescriptor.dispose); + + final persister = Persister.newSqlite(path: sqlitePath); + addDisposer(disposers, persister.dispose); + + final wallet = Wallet( + descriptor: descriptor, + changeDescriptor: changeDescriptor, + network: Network.testnet, + persister: persister, + lookahead: defaultLookahead, + ); + addDisposer(disposers, wallet.dispose); + + wallet.revealNextAddress(keychain: KeychainKind.external_); + wallet.persist(persister: persister); + final checkpointBeforeSync = wallet.latestCheckpoint().height; + + final requestBuilder = wallet.startSyncWithRevealedSpks(); + addDisposer(disposers, requestBuilder.dispose); + final request = requestBuilder.build(); + addDisposer(disposers, request.dispose); + + final client = buildEsploraClientFromEnv(); + addDisposer(disposers, client.dispose); + expect(client.getHeight(), greaterThan(0)); + + final update = client.sync_(request: request, parallelRequests: 4); + addDisposer(disposers, update.dispose); + + final events = wallet.applyUpdateEvents(update: update); + _exerciseWalletEventSurface(events); + _exerciseWalletReadSurface(wallet); + + wallet.persist(persister: persister); + final txCountBeforeReload = wallet.transactions().length; + + final reloadedPersister = Persister.newSqlite(path: sqlitePath); + addDisposer(disposers, reloadedPersister.dispose); + final reloadedWallet = Wallet.load( + descriptor: descriptor, + changeDescriptor: changeDescriptor, + persister: reloadedPersister, + lookahead: defaultLookahead, + ); + addDisposer(disposers, reloadedWallet.dispose); + + expect( + reloadedWallet.latestCheckpoint().height, + greaterThanOrEqualTo(checkpointBeforeSync), + ); + _exerciseWalletReadSurface(reloadedWallet); + expect( + reloadedWallet.transactions().length, + equals(txCountBeforeReload), + ); + } finally { + disposeAll(disposers); + } + }, skip: integrationSkipReason(requiredEnv: [esploraUrlEnv])); }); } From 895083a14a8462c73b94180de29e3ccaf864716a Mon Sep 17 00:00:00 2001 From: Johnosezele Date: Mon, 5 Oct 2026 23:13:41 +0100 Subject: [PATCH 3/3] chore: update CONTRIBUTING.md to tell contributors to install Dart 3.13.4 --- CONTRIBUTING.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ea212f1..3f492bb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,8 +4,10 @@ Keep PRs focused and include the smallest checks that cover the change. ## Setup -Install Dart 3.10 or newer (CI uses 3.13.4) and Rust stable. Install Flutter -stable when working on `bdk_demo` or mobile targets. +Install Dart 3.13.4 for local development and formatting. `dart format` output +differs between 3.10 and 3.13, and CI checks formatting on 3.13.4. The published +package still allows Dart `^3.10.0` (`pubspec.yaml`). Install Rust stable, and +Flutter stable when working on `bdk_demo` or mobile targets. From the repository root: