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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/upstream-compat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ 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.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:

Expand Down
5 changes: 5 additions & 0 deletions bdk_demo/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
228 changes: 110 additions & 118 deletions test/integration/electrum_sync_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,123 +35,115 @@ String _createTempSqlitePath() {

void main() {
group('Electrum integration', () {
test(
'sync, apply update, persist, and reload wallet state',
() {
final disposers = <Disposer>[];
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 = <Disposer>[];
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]));
});
}
Loading
Loading