feat: bump rust libraries to alpha 13

This commit is contained in:
thunderbiscuit 2024-06-24 10:15:30 -04:00
parent 92aeeab436
commit f66f8417cf
No known key found for this signature in database
GPG Key ID: 88253696EB836462
10 changed files with 438 additions and 655 deletions

220
bdk-ffi/Cargo.lock generated
View File

@ -128,6 +128,16 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "base58ck"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f"
dependencies = [
"bitcoin-internals 0.3.0",
"bitcoin_hashes 0.14.0",
]
[[package]]
name = "base64"
version = "0.12.3"
@ -165,37 +175,27 @@ dependencies = [
"bdk_esplora",
"bdk_sqlite",
"bdk_wallet",
"bitcoin-internals",
"bitcoin-internals 0.2.0",
"thiserror",
"uniffi",
]
[[package]]
name = "bdk_bitcoind_rpc"
version = "0.10.0"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54fe9410002d5c350b59145ed0b18af1bb81521e7d62515defe539a450e20551"
checksum = "ae8b85b7f47af08bb41d6fb9301c9de8ad937a4d506ba0d9920b094fd48d8fbb"
dependencies = [
"bdk_chain 0.14.0",
"bdk_chain",
"bitcoin",
"bitcoincore-rpc",
]
[[package]]
name = "bdk_chain"
version = "0.14.0"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "440ec5b1c8911f126b540e05c98493b699b497a3cb90c5e9c5eee21cdd8d1e01"
dependencies = [
"bitcoin",
"miniscript",
]
[[package]]
name = "bdk_chain"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c601c4dc7e6c3efa538a0afbb43b964cefab9a9b5e8f352fa0ca38145448a5e7"
checksum = "163b064557cee078e8ee5dd2c88944204506f7b2b1524f78e8fcba38c346da7b"
dependencies = [
"bitcoin",
"miniscript",
@ -204,43 +204,31 @@ dependencies = [
[[package]]
name = "bdk_electrum"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28906275aeb1f71dc32045670f06c8a26fb17cc62151a99f7425d258f4bda589"
version = "0.15.0"
source = "git+https://github.com/thunderbiscuit/bdk/?branch=feature/electrum-client-ring-feature#31ddf1b4b600e9bf10e622cb0dee7ff158439b48"
dependencies = [
"bdk_chain 0.15.0",
"bdk_chain",
"electrum-client",
]
[[package]]
name = "bdk_esplora"
version = "0.14.0"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b2409ff6b35fc69e864bc6986731e024ccd70bd325183f8ffff1590d9895d1"
checksum = "089babab213bbb32518bad79a7313ebb4c85a52c18c8b558402dfa810c27de3f"
dependencies = [
"bdk_chain 0.15.0",
"bdk_chain",
"esplora-client",
]
[[package]]
name = "bdk_persist"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41528569e8507f078143526c72bdee75f93f17d3b028cb7d88b4889278973e7d"
dependencies = [
"anyhow",
"bdk_chain 0.15.0",
"miniscript",
]
[[package]]
name = "bdk_sqlite"
version = "0.1.0"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b665413b2c5d5151dbb9cb6a855ccbbc26fdb6143f22faf2deea4e8c61fc33e6"
checksum = "0926dc5778fb3c5afaf7def9ed9b9c9d9fe9e3ba499e09cb816d3de43211be71"
dependencies = [
"anyhow",
"bdk_chain 0.15.0",
"bdk_persist",
"bdk_chain",
"rusqlite",
"serde",
"serde_json",
@ -248,13 +236,11 @@ dependencies = [
[[package]]
name = "bdk_wallet"
version = "1.0.0-alpha.12"
version = "1.0.0-alpha.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f830d1a9a090b5837d3813aff8b90888e04b72bf2704b29796e1bab439c86255"
checksum = "2926afdbfc54ebf7df2caa51af5be4435b90c01c6fbe5578b51b7c2c0a264bd9"
dependencies = [
"anyhow",
"bdk_chain 0.15.0",
"bdk_persist",
"bdk_chain",
"bip39",
"bitcoin",
"getrandom",
@ -267,9 +253,9 @@ dependencies = [
[[package]]
name = "bech32"
version = "0.10.0-beta"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98f7eed2b2781a6f0b5c903471d48e15f56fb4e1165df8a9a2337fd1a59d45ea"
checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d"
[[package]]
name = "bincode"
@ -293,15 +279,18 @@ dependencies = [
[[package]]
name = "bitcoin"
version = "0.31.2"
version = "0.32.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c85783c2fe40083ea54a33aa2f0ba58831d90fcd190f5bdc47e74e84d2a96ae"
checksum = "ea507acc1cd80fc084ace38544bbcf7ced7c2aa65b653b102de0ce718df668f6"
dependencies = [
"base58ck",
"base64 0.21.7",
"bech32",
"bitcoin-internals",
"bitcoin_hashes 0.13.0",
"hex-conservative 0.1.2",
"bitcoin-internals 0.3.0",
"bitcoin-io",
"bitcoin-units",
"bitcoin_hashes 0.14.0",
"hex-conservative",
"hex_lit",
"secp256k1",
"serde",
@ -312,10 +301,32 @@ name = "bitcoin-internals"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb"
[[package]]
name = "bitcoin-internals"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2"
dependencies = [
"serde",
]
[[package]]
name = "bitcoin-io"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56"
[[package]]
name = "bitcoin-units"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb54da0b28892f3c52203a7191534033e051b6f4b52bc15480681b57b7e036f5"
dependencies = [
"bitcoin-internals 0.3.0",
"serde",
]
[[package]]
name = "bitcoin_hashes"
version = "0.11.0"
@ -324,20 +335,20 @@ checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4"
[[package]]
name = "bitcoin_hashes"
version = "0.13.0"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b"
checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16"
dependencies = [
"bitcoin-internals",
"hex-conservative 0.1.2",
"bitcoin-io",
"hex-conservative",
"serde",
]
[[package]]
name = "bitcoincore-rpc"
version = "0.18.0"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eb70725a621848c83b3809913d5314c0d20ca84877d99dd909504b564edab00"
checksum = "aedd23ae0fd321affb4bbbc36126c6f49a32818dc6b979395d24da8c9d4e80ee"
dependencies = [
"bitcoincore-rpc-json",
"jsonrpc",
@ -348,9 +359,9 @@ dependencies = [
[[package]]
name = "bitcoincore-rpc-json"
version = "0.18.0"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "856ffbee2e492c23bca715d72ea34aae80d58400f2bda26a82015d6bc2ec3662"
checksum = "d8909583c5fab98508e80ef73e5592a651c954993dc6b7739963257d19f0e71a"
dependencies = [
"bitcoin",
"serde",
@ -473,15 +484,14 @@ checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
[[package]]
name = "electrum-client"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89008f106be6f303695522f2f4c1f28b40c3e8367ed8b3bb227f1f882cb52cc2"
version = "0.20.0"
source = "git+https://github.com/thunderbiscuit/rust-electrum-client/?branch=feature/ring-feature#7576e1b6d1f298d270526d740b8508923f3fb790"
dependencies = [
"bitcoin",
"byteorder",
"libc",
"log",
"rustls",
"rustls 0.23.10",
"serde",
"serde_json",
"webpki-roots",
@ -490,12 +500,12 @@ dependencies = [
[[package]]
name = "esplora-client"
version = "0.7.0"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a73e879128c5fcb38abaf0ec53e3310947c6e7b61ce0f1b4cd7a0b8ea1ab0389"
checksum = "69c6d27ef4ff21019edd98aa92199757e10a88065bbfcef6bb750ca6ec5e4a45"
dependencies = [
"bitcoin",
"hex-conservative 0.2.1",
"hex-conservative",
"log",
"minreq",
"serde",
@ -574,12 +584,6 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hex-conservative"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20"
[[package]]
name = "hex-conservative"
version = "0.2.1"
@ -618,11 +622,12 @@ dependencies = [
[[package]]
name = "jsonrpc"
version = "0.14.1"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8128f36b47411cd3f044be8c1f5cc0c9e24d1d1bfdc45f0a57897b32513053f2"
checksum = "3662a38d341d77efecb73caf01420cfa5aa63c0253fd7bc05289ef9f6616e1bf"
dependencies = [
"base64 0.13.1",
"minreq",
"serde",
"serde_json",
]
@ -652,9 +657,9 @@ checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "memchr"
version = "2.7.2"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "mime"
@ -680,13 +685,12 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniscript"
version = "11.0.0"
version = "12.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86a23dd3ad145a980e231185d114399f25a0a307d2cd918010ddda6334323df9"
checksum = "b59c67956fd276ceec0cf194fbf80754ef4d88a496d5cf5e4fdf33561466183d"
dependencies = [
"bech32",
"bitcoin",
"bitcoin-internals",
"serde",
]
@ -699,8 +703,8 @@ dependencies = [
"base64 0.12.3",
"log",
"once_cell",
"rustls",
"rustls-webpki",
"rustls 0.21.12",
"rustls-webpki 0.101.7",
"serde",
"serde_json",
"webpki-roots",
@ -831,10 +835,31 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
dependencies = [
"log",
"ring",
"rustls-webpki",
"rustls-webpki 0.101.7",
"sct",
]
[[package]]
name = "rustls"
version = "0.23.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402"
dependencies = [
"log",
"once_cell",
"ring",
"rustls-pki-types",
"rustls-webpki 0.102.4",
"subtle",
"zeroize",
]
[[package]]
name = "rustls-pki-types"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
[[package]]
name = "rustls-webpki"
version = "0.101.7"
@ -845,6 +870,17 @@ dependencies = [
"untrusted",
]
[[package]]
name = "rustls-webpki"
version = "0.102.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e"
dependencies = [
"ring",
"rustls-pki-types",
"untrusted",
]
[[package]]
name = "ryu"
version = "1.0.18"
@ -883,11 +919,11 @@ dependencies = [
[[package]]
name = "secp256k1"
version = "0.28.2"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10"
checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3"
dependencies = [
"bitcoin_hashes 0.13.0",
"bitcoin_hashes 0.14.0",
"rand",
"secp256k1-sys",
"serde",
@ -895,9 +931,9 @@ dependencies = [
[[package]]
name = "secp256k1-sys"
version = "0.9.2"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb"
checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b"
dependencies = [
"cc",
]
@ -978,6 +1014,12 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "subtle"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d0208408ba0c3df17ed26eb06992cb1a1268d41b2c0e12e65203fbe3972cee5"
[[package]]
name = "syn"
version = "2.0.66"
@ -1410,3 +1452,9 @@ dependencies = [
"quote",
"syn",
]
[[package]]
name = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"

View File

@ -18,14 +18,17 @@ path = "uniffi-bindgen.rs"
default = ["uniffi/cli"]
[dependencies]
bdk_wallet = { version = "1.0.0-alpha.12", features = ["all-keys", "keys-bip39"] }
bdk_esplora = { version = "0.14.0", default-features = false, features = ["std", "blocking", "blocking-https-rustls"] }
bdk_electrum = { version = "0.14.0" }
bdk_sqlite = { version = "0.1.0" }
bdk_bitcoind_rpc = { version = "0.10.0" }
bdk_wallet = { version = "1.0.0-alpha.13", features = ["all-keys", "keys-bip39"] }
bdk_esplora = { version = "0.15.0", default-features = false, features = ["std", "blocking", "blocking-https-rustls"] }
# NOTE: This is a temporary workaround to use the electrum-client with the use-rustls-ring feature. It points to a fork
# of bdk in which the bdk_electrum library uses the electrum-client with the use-rustls-ring feature.
bdk_electrum = { git = "https://github.com/thunderbiscuit/bdk/", package = "bdk_electrum", branch = "feature/electrum-client-ring-feature" }
# bdk_electrum = { version = "0.15.0" }
bdk_sqlite = { version = "0.2.0" }
bdk_bitcoind_rpc = { version = "0.12.0" }
bitcoin-internals = { version = "0.2.0", features = ["alloc"] }
uniffi = { version = "=0.28.0" }
bitcoin-internals = { version = "0.2.0", features = ["alloc"] }
thiserror = "1.0.58"
[build-dependencies]

View File

@ -5,16 +5,17 @@ namespace bdk {};
// ------------------------------------------------------------------------
[Error]
interface AddressError {
interface AddressParseError {
Base58();
Bech32();
WitnessVersion(string error_message);
WitnessProgram(string error_message);
UncompressedPubkey();
ExcessiveScriptSize();
UnrecognizedScript();
NetworkValidation(Network required, Network found, string address);
OtherAddressErr();
UnknownHrp();
LegacyAddressTooLong();
InvalidBase58PayloadLength();
InvalidLegacyPrefix();
NetworkValidation();
OtherAddressParseErr();
};
[Error]
@ -44,7 +45,7 @@ interface Bip39Error {
[Error]
interface CalculateFeeError {
MissingTxOut(sequence<OutPoint> out_points);
NegativeFee(i64 fee);
NegativeFee(string amount);
};
[Error]
@ -55,7 +56,6 @@ interface CannotConnectError {
[Error]
interface CreateTxError {
Descriptor(string error_message);
Persist(string error_message);
Policy(string error_message);
SpendingPolicyRequired(string kind);
Version0();
@ -63,7 +63,7 @@ interface CreateTxError {
LockTime(string requested, string required);
RbfSequence();
RbfSequenceCsv(string rbf, string csv);
FeeTooLow(u64 required);
FeeTooLow(string required);
FeeRateTooLow(string required);
NoUtxosSelected();
OutputBelowDustLimit(u64 index);
@ -92,6 +92,7 @@ interface DescriptorError {
Pk(string error_message);
Miniscript(string error_message);
Hex(string error_message);
ExternalAndInternalAreTheSame();
};
[Error]
@ -152,16 +153,21 @@ enum FeeRateError {
"ArithmeticOverflow"
};
[Error]
interface FromScriptError {
UnrecognizedScript();
WitnessProgram(string error_message);
WitnessVersion(string error_message);
OtherFromScriptErr();
};
[Error]
interface ParseAmountError {
Negative();
TooBig();
OutOfRange();
TooPrecise();
InvalidFormat();
MissingDigits();
InputTooLarge();
InvalidCharacter(string error_message);
UnknownDenomination(string error_message);
PossiblyConfusingDenomination(string error_message);
OtherParseAmountErr();
};
@ -231,7 +237,9 @@ interface SignerError {
MissingHdKeypath();
NonStandardSighash();
InvalidSighash();
SighashError(string error_message);
SighashP2wpkh(string error_message);
SighashTaproot(string error_message);
TxInputsIndexError(string error_message);
MiniscriptPsbt(string error_message);
External(string error_message);
};
@ -260,19 +268,14 @@ interface TxidParseError {
[Error]
interface WalletCreationError {
Io(string error_message);
InvalidMagicBytes(sequence<u8> got, sequence<u8> expected);
Descriptor();
Persist(string error_message);
NotInitialized();
Descriptor(string error_message);
LoadedGenesisDoesNotMatch(string expected, string got);
LoadedNetworkDoesNotMatch(Network expected, Network? got);
LoadedDescriptorDoesNotMatch(string got, KeychainKind keychain);
Sqlite(string error_message);
};
// ------------------------------------------------------------------------
// bdk crate - types module
// bdk_wallet crate - types module
// ------------------------------------------------------------------------
enum KeychainKind {
@ -343,8 +346,10 @@ interface FullScanScriptInspector {
void inspect(KeychainKind keychain, u32 index, Script script);
};
interface ChangeSet {};
// ------------------------------------------------------------------------
// bdk crate - wallet module
// bdk_wallet crate - wallet module
// ------------------------------------------------------------------------
enum ChangeSpendPolicy {
@ -355,24 +360,20 @@ enum ChangeSpendPolicy {
interface Wallet {
[Throws=WalletCreationError]
constructor(Descriptor descriptor, Descriptor? change_descriptor, string persistence_backend_path, Network network);
constructor(Descriptor descriptor, Descriptor change_descriptor, Network network);
[Name=new_no_persist, Throws=DescriptorError]
constructor(Descriptor descriptor, Descriptor? change_descriptor, Network network);
// [Name=new_or_load, Throws=WalletCreationError]
// constructor(Descriptor descriptor, Descriptor change_descriptor, Network network);
[Throws=PersistenceError]
AddressInfo reveal_next_address(KeychainKind keychain);
Network network();
Balance get_balance();
Balance balance();
[Throws=CannotConnectError]
void apply_update(Update update);
[Throws=PersistenceError]
boolean commit();
boolean is_mine([ByRef] Script script);
[Throws=SignerError]
@ -386,7 +387,7 @@ interface Wallet {
CanonicalTx? get_tx(string txid);
[Throws=CalculateFeeError]
u64 calculate_fee([ByRef] Transaction tx);
Amount calculate_fee([ByRef] Transaction tx);
[Throws=CalculateFeeError]
FeeRate calculate_fee_rate([ByRef] Transaction tx);
@ -398,6 +399,8 @@ interface Wallet {
FullScanRequest start_full_scan();
SyncRequest start_sync_with_revealed_spks();
ChangeSet? take_staged();
};
interface Update {};
@ -450,6 +453,18 @@ interface BumpFeeTxBuilder {
Psbt finish([ByRef] Wallet wallet);
};
// ------------------------------------------------------------------------
// bdk_sqlite crate
// ------------------------------------------------------------------------
interface SqliteStore {
[Throws=SqliteError]
constructor(string path);
[Throws=SqliteError]
void write([ByRef] ChangeSet change_set);
};
// ------------------------------------------------------------------------
// bdk crate - descriptor module
// ------------------------------------------------------------------------
@ -584,7 +599,7 @@ dictionary SentAndReceivedValues {
};
// ------------------------------------------------------------------------
// bdk crate - bitcoin re-exports
// bdk_wallet crate - bitcoin re-exports
// ------------------------------------------------------------------------
interface Script {
@ -611,14 +626,12 @@ enum WordCount {
[Traits=(Display)]
interface Address {
[Throws=AddressError]
[Throws=AddressParseError]
constructor(string address, Network network);
[Name=from_script, Throws=AddressError]
[Name=from_script, Throws=FromScriptError]
constructor(Script script, Network network);
Network network();
Script script_pubkey();
string to_qr_uri();
@ -630,7 +643,7 @@ interface Transaction {
[Throws=TransactionError]
constructor(sequence<u8> transaction_bytes);
string txid();
string compute_txid();
u64 total_size();

View File

@ -1,5 +1,6 @@
use crate::error::{AddressError, FeeRateError, PsbtError, PsbtParseError, TransactionError};
use std::fmt::Display;
use crate::error::{
AddressParseError, FeeRateError, FromScriptError, PsbtError, PsbtParseError, TransactionError,
};
use bdk_bitcoind_rpc::bitcoincore_rpc::jsonrpc::serde_json;
use bdk_wallet::bitcoin::address::{NetworkChecked, NetworkUnchecked};
@ -8,6 +9,7 @@ use bdk_wallet::bitcoin::blockdata::script::ScriptBuf as BdkScriptBuf;
use bdk_wallet::bitcoin::blockdata::transaction::TxOut as BdkTxOut;
use bdk_wallet::bitcoin::consensus::encode::serialize;
use bdk_wallet::bitcoin::consensus::Decodable;
use bdk_wallet::bitcoin::io::Cursor;
use bdk_wallet::bitcoin::psbt::ExtractTxError;
use bdk_wallet::bitcoin::Address as BdkAddress;
use bdk_wallet::bitcoin::Amount as BdkAmount;
@ -19,7 +21,7 @@ use bdk_wallet::bitcoin::Transaction as BdkTransaction;
use bdk_wallet::bitcoin::TxIn as BdkTxIn;
use bdk_wallet::bitcoin::Txid;
use std::io::Cursor;
use std::fmt::Display;
use std::ops::Deref;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
@ -82,23 +84,19 @@ impl From<BdkScriptBuf> for Script {
pub struct Address(BdkAddress<NetworkChecked>);
impl Address {
pub fn new(address: String, network: Network) -> Result<Self, AddressError> {
pub fn new(address: String, network: Network) -> Result<Self, AddressParseError> {
let parsed_address = address.parse::<bdk_wallet::bitcoin::Address<NetworkUnchecked>>()?;
let network_checked_address = parsed_address.require_network(network)?;
Ok(Address(network_checked_address))
}
pub fn from_script(script: Arc<Script>, network: Network) -> Result<Self, AddressError> {
pub fn from_script(script: Arc<Script>, network: Network) -> Result<Self, FromScriptError> {
let address = BdkAddress::from_script(&script.0.clone(), network)?;
Ok(Address(address))
}
pub fn network(&self) -> Network {
*self.0.network()
}
pub fn script_pubkey(&self) -> Arc<Script> {
Arc::new(Script(self.0.script_pubkey()))
}
@ -145,8 +143,8 @@ impl Transaction {
Ok(Transaction(tx))
}
pub fn txid(&self) -> String {
self.0.txid().to_string()
pub fn compute_txid(&self) -> String {
self.0.compute_txid().to_string()
}
pub fn weight(&self) -> u64 {
@ -374,11 +372,6 @@ mod tests {
docs_address_testnet.is_valid_for_network(Network::Regtest),
"Address should be valid for Regtest"
);
assert_ne!(
docs_address_testnet.network(),
Network::Bitcoin,
"Address should not be parsed as Bitcoin"
);
let docs_address_mainnet_str = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf";
let docs_address_mainnet =
@ -387,21 +380,6 @@ mod tests {
docs_address_mainnet.is_valid_for_network(Network::Bitcoin),
"Address should be valid for Bitcoin"
);
assert_ne!(
docs_address_mainnet.network(),
Network::Testnet,
"Address should not be valid for Testnet"
);
assert_ne!(
docs_address_mainnet.network(),
Network::Signet,
"Address should not be valid for Signet"
);
assert_ne!(
docs_address_mainnet.network(),
Network::Regtest,
"Address should not be valid for Regtest"
);
// ====Bech32====

View File

@ -3,8 +3,8 @@ use crate::error::ElectrumError;
use crate::types::{FullScanRequest, SyncRequest};
use crate::wallet::Update;
use bdk_electrum::electrum_client::{Client as BdkBlockingClient, ElectrumApi};
use bdk_electrum::{ElectrumExt, ElectrumFullScanResult, ElectrumSyncResult};
use bdk_electrum::BdkElectrumClient as BdkBdkElectrumClient;
use bdk_electrum::{ElectrumFullScanResult, ElectrumSyncResult};
use bdk_wallet::bitcoin::Transaction as BdkTransaction;
use bdk_wallet::chain::spk_client::FullScanRequest as BdkFullScanRequest;
use bdk_wallet::chain::spk_client::FullScanResult as BdkFullScanResult;
@ -16,11 +16,16 @@ use bdk_wallet::KeychainKind;
use std::collections::BTreeMap;
use std::sync::Arc;
pub struct ElectrumClient(BdkBlockingClient);
// NOTE: We are keeping our naming convention where the alias of the inner type is the Rust type
// prefixed with `Bdk`. In this case the inner type is `BdkElectrumClient`, so the alias is
// funnily enough named `BdkBdkElectrumClient`.
pub struct ElectrumClient(BdkBdkElectrumClient<bdk_electrum::electrum_client::Client>);
impl ElectrumClient {
pub fn new(url: String) -> Result<Self, ElectrumError> {
let client = BdkBlockingClient::new(url.as_str())?;
let inner_client: bdk_electrum::electrum_client::Client =
bdk_electrum::electrum_client::Client::new(url.as_str())?;
let client = BdkBdkElectrumClient::new(inner_client);
Ok(Self(client))
}

View File

@ -1,12 +1,12 @@
use crate::bitcoin::OutPoint;
use crate::Network;
use bdk_bitcoind_rpc::bitcoincore_rpc::bitcoin::address::ParseError;
use bdk_electrum::electrum_client::Error as BdkElectrumError;
use bdk_esplora::esplora_client::{Error as BdkEsploraError, Error};
use bdk_sqlite::rusqlite::Error as BdkRusqliteError;
use bdk_sqlite::Error as BdkSqliteError;
use bdk_wallet::bitcoin::address::Error as BdkAddressError;
use bdk_wallet::bitcoin::address::ParseError;
use bdk_wallet::bitcoin::address::FromScriptError as BdkFromScriptError;
use bdk_wallet::bitcoin::address::ParseError as BdkParseError;
use bdk_wallet::bitcoin::amount::ParseAmountError as BdkParseAmountError;
use bdk_wallet::bitcoin::bip32::Error as BdkBip32Error;
use bdk_wallet::bitcoin::consensus::encode::Error as BdkEncodeError;
@ -22,7 +22,7 @@ use bdk_wallet::wallet::error::BuildFeeBumpError;
use bdk_wallet::wallet::error::CreateTxError as BdkCreateTxError;
use bdk_wallet::wallet::signer::SignerError as BdkSignerError;
use bdk_wallet::wallet::tx_builder::AddUtxoError;
use bdk_wallet::wallet::NewOrLoadError;
use bdk_wallet::wallet::{NewError, NewOrLoadError};
use bdk_wallet::KeychainKind;
use bitcoin_internals::hex::display::DisplayHex;
@ -33,7 +33,7 @@ use std::convert::TryInto;
// ------------------------------------------------------------------------
#[derive(Debug, thiserror::Error)]
pub enum AddressError {
pub enum AddressParseError {
#[error("base58 address encoding error")]
Base58,
@ -46,25 +46,24 @@ pub enum AddressError {
#[error("witness program error: {error_message}")]
WitnessProgram { error_message: String },
#[error("an uncompressed pubkey was used where it is not allowed")]
UncompressedPubkey,
#[error("tried to parse an unknown hrp")]
UnknownHrp,
#[error("script size exceed 520 bytes")]
ExcessiveScriptSize,
#[error("legacy address base58 string")]
LegacyAddressTooLong,
#[error("script is not p2pkh, p2sh, or witness program")]
UnrecognizedScript,
#[error("legacy address base58 data")]
InvalidBase58PayloadLength,
#[error("address {address} is not valid on {required}")]
NetworkValidation {
required: Network,
found: Network,
address: String,
},
#[error("segwit address bech32 string")]
InvalidLegacyPrefix,
// This is required because the bdk::bitcoin::address::Error is non-exhaustive
#[error("other address error")]
OtherAddressErr,
#[error("validation error")]
NetworkValidation,
// This error is required because the bdk::bitcoin::address::ParseError is non-exhaustive
#[error("other address parse error")]
OtherAddressParseErr,
}
#[derive(Debug, thiserror::Error)]
@ -126,8 +125,8 @@ pub enum CalculateFeeError {
#[error("missing transaction output: {out_points:?}")]
MissingTxOut { out_points: Vec<OutPoint> },
#[error("negative fee value: {fee}")]
NegativeFee { fee: i64 },
#[error("negative fee value: {amount}")]
NegativeFee { amount: String },
}
#[derive(Debug, thiserror::Error)]
@ -141,9 +140,6 @@ pub enum CreateTxError {
#[error("descriptor error: {error_message}")]
Descriptor { error_message: String },
#[error("persistence failure: {error_message}")]
Persist { error_message: String },
#[error("policy error: {error_message}")]
Policy { error_message: String },
@ -165,8 +161,8 @@ pub enum CreateTxError {
#[error("rbf sequence: {rbf}, csv sequence: {csv}")]
RbfSequenceCsv { rbf: String, csv: String },
#[error("fee too low: {required} sat required")]
FeeTooLow { required: u64 },
#[error("fee too low: required {required}")]
FeeTooLow { required: String },
#[error("fee rate too low: {required}")]
FeeRateTooLow { required: String },
@ -242,6 +238,9 @@ pub enum DescriptorError {
#[error("hex decoding error: {error_message}")]
Hex { error_message: String },
#[error("external and internal descriptors are the same")]
ExternalAndInternalAreTheSame,
}
#[derive(Debug, thiserror::Error)]
@ -375,6 +374,22 @@ pub enum FeeRateError {
ArithmeticOverflow,
}
#[derive(Debug, thiserror::Error)]
pub enum FromScriptError {
#[error("script is not a p2pkh, p2sh or witness program")]
UnrecognizedScript,
#[error("witness program error: {error_message}")]
WitnessProgram { error_message: String },
#[error("witness version construction error: {error_message}")]
WitnessVersion { error_message: String },
// This error is required because the bdk::bitcoin::address::FromScriptError is non-exhaustive
#[error("other from script error")]
OtherFromScriptErr,
}
#[derive(Debug, thiserror::Error)]
pub enum InspectError {
#[error("the request has already been consumed")]
@ -383,30 +398,21 @@ pub enum InspectError {
#[derive(Debug, thiserror::Error)]
pub enum ParseAmountError {
#[error("amount is negative")]
Negative,
#[error("amount out of range")]
OutOfRange,
#[error("amount is too large")]
TooBig,
#[error("amount is too precise")]
#[error("amount has a too high precision")]
TooPrecise,
#[error("invalid amount format")]
InvalidFormat,
#[error("the input has too few digits")]
MissingDigits,
#[error("input is too large")]
#[error("the input is too large")]
InputTooLarge,
#[error("invalid character: {error_message}")]
InvalidCharacter { error_message: String },
#[error("unknown denomination: {error_message}")]
UnknownDenomination { error_message: String },
#[error("possibly confusing denomination: {error_message}")]
PossiblyConfusingDenomination { error_message: String },
// Has to handle non-exhaustive
#[error("unknown parse amount error")]
OtherParseAmountErr,
@ -566,8 +572,14 @@ pub enum SignerError {
#[error("invalid sighash type provided")]
InvalidSighash,
#[error("error with sighash computation: {error_message}")]
SighashError { error_message: String },
#[error("error while computing the hash to sign a P2WPKH input: {error_message}")]
SighashP2wpkh { error_message: String },
#[error("error while computing the hash to sign a taproot input: {error_message}")]
SighashTaproot { error_message: String },
#[error("Error while computing the hash, out of bounds access on the transaction inputs: {error_message}")]
TxInputsIndexError { error_message: String },
#[error("miniscript psbt error: {error_message}")]
MiniscriptPsbt { error_message: String },
@ -578,8 +590,8 @@ pub enum SignerError {
#[derive(Debug, thiserror::Error)]
pub enum SqliteError {
// This error is renamed from Network to InvalidNetwork to avoid conflict with the Network enum
// in uniffi.
// NOTE: This error is renamed from Network to InvalidNetwork to avoid conflict with the Network
// enum in uniffi.
#[error("invalid network, cannot change the one already stored in the database")]
InvalidNetwork { expected: Network, given: Network },
@ -618,24 +630,14 @@ pub enum TxidParseError {
InvalidTxid { txid: String },
}
// This error combines the Rust bdk::wallet::NewOrLoadError and bdk_wallet::rusqlite::Error
// This error combines the Rust bdk_wallet::wallet::NewError and bdk_wallet::wallet::NewOrLoadError
#[derive(Debug, thiserror::Error)]
pub enum WalletCreationError {
#[error("io error trying to read file: {error_message}")]
Io { error_message: String },
#[error("file has invalid magic bytes: expected={expected:?} got={got:?}")]
InvalidMagicBytes { got: Vec<u8>, expected: Vec<u8> },
#[error("error with descriptor")]
Descriptor,
#[error("failed to either write to or load from persistence, {error_message}")]
Persist { error_message: String },
#[error("wallet is not initialized, persistence backend is empty")]
NotInitialized,
// From NewError and NewOrLoadError
#[error("error with descriptor: {error_message}")]
Descriptor { error_message: String },
// From NewOrLoadError
#[error("loaded genesis hash '{got}' does not match the expected one '{expected}'")]
LoadedGenesisDoesNotMatch { expected: String, got: String },
@ -647,41 +649,12 @@ pub enum WalletCreationError {
#[error("loaded descriptor '{got}' does not match what was provided '{keychain:?}'")]
LoadedDescriptorDoesNotMatch { got: String, keychain: KeychainKind },
#[error("error with sqlite persistence: {error_message}")]
Sqlite { error_message: String },
}
// ------------------------------------------------------------------------
// error conversions
// ------------------------------------------------------------------------
impl From<BdkAddressError> for AddressError {
fn from(error: BdkAddressError) -> Self {
match error {
BdkAddressError::WitnessVersion(error_message) => AddressError::WitnessVersion {
error_message: error_message.to_string(),
},
BdkAddressError::WitnessProgram(e) => AddressError::WitnessProgram {
error_message: e.to_string(),
},
BdkAddressError::UncompressedPubkey => AddressError::UncompressedPubkey,
BdkAddressError::ExcessiveScriptSize => AddressError::ExcessiveScriptSize,
BdkAddressError::UnrecognizedScript => AddressError::UnrecognizedScript,
BdkAddressError::NetworkValidation {
required,
found,
address,
} => AddressError::NetworkValidation {
required,
found,
address: format!("{:?}", address),
},
_ => AddressError::OtherAddressErr,
}
}
}
impl From<BdkElectrumError> for ElectrumError {
fn from(error: BdkElectrumError) -> Self {
match error {
@ -727,18 +700,25 @@ impl From<BdkElectrumError> for ElectrumError {
}
}
impl From<ParseError> for AddressError {
fn from(error: ParseError) -> Self {
impl From<BdkParseError> for AddressParseError {
fn from(error: BdkParseError) -> Self {
match error {
ParseError::Base58(_) => AddressError::Base58,
ParseError::Bech32(_) => AddressError::Bech32,
ParseError::WitnessVersion(e) => AddressError::WitnessVersion {
BdkParseError::Base58(_) => AddressParseError::Base58,
BdkParseError::Bech32(_) => AddressParseError::Bech32,
BdkParseError::WitnessVersion(e) => AddressParseError::WitnessVersion {
error_message: e.to_string(),
},
ParseError::WitnessProgram(e) => AddressError::WitnessProgram {
BdkParseError::WitnessProgram(e) => AddressParseError::WitnessProgram {
error_message: e.to_string(),
},
_ => AddressError::OtherAddressErr,
ParseError::UnknownHrp(_) => AddressParseError::UnknownHrp,
ParseError::LegacyAddressTooLong(_) => AddressParseError::LegacyAddressTooLong,
ParseError::InvalidBase58PayloadLength(_) => {
AddressParseError::InvalidBase58PayloadLength
}
ParseError::InvalidLegacyPrefix(_) => AddressParseError::InvalidLegacyPrefix,
ParseError::NetworkValidation(_) => AddressParseError::NetworkValidation,
_ => AddressParseError::OtherAddressParseErr,
}
}
}
@ -803,7 +783,9 @@ impl From<BdkCalculateFeeError> for CalculateFeeError {
BdkCalculateFeeError::MissingTxOut(out_points) => CalculateFeeError::MissingTxOut {
out_points: out_points.iter().map(|op| op.into()).collect(),
},
BdkCalculateFeeError::NegativeFee(fee) => CalculateFeeError::NegativeFee { fee },
BdkCalculateFeeError::NegativeFee(signed_amount) => CalculateFeeError::NegativeFee {
amount: signed_amount.to_string(),
},
}
}
}
@ -822,9 +804,9 @@ impl From<BdkCreateTxError> for CreateTxError {
BdkCreateTxError::Descriptor(e) => CreateTxError::Descriptor {
error_message: e.to_string(),
},
BdkCreateTxError::Persist(e) => CreateTxError::Persist {
error_message: e.to_string(),
},
// BdkCreateTxError::Persist(e) => CreateTxError::Persist {
// error_message: e.to_string(),
// },
BdkCreateTxError::Policy(e) => CreateTxError::Policy {
error_message: e.to_string(),
},
@ -847,7 +829,9 @@ impl From<BdkCreateTxError> for CreateTxError {
rbf: rbf.to_string(),
csv: csv.to_string(),
},
BdkCreateTxError::FeeTooLow { required } => CreateTxError::FeeTooLow { required },
BdkCreateTxError::FeeTooLow { required } => CreateTxError::FeeTooLow {
required: required.to_string(),
},
BdkCreateTxError::FeeRateTooLow { required } => CreateTxError::FeeRateTooLow {
required: required.to_string(),
},
@ -855,13 +839,13 @@ impl From<BdkCreateTxError> for CreateTxError {
BdkCreateTxError::OutputBelowDustLimit(index) => CreateTxError::OutputBelowDustLimit {
index: index as u64,
},
BdkCreateTxError::ChangePolicyDescriptor => CreateTxError::ChangePolicyDescriptor,
// BdkCreateTxError::ChangePolicyDescriptor => CreateTxError::ChangePolicyDescriptor,
BdkCreateTxError::CoinSelection(e) => CreateTxError::CoinSelection {
error_message: e.to_string(),
},
BdkCreateTxError::InsufficientFunds { needed, available } => {
CreateTxError::InsufficientFunds { needed, available }
}
// BdkCreateTxError::InsufficientFunds { needed, available } => {
// CreateTxError::InsufficientFunds { needed, available }
// }
BdkCreateTxError::NoRecipients => CreateTxError::NoRecipients,
BdkCreateTxError::Psbt(e) => CreateTxError::Psbt {
error_message: e.to_string(),
@ -949,6 +933,9 @@ impl From<BdkDescriptorError> for DescriptorError {
BdkDescriptorError::Hex(e) => DescriptorError::Hex {
error_message: e.to_string(),
},
BdkDescriptorError::ExternalAndInternalAreTheSame => {
DescriptorError::ExternalAndInternalAreTheSame
}
}
}
}
@ -1061,23 +1048,31 @@ impl From<BdkExtractTxError> for ExtractTxError {
}
}
impl From<BdkFromScriptError> for FromScriptError {
fn from(error: BdkFromScriptError) -> Self {
match error {
BdkFromScriptError::UnrecognizedScript => FromScriptError::UnrecognizedScript,
BdkFromScriptError::WitnessProgram(e) => FromScriptError::WitnessProgram {
error_message: e.to_string(),
},
BdkFromScriptError::WitnessVersion(e) => FromScriptError::WitnessVersion {
error_message: e.to_string(),
},
_ => FromScriptError::OtherFromScriptErr,
}
}
}
impl From<BdkParseAmountError> for ParseAmountError {
fn from(error: BdkParseAmountError) -> Self {
match error {
BdkParseAmountError::Negative => ParseAmountError::Negative,
BdkParseAmountError::TooBig => ParseAmountError::TooBig,
BdkParseAmountError::InvalidFormat => ParseAmountError::InvalidFormat,
BdkParseAmountError::TooPrecise => ParseAmountError::TooPrecise,
BdkParseAmountError::InputTooLarge => ParseAmountError::InputTooLarge,
BdkParseAmountError::OutOfRange(_) => ParseAmountError::OutOfRange,
BdkParseAmountError::TooPrecise(_) => ParseAmountError::TooPrecise,
BdkParseAmountError::MissingDigits(_) => ParseAmountError::MissingDigits,
BdkParseAmountError::InputTooLarge(_) => ParseAmountError::InputTooLarge,
BdkParseAmountError::InvalidCharacter(c) => ParseAmountError::InvalidCharacter {
error_message: c.to_string(),
},
BdkParseAmountError::UnknownDenomination(s) => {
ParseAmountError::UnknownDenomination { error_message: s }
}
BdkParseAmountError::PossiblyConfusingDenomination(s) => {
ParseAmountError::PossiblyConfusingDenomination { error_message: s }
}
_ => ParseAmountError::OtherParseAmountErr,
}
}
@ -1189,11 +1184,17 @@ impl From<BdkSignerError> for SignerError {
BdkSignerError::MissingHdKeypath => SignerError::MissingHdKeypath,
BdkSignerError::NonStandardSighash => SignerError::NonStandardSighash,
BdkSignerError::InvalidSighash => SignerError::InvalidSighash,
BdkSignerError::SighashError(e) => SignerError::SighashError {
BdkSignerError::SighashP2wpkh(e) => SignerError::SighashP2wpkh {
error_message: e.to_string(),
},
BdkSignerError::SighashTaproot(e) => SignerError::SighashTaproot {
error_message: e.to_string(),
},
BdkSignerError::TxInputsIndexError(e) => SignerError::TxInputsIndexError {
error_message: e.to_string(),
},
BdkSignerError::MiniscriptPsbt(e) => SignerError::MiniscriptPsbt {
error_message: format!("{:?}", e),
error_message: e.to_string(),
},
BdkSignerError::External(e) => SignerError::External { error_message: e },
}
@ -1223,14 +1224,6 @@ impl From<BdkEncodeError> for TransactionError {
}
}
impl From<BdkRusqliteError> for WalletCreationError {
fn from(error: BdkRusqliteError) -> Self {
WalletCreationError::Sqlite {
error_message: error.to_string(),
}
}
}
impl From<BdkSqliteError> for SqliteError {
fn from(error: BdkSqliteError) -> Self {
match error {
@ -1244,14 +1237,28 @@ impl From<BdkSqliteError> for SqliteError {
}
}
impl From<bdk_sqlite::rusqlite::Error> for SqliteError {
fn from(error: bdk_sqlite::rusqlite::Error) -> Self {
SqliteError::Sqlite {
rusqlite_error: error.to_string(),
}
}
}
impl From<NewError> for WalletCreationError {
fn from(error: NewError) -> Self {
WalletCreationError::Descriptor {
error_message: error.to_string(),
}
}
}
impl From<NewOrLoadError> for WalletCreationError {
fn from(error: NewOrLoadError) -> Self {
match error {
NewOrLoadError::Descriptor(_) => WalletCreationError::Descriptor,
NewOrLoadError::Persist(e) => WalletCreationError::Persist {
NewOrLoadError::Descriptor(e) => WalletCreationError::Descriptor {
error_message: e.to_string(),
},
NewOrLoadError::NotInitialized => WalletCreationError::NotInitialized,
NewOrLoadError::LoadedGenesisDoesNotMatch { expected, got } => {
WalletCreationError::LoadedGenesisDoesNotMatch {
expected: expected.to_string(),
@ -1278,61 +1285,11 @@ impl From<NewOrLoadError> for WalletCreationError {
#[cfg(test)]
mod test {
use crate::error::{
AddressError, Bip32Error, Bip39Error, CannotConnectError, CreateTxError, DescriptorError,
DescriptorKeyError, ElectrumError, EsploraError, ExtractTxError, FeeRateError,
InspectError, ParseAmountError, PersistenceError, PsbtError, PsbtParseError,
TransactionError, TxidParseError, WalletCreationError,
Bip32Error, Bip39Error, CannotConnectError, DescriptorError, DescriptorKeyError,
ElectrumError, EsploraError, ExtractTxError, FeeRateError, InspectError, PersistenceError,
PsbtError, PsbtParseError, TransactionError, TxidParseError,
};
use crate::CalculateFeeError;
use crate::OutPoint;
use crate::SignerError;
use bdk_wallet::bitcoin::Network;
use bdk_wallet::KeychainKind;
#[test]
fn test_error_address() {
let cases = vec![
(AddressError::Base58, "base58 address encoding error"),
(AddressError::Bech32, "bech32 address encoding error"),
(
AddressError::WitnessVersion {
error_message: "version error".to_string(),
},
"witness version conversion/parsing error: version error",
),
(
AddressError::WitnessProgram {
error_message: "program error".to_string(),
},
"witness program error: program error",
),
(
AddressError::UncompressedPubkey,
"an uncompressed pubkey was used where it is not allowed",
),
(
AddressError::ExcessiveScriptSize,
"script size exceed 520 bytes",
),
(
AddressError::UnrecognizedScript,
"script is not p2pkh, p2sh, or witness program",
),
(
AddressError::NetworkValidation {
required: Network::Bitcoin,
found: Network::Testnet,
address: "1BitcoinEaterAddressDontSendf59kuE".to_string(),
},
"address 1BitcoinEaterAddressDontSendf59kuE is not valid on bitcoin",
),
(AddressError::OtherAddressErr, "other address error"),
];
for (error, expected_message) in cases {
assert_eq!(error.to_string(), expected_message);
}
}
#[test]
fn test_error_bip32() {
@ -1427,42 +1384,6 @@ mod test {
}
}
#[test]
fn test_error_calculate_fee() {
let out_points: Vec<OutPoint> = vec![
OutPoint {
txid: "0000000000000000000000000000000000000000000000000000000000000001"
.to_string(),
vout: 0,
},
OutPoint {
txid: "0000000000000000000000000000000000000000000000000000000000000002"
.to_string(),
vout: 1,
},
];
let cases = vec![
(
CalculateFeeError::MissingTxOut {
out_points: out_points.clone(),
},
format!(
"missing transaction output: [{:?}, {:?}]",
out_points[0], out_points[1]
),
),
(
CalculateFeeError::NegativeFee { fee: -100 },
"negative fee value: -100".to_string(),
),
];
for (error, expected_message) in cases {
assert_eq!(error.to_string(), expected_message);
}
}
#[test]
fn test_error_cannot_connect() {
let error = CannotConnectError::Include { height: 42 };
@ -1470,126 +1391,6 @@ mod test {
assert_eq!(format!("{}", error), "cannot include height: 42");
}
#[test]
fn test_error_create_tx() {
let cases = vec![
(
CreateTxError::Descriptor {
error_message: "Descriptor failure".to_string(),
},
"descriptor error: Descriptor failure",
),
(
CreateTxError::Persist {
error_message: "Persistence error".to_string(),
},
"persistence failure: Persistence error",
),
(
CreateTxError::Policy {
error_message: "Policy violation".to_string(),
},
"policy error: Policy violation",
),
(
CreateTxError::SpendingPolicyRequired {
kind: "multisig".to_string(),
},
"spending policy required for multisig",
),
(CreateTxError::Version0, "unsupported version 0"),
(CreateTxError::Version1Csv, "unsupported version 1 with csv"),
(
CreateTxError::LockTime {
requested: "today".to_string(),
required: "tomorrow".to_string(),
},
"lock time conflict: requested today, but required tomorrow",
),
(
CreateTxError::RbfSequence,
"transaction requires rbf sequence number",
),
(
CreateTxError::RbfSequenceCsv {
rbf: "123".to_string(),
csv: "456".to_string(),
},
"rbf sequence: 123, csv sequence: 456",
),
(
CreateTxError::FeeTooLow { required: 1000 },
"fee too low: 1000 sat required",
),
(
CreateTxError::FeeRateTooLow {
required: "5 sat/vB".to_string(),
},
"fee rate too low: 5 sat/vB",
),
(
CreateTxError::NoUtxosSelected,
"no utxos selected for the transaction",
),
(
CreateTxError::OutputBelowDustLimit { index: 2 },
"output value below dust limit at index 2",
),
(
CreateTxError::ChangePolicyDescriptor,
"change policy descriptor error",
),
(
CreateTxError::CoinSelection {
error_message: "No suitable outputs".to_string(),
},
"coin selection failed: No suitable outputs",
),
(
CreateTxError::InsufficientFunds {
needed: 5000,
available: 3000,
},
"insufficient funds: needed 5000 sat, available 3000 sat",
),
(CreateTxError::NoRecipients, "transaction has no recipients"),
(
CreateTxError::Psbt {
error_message: "PSBT creation failed".to_string(),
},
"psbt creation error: PSBT creation failed",
),
(
CreateTxError::MissingKeyOrigin {
key: "xpub...".to_string(),
},
"missing key origin for: xpub...",
),
(
CreateTxError::UnknownUtxo {
outpoint: "outpoint123".to_string(),
},
"reference to an unknown utxo: outpoint123",
),
(
CreateTxError::MissingNonWitnessUtxo {
outpoint: "outpoint456".to_string(),
},
"missing non-witness utxo for outpoint: outpoint456",
),
(
CreateTxError::MiniscriptPsbt {
error_message: "Miniscript error".to_string(),
},
"miniscript psbt error: Miniscript error",
),
];
for (error, expected_message) in cases {
assert_eq!(error.to_string(), expected_message);
}
}
#[test]
fn test_error_descriptor() {
let cases = vec![
@ -1883,43 +1684,6 @@ mod test {
}
}
#[test]
fn test_error_parse_amount() {
let cases = vec![
(ParseAmountError::Negative, "amount is negative"),
(ParseAmountError::TooBig, "amount is too large"),
(ParseAmountError::TooPrecise, "amount is too precise"),
(ParseAmountError::InvalidFormat, "invalid amount format"),
(ParseAmountError::InputTooLarge, "input is too large"),
(
ParseAmountError::InvalidCharacter {
error_message: "invalid char".to_string(),
},
"invalid character: invalid char",
),
(
ParseAmountError::UnknownDenomination {
error_message: "unknown denom".to_string(),
},
"unknown denomination: unknown denom",
),
(
ParseAmountError::PossiblyConfusingDenomination {
error_message: "confusing denom".to_string(),
},
"possibly confusing denomination: confusing denom",
),
(
ParseAmountError::OtherParseAmountErr,
"unknown parse amount error",
),
];
for (error, expected_message) in cases {
assert_eq!(error.to_string(), expected_message);
}
}
#[test]
fn test_persistence_error() {
let cases = vec![
@ -2134,12 +1898,6 @@ mod test {
"non-standard sighash type used",
),
(SignerError::InvalidSighash, "invalid sighash type provided"),
(
SignerError::SighashError {
error_message: "dummy error".into(),
},
"error with sighash computation: dummy error",
),
(
SignerError::MiniscriptPsbt {
error_message: "psbt issue".into(),
@ -2204,62 +1962,4 @@ mod test {
assert_eq!(error.to_string(), expected_message);
}
}
#[test]
fn test_error_wallet_creation() {
let errors = vec![
(
WalletCreationError::Io {
error_message: "io error".to_string(),
},
"io error trying to read file: io error".to_string(),
),
(
WalletCreationError::InvalidMagicBytes {
got: vec![1, 2, 3, 4],
expected: vec![4, 3, 2, 1],
},
"file has invalid magic bytes: expected=[4, 3, 2, 1] got=[1, 2, 3, 4]".to_string(),
),
(
WalletCreationError::Descriptor,
"error with descriptor".to_string(),
),
(
WalletCreationError::Persist {
error_message: "persistence error".to_string(),
},
"failed to either write to or load from persistence, persistence error".to_string(),
),
(
WalletCreationError::NotInitialized,
"wallet is not initialized, persistence backend is empty".to_string(),
),
(
WalletCreationError::LoadedGenesisDoesNotMatch {
expected: "abc".to_string(),
got: "def".to_string(),
},
"loaded genesis hash 'def' does not match the expected one 'abc'".to_string(),
),
(
WalletCreationError::LoadedNetworkDoesNotMatch {
expected: Network::Bitcoin,
got: Some(Network::Testnet),
},
"loaded network type is not bitcoin, got Some(Testnet)".to_string(),
),
(
WalletCreationError::LoadedDescriptorDoesNotMatch {
got: "def".to_string(),
keychain: KeychainKind::External,
},
"loaded descriptor 'def' does not match what was provided 'External'".to_string(),
),
];
for (error, expected) in errors {
assert_eq!(error.to_string(), expected);
}
}
}

View File

@ -4,6 +4,7 @@ mod electrum;
mod error;
mod esplora;
mod keys;
mod store;
mod types;
mod wallet;
@ -18,7 +19,7 @@ use crate::bitcoin::TxIn;
use crate::bitcoin::TxOut;
use crate::descriptor::Descriptor;
use crate::electrum::ElectrumClient;
use crate::error::AddressError;
use crate::error::AddressParseError;
use crate::error::Bip32Error;
use crate::error::Bip39Error;
use crate::error::CalculateFeeError;
@ -30,6 +31,7 @@ use crate::error::ElectrumError;
use crate::error::EsploraError;
use crate::error::ExtractTxError;
use crate::error::FeeRateError;
use crate::error::FromScriptError;
use crate::error::InspectError;
use crate::error::ParseAmountError;
use crate::error::PersistenceError;
@ -45,10 +47,12 @@ use crate::keys::DerivationPath;
use crate::keys::DescriptorPublicKey;
use crate::keys::DescriptorSecretKey;
use crate::keys::Mnemonic;
use crate::store::SqliteStore;
use crate::types::AddressInfo;
use crate::types::Balance;
use crate::types::CanonicalTx;
use crate::types::ChainPosition;
use crate::types::ChangeSet;
use crate::types::FullScanRequest;
use crate::types::FullScanScriptInspector;
use crate::types::LocalOutput;

39
bdk-ffi/src/store.rs Normal file
View File

@ -0,0 +1,39 @@
use crate::error::SqliteError;
use crate::types::ChangeSet;
use bdk_sqlite::rusqlite::Connection;
use bdk_sqlite::{Store as BdkSqliteStore, Store};
use bdk_wallet::chain::ConfirmationTimeHeightAnchor;
use bdk_wallet::KeychainKind;
use std::sync::{Mutex, MutexGuard};
pub struct SqliteStore {
inner_mutex: Mutex<BdkSqliteStore<KeychainKind, ConfirmationTimeHeightAnchor>>,
}
impl SqliteStore {
pub fn new(path: String) -> Result<Self, SqliteError> {
let connection = Connection::open(path)?;
let db = Store::new(connection)?;
Ok(Self {
inner_mutex: Mutex::new(db),
})
}
pub(crate) fn get_store(
&self,
) -> MutexGuard<BdkSqliteStore<KeychainKind, ConfirmationTimeHeightAnchor>> {
self.inner_mutex.lock().expect("sqlite store")
}
// pub fn read(&self) -> Result<Option<CombinedChangeSet<KeychainKind, ConfirmationTimeHeightAnchor>, Error> {
// self.0.read().map_err(SqliteError::from)
// }
pub fn write(&self, changeset: &ChangeSet) -> Result<(), SqliteError> {
self.get_store()
.write(&changeset.0)
.map_err(SqliteError::from)
}
}

View File

@ -13,6 +13,7 @@ use bdk_wallet::wallet::Balance as BdkBalance;
use bdk_wallet::KeychainKind;
use bdk_wallet::LocalOutput as BdkLocalOutput;
use bdk_electrum::bdk_chain::CombinedChangeSet;
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone, PartialEq, Eq)]
@ -86,6 +87,14 @@ impl From<BdkBalance> for Balance {
}
}
pub struct ChangeSet(pub(crate) CombinedChangeSet<KeychainKind, ConfirmationTimeHeightAnchor>);
impl From<CombinedChangeSet<KeychainKind, ConfirmationTimeHeightAnchor>> for ChangeSet {
fn from(change_set: CombinedChangeSet<KeychainKind, ConfirmationTimeHeightAnchor>) -> Self {
ChangeSet(change_set)
}
}
pub struct LocalOutput {
pub outpoint: OutPoint,
pub txout: TxOut,

View File

@ -2,20 +2,20 @@ use crate::bitcoin::Amount;
use crate::bitcoin::{FeeRate, OutPoint, Psbt, Script, Transaction};
use crate::descriptor::Descriptor;
use crate::error::{
CalculateFeeError, CannotConnectError, CreateTxError, DescriptorError, PersistenceError,
SignerError, TxidParseError, WalletCreationError,
CalculateFeeError, CannotConnectError, CreateTxError, SignerError, TxidParseError,
WalletCreationError,
};
use crate::types::{
AddressInfo, Balance, CanonicalTx, FullScanRequest, LocalOutput, ScriptAmount, SyncRequest,
AddressInfo, Balance, CanonicalTx, ChangeSet, FullScanRequest, LocalOutput, ScriptAmount,
SyncRequest,
};
use bdk_sqlite::rusqlite::Connection;
use bdk_sqlite::Store;
use bdk_wallet::bitcoin::amount::Amount as BdkAmount;
use bdk_wallet::bitcoin::blockdata::script::ScriptBuf as BdkScriptBuf;
use bdk_wallet::bitcoin::Network;
use bdk_wallet::bitcoin::Psbt as BdkPsbt;
use bdk_wallet::bitcoin::{OutPoint as BdkOutPoint, Sequence, Txid};
// use bdk_wallet::chain::{CombinedChangeSet, ConfirmationTimeHeightAnchor};
use bdk_wallet::wallet::tx_builder::ChangeSpendPolicy;
use bdk_wallet::wallet::Update as BdkUpdate;
use bdk_wallet::Wallet as BdkWallet;
@ -32,53 +32,37 @@ pub struct Wallet {
impl Wallet {
pub fn new(
descriptor: Arc<Descriptor>,
change_descriptor: Option<Arc<Descriptor>>,
persistence_backend_path: String,
change_descriptor: Arc<Descriptor>,
network: Network,
) -> Result<Self, WalletCreationError> {
let descriptor = descriptor.to_string_with_secret();
let change_descriptor = change_descriptor.map(|d| d.to_string_with_secret());
let connection = Connection::open(persistence_backend_path)?;
let db = Store::new(connection)?;
let wallet: BdkWallet =
BdkWallet::new_or_load(&descriptor, change_descriptor.as_ref(), db, network)?;
let change_descriptor = change_descriptor.to_string_with_secret();
let wallet: BdkWallet = BdkWallet::new(&descriptor, &change_descriptor, network)?;
Ok(Wallet {
inner_mutex: Mutex::new(wallet),
})
}
pub fn new_no_persist(
descriptor: Arc<Descriptor>,
change_descriptor: Option<Arc<Descriptor>>,
network: Network,
) -> Result<Self, DescriptorError> {
let descriptor = descriptor.to_string_with_secret();
let change_descriptor = change_descriptor.map(|d| d.to_string_with_secret());
let wallet: BdkWallet =
BdkWallet::new_no_persist(&descriptor, change_descriptor.as_ref(), network)?;
Ok(Wallet {
inner_mutex: Mutex::new(wallet),
})
}
// pub fn new_or_load(
// descriptor: Arc<Descriptor>,
// change_descriptor: Option<Arc<Descriptor>>,
// change_set: Option<CombinedChangeSet<KeychainKind, ConfirmationTimeHeightAnchor>>,
// network: Network,
// ) -> Result<Self, WalletCreationError> {
// let descriptor = descriptor.to_string_with_secret();
// let change_descriptor = change_descriptor.to_string_with_secret();
// let wallet: BdkWallet = BdkWallet::new_or_load(&descriptor, &change_descriptor, network)?;
//
// Ok(Wallet { inner_mutex: Mutex::new(wallet) })
// }
pub(crate) fn get_wallet(&self) -> MutexGuard<BdkWallet> {
self.inner_mutex.lock().expect("wallet")
}
pub fn reveal_next_address(
&self,
keychain_kind: KeychainKind,
) -> Result<AddressInfo, PersistenceError> {
self.get_wallet()
.reveal_next_address(keychain_kind)
.map(|address_info| address_info.into())
.map_err(|e| PersistenceError::Write {
error_message: e.to_string(),
})
pub fn reveal_next_address(&self, keychain_kind: KeychainKind) -> AddressInfo {
self.get_wallet().reveal_next_address(keychain_kind).into()
}
pub fn apply_update(&self, update: Arc<Update>) -> Result<(), CannotConnectError> {
@ -87,20 +71,12 @@ impl Wallet {
.map_err(CannotConnectError::from)
}
pub fn commit(&self) -> Result<bool, PersistenceError> {
self.get_wallet()
.commit()
.map_err(|e| PersistenceError::Write {
error_message: e.to_string(),
})
}
pub fn network(&self) -> Network {
self.get_wallet().network()
}
pub fn get_balance(&self) -> Balance {
let bdk_balance = self.get_wallet().get_balance();
pub fn balance(&self) -> Balance {
let bdk_balance = self.get_wallet().balance();
Balance::from(bdk_balance)
}
@ -140,9 +116,11 @@ impl Wallet {
Ok(self.get_wallet().get_tx(txid).map(|tx| tx.into()))
}
pub fn calculate_fee(&self, tx: &Transaction) -> Result<u64, CalculateFeeError> {
pub fn calculate_fee(&self, tx: &Transaction) -> Result<Arc<Amount>, CalculateFeeError> {
self.get_wallet()
.calculate_fee(&tx.into())
.map(Amount::from)
.map(Arc::new)
.map_err(|e| e.into())
}
@ -170,6 +148,12 @@ impl Wallet {
let request = self.get_wallet().start_sync_with_revealed_spks();
Arc::new(SyncRequest(Mutex::new(Some(request))))
}
pub fn take_staged(&self) -> Option<Arc<ChangeSet>> {
self.get_wallet()
.take_staged()
.map(|change_set| Arc::new(change_set.into()))
}
}
pub struct SentAndReceivedValues {