From 3e13678bc74bc20f65a538768c38b57e52b213c3 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 20 Jul 2022 10:41:30 -0400 Subject: [PATCH 01/61] Add wallet utxos subcommand --- src/subcommand/wallet.rs | 31 +++++++++++++++++++++++++++++++ src/subcommand/wallet/fund.rs | 26 +------------------------- src/subcommand/wallet/utxos.rs | 9 +++++++++ 3 files changed, 41 insertions(+), 25 deletions(-) create mode 100644 src/subcommand/wallet/utxos.rs diff --git a/src/subcommand/wallet.rs b/src/subcommand/wallet.rs index da16cc4762..68a1c23cb0 100644 --- a/src/subcommand/wallet.rs +++ b/src/subcommand/wallet.rs @@ -2,11 +2,41 @@ use super::*; mod fund; mod init; +mod utxos; + +fn get_wallet() -> Result> { + let path = data_dir() + .ok_or_else(|| anyhow!("Failed to retrieve data dir"))? + .join("ord"); + + if !path.exists() { + return Err(anyhow!("Wallet doesn't exist.")); + } + + let entropy = fs::read(path.join("entropy"))?; + + Ok(bdk::wallet::Wallet::new( + Bip84( + (Mnemonic::from_entropy(&entropy)?, None), + KeychainKind::External, + ), + None, + Network::Signet, + SqliteDatabase::new( + path + .join("wallet.sqlite") + .to_str() + .ok_or_else(|| anyhow!("Failed to convert path to str"))? + .to_string(), + ), + )?) +} #[derive(Parser)] pub(crate) enum Wallet { Init, Fund, + Utxos, } impl Wallet { @@ -14,6 +44,7 @@ impl Wallet { match self { Self::Init => init::run(), Self::Fund => fund::run(), + Self::Utxos => utxos::run(), } } } diff --git a/src/subcommand/wallet/fund.rs b/src/subcommand/wallet/fund.rs index 1ac414f9e3..b5e28b846a 100644 --- a/src/subcommand/wallet/fund.rs +++ b/src/subcommand/wallet/fund.rs @@ -1,31 +1,7 @@ use super::*; pub(crate) fn run() -> Result { - let path = data_dir() - .ok_or_else(|| anyhow!("Failed to retrieve data dir"))? - .join("ord"); - - if !path.exists() { - return Err(anyhow!("Wallet doesn't exist.")); - } - - let entropy = fs::read(path.join("entropy"))?; - - let wallet = bdk::wallet::Wallet::new( - Bip84( - (Mnemonic::from_entropy(&entropy)?, None), - KeychainKind::External, - ), - None, - Network::Signet, - SqliteDatabase::new( - path - .join("wallet.sqlite") - .to_str() - .ok_or_else(|| anyhow!("Failed to convert path to str"))? - .to_string(), - ), - )?; + let wallet = get_wallet()?; println!("{}", wallet.get_address(LastUnused)?); diff --git a/src/subcommand/wallet/utxos.rs b/src/subcommand/wallet/utxos.rs new file mode 100644 index 0000000000..484da6e7c5 --- /dev/null +++ b/src/subcommand/wallet/utxos.rs @@ -0,0 +1,9 @@ +use super::*; + +pub(crate) fn run() -> Result { + let wallet = get_wallet()?; + + println!("{:?}", wallet.list_unspent()?); + + Ok(()) +} From ed59bd2b6875f22074fc928208e681e83dba09f1 Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 21 Jul 2022 17:19:14 -0400 Subject: [PATCH 02/61] Semi-working --- Cargo.lock | 479 +++++++++++++++++++++++++++++++-- Cargo.toml | 3 +- src/main.rs | 3 +- src/subcommand.rs | 2 +- src/subcommand/wallet.rs | 53 +++- src/subcommand/wallet/fund.rs | 6 +- src/subcommand/wallet/init.rs | 29 +- src/subcommand/wallet/utxos.rs | 6 +- tests/index.rs | 2 +- tests/info.rs | 2 +- tests/lib.rs | 34 ++- tests/nft.rs | 2 +- tests/wallet.rs | 51 +++- 13 files changed, 618 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6b6ecb07d..fde39c2ad9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -159,11 +159,17 @@ dependencies = [ "cc", "cfg-if 1.0.0", "libc", - "miniz_oxide", + "miniz_oxide 0.5.3", "object", "rustc-demangle", ] +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + [[package]] name = "base64" version = "0.13.0" @@ -190,6 +196,7 @@ dependencies = [ "bdk-macros", "bip39", "bitcoin", + "bitcoincore-rpc", "electrum-client", "js-sys", "log", @@ -295,6 +302,24 @@ dependencies = [ "serde_json", ] +[[package]] +name = "bitcoind" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0831b9721892ce845a6acadd111311bee84f9e1cc0c5017b8213ec4437ccdfe2" +dependencies = [ + "bitcoin_hashes 0.10.0", + "bitcoincore-rpc", + "filetime", + "flate2", + "home", + "log", + "tar", + "tempfile", + "ureq 1.5.5", + "which", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -337,6 +362,27 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e" +[[package]] +name = "bzip2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cast" version = "0.3.0" @@ -370,10 +416,16 @@ dependencies = [ "libc", "num-integer", "num-traits", - "time", + "time 0.1.44", "winapi", ] +[[package]] +name = "chunked_transfer" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" + [[package]] name = "clap" version = "2.34.0" @@ -439,12 +491,45 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "const_fn" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" + [[package]] name = "convert_case" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "cookie" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" +dependencies = [ + "percent-encoding 2.1.0", + "time 0.2.27", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3" +dependencies = [ + "cookie", + "idna 0.2.1", + "log", + "publicsuffix", + "serde", + "serde_json", + "time 0.2.27", + "url 2.2.2", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -579,7 +664,7 @@ version = "3.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b37feaa84e6861e00a1f5e5aa8da3ee56d605c9992d33e082786754828e20865" dependencies = [ - "nix", + "nix 0.24.2", "winapi", ] @@ -601,7 +686,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version", + "rustc_version 0.4.0", "syn", ] @@ -625,12 +710,33 @@ dependencies = [ "winapi", ] +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + [[package]] name = "either" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" +[[package]] +name = "electrsd" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad65605e022b44ab8c1e489547311bb48b5c605a0aea9ba908e12cae2880111" +dependencies = [ + "bitcoin_hashes 0.10.0", + "bitcoind", + "electrum-client", + "log", + "nix 0.22.3", + "ureq 2.5.0", + "zip", +] + [[package]] name = "electrum-client" version = "0.10.1" @@ -639,12 +745,12 @@ checksum = "8ef9b40020912229e947b45d91f9ff96b10d543e0eddd75ff41b9eda24d9c051" dependencies = [ "bitcoin", "log", - "rustls", + "rustls 0.20.6", "serde", "serde_json", "socks", - "webpki", - "webpki-roots", + "webpki 0.22.0", + "webpki-roots 0.22.4", ] [[package]] @@ -669,6 +775,15 @@ dependencies = [ "termcolor", ] +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "version_check", +] + [[package]] name = "executable-path" version = "1.0.0" @@ -712,14 +827,28 @@ dependencies = [ "instant", ] +[[package]] +name = "filetime" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "winapi", +] + [[package]] name = "flate2" -version = "1.0.24" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" dependencies = [ + "cfg-if 1.0.0", "crc32fast", - "miniz_oxide", + "libc", + "miniz_oxide 0.4.4", ] [[package]] @@ -1013,6 +1142,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "home" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" +dependencies = [ + "winapi", +] + [[package]] name = "html-escape" version = "0.2.11" @@ -1429,6 +1567,16 @@ dependencies = [ "serde", ] +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg 1.1.0", +] + [[package]] name = "miniz_oxide" version = "0.5.3" @@ -1488,6 +1636,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", + "memoffset", +] + [[package]] name = "nix" version = "0.24.2" @@ -1624,6 +1785,7 @@ dependencies = [ "ctrlc", "derive_more", "dirs", + "electrsd", "env_logger", "executable-path", "hex", @@ -1635,7 +1797,7 @@ dependencies = [ "jsonrpc-http-server", "lazy_static", "log", - "nix", + "nix 0.24.2", "qrcode-generator", "rayon", "redb", @@ -1769,7 +1931,7 @@ dependencies = [ "bitflags", "crc32fast", "deflate", - "miniz_oxide", + "miniz_oxide 0.5.3", ] [[package]] @@ -1811,6 +1973,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + [[package]] name = "proc-macro2" version = "1.0.40" @@ -1820,6 +1988,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "publicsuffix" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" +dependencies = [ + "error-chain", + "idna 0.2.1", + "lazy_static", + "regex", + "url 2.2.2", +] + [[package]] name = "qrcode-generator" version = "4.1.6" @@ -1837,6 +2018,15 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4339fc7a1021c9c1621d87f5e3505f2805c8c105420ba2f2a4df86814590c142" +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding 2.1.0", +] + [[package]] name = "quote" version = "1.0.20" @@ -2160,13 +2350,35 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.12", +] + +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64", + "log", + "ring", + "sct 0.6.1", + "webpki 0.21.4", ] [[package]] @@ -2177,8 +2389,8 @@ checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" dependencies = [ "log", "ring", - "sct", - "webpki", + "sct 0.7.0", + "webpki 0.22.0", ] [[package]] @@ -2218,6 +2430,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "sct" version = "0.7.0" @@ -2271,12 +2493,27 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" version = "1.0.139" @@ -2330,6 +2567,21 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + [[package]] name = "slab" version = "0.4.7" @@ -2406,6 +2658,64 @@ dependencies = [ "lock_api", ] +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version 0.2.3", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + [[package]] name = "strsim" version = "0.10.0" @@ -2429,6 +2739,17 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" +[[package]] +name = "tar" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tempfile" version = "3.3.0" @@ -2518,6 +2839,44 @@ dependencies = [ "winapi", ] +[[package]] +name = "time" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +dependencies = [ + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros", + "version_check", + "winapi", +] + +[[package]] +name = "time-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -2738,6 +3097,42 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "ureq" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8b063c2d59218ae09f22b53c42eaad0d53516457905f5235ca4bc9e99daa71" +dependencies = [ + "base64", + "chunked_transfer", + "cookie", + "cookie_store", + "log", + "once_cell", + "qstring", + "rustls 0.19.1", + "url 2.2.2", + "webpki 0.21.4", + "webpki-roots 0.21.1", +] + +[[package]] +name = "ureq" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97acb4c28a254fd7a4aeec976c46a7fa404eac4d7c134b30c75144846d7cb8f" +dependencies = [ + "base64", + "chunked_transfer", + "flate2", + "log", + "once_cell", + "rustls 0.20.6", + "url 2.2.2", + "webpki 0.22.0", + "webpki-roots 0.22.4", +] + [[package]] name = "url" version = "1.7.2" @@ -2894,6 +3289,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "webpki" version = "0.22.0" @@ -2904,13 +3309,22 @@ dependencies = [ "untrusted", ] +[[package]] +name = "webpki-roots" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +dependencies = [ + "webpki 0.21.4", +] + [[package]] name = "webpki-roots" version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf" dependencies = [ - "webpki", + "webpki 0.22.0", ] [[package]] @@ -2919,6 +3333,17 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" +[[package]] +name = "which" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" +dependencies = [ + "either", + "lazy_static", + "libc", +] + [[package]] name = "winapi" version = "0.3.9" @@ -3001,3 +3426,25 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] + +[[package]] +name = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +dependencies = [ + "libc", +] + +[[package]] +name = "zip" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" +dependencies = [ + "byteorder", + "bzip2", + "crc32fast", + "flate2", + "thiserror", +] diff --git a/Cargo.toml b/Cargo.toml index 3b8f5a8df1..ef8e55ce12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ autotests = false anyhow = { version = "1.0.56", features = ["backtrace"] } axum = "0.5.6" axum-server = "0.4.0" -bdk = { version = "0.20.0", features = ["keys-bip39", "sqlite"] } +bdk = { version = "0.20.0", features = ["rpc", "keys-bip39", "sqlite"] } bech32 = "0.9.0" bitcoin = "0.28.1" bitcoin_hashes = "0.10.0" @@ -39,6 +39,7 @@ tower-http = { version = "0.3.3", features = ["cors"] } [dev-dependencies] criterion = "0.3.5" +electrsd = { version = "0.19.1", features = ["electrs_0_8_10", "bitcoind_0_20_0"] } hex = "0.4.3" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" diff --git a/src/main.rs b/src/main.rs index b554232a2e..1863fe61d5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,10 +9,11 @@ use { axum::{extract, http::StatusCode, response::IntoResponse, routing::get, Json, Router}, axum_server::Handle, bdk::{ + blockchain::{rpc::Auth, ConfigurableBlockchain}, database::SqliteDatabase, keys::bip39::{Language, Mnemonic}, template::Bip84, - wallet::AddressIndex::LastUnused, + wallet::{wallet_name_from_descriptor, AddressIndex::LastUnused, SyncOptions}, KeychainKind, }, bech32::{FromBase32, ToBase32}, diff --git a/src/subcommand.rs b/src/subcommand.rs index 940c7eda42..a12e353659 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -53,7 +53,7 @@ impl Subcommand { Self::Supply => supply::run(), Self::Traits(traits) => traits.run(), Self::Verify(verify) => verify.run(), - Self::Wallet(wallet) => wallet.run(), + Self::Wallet(wallet) => wallet.run(options), } } } diff --git a/src/subcommand/wallet.rs b/src/subcommand/wallet.rs index 68a1c23cb0..5f24a05790 100644 --- a/src/subcommand/wallet.rs +++ b/src/subcommand/wallet.rs @@ -4,7 +4,11 @@ mod fund; mod init; mod utxos; -fn get_wallet() -> Result> { +use bdk::blockchain::rpc::{Auth, RpcBlockchain, RpcConfig}; +use bdk::blockchain::ConfigurableBlockchain; +use bdk::wallet::{wallet_name_from_descriptor, SyncOptions}; + +fn get_wallet(options: Options) -> Result> { let path = data_dir() .ok_or_else(|| anyhow!("Failed to retrieve data dir"))? .join("ord"); @@ -13,15 +17,15 @@ fn get_wallet() -> Result> { return Err(anyhow!("Wallet doesn't exist.")); } - let entropy = fs::read(path.join("entropy"))?; + let key = ( + Mnemonic::from_entropy(&fs::read(path.join("entropy"))?)?, + None, + ); - Ok(bdk::wallet::Wallet::new( - Bip84( - (Mnemonic::from_entropy(&entropy)?, None), - KeychainKind::External, - ), + let wallet = bdk::wallet::Wallet::new( + Bip84(key.clone(), KeychainKind::External), None, - Network::Signet, + Network::Regtest, SqliteDatabase::new( path .join("wallet.sqlite") @@ -29,7 +33,30 @@ fn get_wallet() -> Result> { .ok_or_else(|| anyhow!("Failed to convert path to str"))? .to_string(), ), - )?) + )?; + + wallet.sync( + &RpcBlockchain::from_config(&RpcConfig { + url: options + .rpc_url + .ok_or_else(|| anyhow!("This command requires `--rpc-url`"))?, + auth: options + .cookie_file + .map(|path| Auth::Cookie { file: path }) + .unwrap_or(Auth::None), + network: Network::Regtest, + wallet_name: wallet_name_from_descriptor( + Bip84(key, KeychainKind::External), + None, + Network::Regtest, + &Secp256k1::new(), + )?, + skip_blocks: None, + })?, + SyncOptions::default(), + )?; + + Ok(wallet) } #[derive(Parser)] @@ -40,11 +67,11 @@ pub(crate) enum Wallet { } impl Wallet { - pub(crate) fn run(self) -> Result { + pub(crate) fn run(self, options: Options) -> Result { match self { - Self::Init => init::run(), - Self::Fund => fund::run(), - Self::Utxos => utxos::run(), + Self::Init => init::run(options), + Self::Fund => fund::run(options), + Self::Utxos => utxos::run(options), } } } diff --git a/src/subcommand/wallet/fund.rs b/src/subcommand/wallet/fund.rs index b5e28b846a..03a935a015 100644 --- a/src/subcommand/wallet/fund.rs +++ b/src/subcommand/wallet/fund.rs @@ -1,9 +1,9 @@ use super::*; -pub(crate) fn run() -> Result { - let wallet = get_wallet()?; +pub(crate) fn run(options: Options) -> Result { + let wallet = get_wallet(options)?; - println!("{}", wallet.get_address(LastUnused)?); + println!("{}", wallet.get_address(LastUnused)?.address); Ok(()) } diff --git a/src/subcommand/wallet/init.rs b/src/subcommand/wallet/init.rs index 986cc62813..75740a89ef 100644 --- a/src/subcommand/wallet/init.rs +++ b/src/subcommand/wallet/init.rs @@ -1,6 +1,6 @@ use super::*; -pub(crate) fn run() -> Result { +pub(crate) fn run(options: Options) -> Result { let path = data_dir() .ok_or_else(|| anyhow!("Failed to retrieve data dir"))? .join("ord"); @@ -15,10 +15,10 @@ pub(crate) fn run() -> Result { fs::write(path.join("entropy"), seed.to_entropy())?; - bdk::wallet::Wallet::new( - Bip84((seed, None), KeychainKind::External), + let wallet = bdk::wallet::Wallet::new( + Bip84((seed.clone(), None), KeychainKind::External), None, - Network::Signet, + Network::Regtest, SqliteDatabase::new( path .join("wallet.sqlite") @@ -28,6 +28,27 @@ pub(crate) fn run() -> Result { ), )?; + wallet.sync( + &RpcBlockchain::from_config(&RpcConfig { + url: options + .rpc_url + .ok_or_else(|| anyhow!("This command requires `--rpc-url`"))?, + auth: options + .cookie_file + .map(|path| Auth::Cookie { file: path }) + .unwrap_or(Auth::None), + network: Network::Regtest, + wallet_name: wallet_name_from_descriptor( + Bip84((seed, None), KeychainKind::External), + None, + Network::Regtest, + &Secp256k1::new(), + )?, + skip_blocks: None, + })?, + SyncOptions::default(), + )?; + eprintln!("Wallet initialized."); Ok(()) diff --git a/src/subcommand/wallet/utxos.rs b/src/subcommand/wallet/utxos.rs index 484da6e7c5..8e022f4b0d 100644 --- a/src/subcommand/wallet/utxos.rs +++ b/src/subcommand/wallet/utxos.rs @@ -1,9 +1,9 @@ use super::*; -pub(crate) fn run() -> Result { - let wallet = get_wallet()?; +pub(crate) fn run(options: Options) -> Result { + let wallet = get_wallet(options)?; - println!("{:?}", wallet.list_unspent()?); + println!("{:?}", wallet.get_balance()?); Ok(()) } diff --git a/tests/index.rs b/tests/index.rs index 7a23a36eab..dc3739e425 100644 --- a/tests/index.rs +++ b/tests/index.rs @@ -10,7 +10,7 @@ fn incremental_indexing() -> Result { assert_eq!(output.calls, &["getblockhash", "getblock", "getblockhash"]); - let output = Test::with_tempdir(output.tempdir) + let output = Test::with_tempdir(output.tempdir)? .command("list 9068a11b8769174363376b606af9a4b8b29dd7b13d013f4b0cbbd457db3c3ce5:0") .expected_stdout("[5000000000,10000000000)\n") .block() diff --git a/tests/info.rs b/tests/info.rs index 44c108f4df..16edfaeecf 100644 --- a/tests/info.rs +++ b/tests/info.rs @@ -4,7 +4,7 @@ use super::*; fn basic() -> Result { let output = Test::new()?.command("index").block().output()?; - Test::with_tempdir(output.tempdir) + Test::with_tempdir(output.tempdir)? .command("info") .stdout_regex( r" diff --git a/tests/lib.rs b/tests/lib.rs index bdac4e089a..a7bb795852 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -6,6 +6,14 @@ use { blockdata::constants::COIN_VALUE, blockdata::script, consensus::Encodable, Block, BlockHash, BlockHeader, OutPoint, Transaction, TxIn, TxOut, Witness, }, + core::str::FromStr, + electrsd::bitcoind::{ + bitcoincore_rpc::{ + bitcoin::{Address, Amount}, + RpcApi, + }, + BitcoinD as Bitcoind, + }, executable_path::executable_path, nix::{ sys::signal::{self, Signal}, @@ -57,6 +65,7 @@ enum Event { } struct Output { + bitcoind: Bitcoind, calls: Vec, stdout: String, tempdir: TempDir, @@ -86,6 +95,7 @@ struct TransactionOptions<'a> { struct Test { args: Vec, + bitcoind: Bitcoind, envs: Vec<(OsString, OsString)>, events: Vec, expected_status: i32, @@ -96,19 +106,23 @@ struct Test { impl Test { fn new() -> Result { - Ok(Self::with_tempdir(TempDir::new()?)) + Ok(Self::with_tempdir(TempDir::new()?)?) } - fn with_tempdir(tempdir: TempDir) -> Self { - Self { + fn with_tempdir(tempdir: TempDir) -> Result { + Ok(Self { args: Vec::new(), + bitcoind: Bitcoind::with_conf( + electrsd::bitcoind::downloaded_exe_path()?, + &electrsd::bitcoind::Conf::default(), + )?, envs: Vec::new(), events: Vec::new(), expected_status: 0, expected_stderr: None, expected_stdout: Expected::String(String::new()), tempdir, - } + }) } fn command(self, args: &str) -> Self { @@ -215,6 +229,8 @@ impl Test { RpcServer::spawn(self.blocks().cloned().collect()) }; + eprintln!("{}", self.bitcoind.params.rpc_socket.to_string()); + let child = Command::new(executable_path("ord")) .envs(self.envs) .stdin(Stdio::null()) @@ -225,7 +241,12 @@ impl Test { Stdio::inherit() }) .current_dir(&self.tempdir) - .arg(format!("--rpc-url=http://127.0.0.1:{rpc_server_port}")) + // .arg(format!("--rpc-url=http://127.0.0.1:{rpc_server_port}")) + .arg(format!( + "--rpc-url={}", + self.bitcoind.params.rpc_socket.to_string() + )) + .arg(format!("--cookie-file={}", self.bitcoind.params.cookie_file.display())) .args(self.args) .spawn()?; @@ -324,9 +345,10 @@ impl Test { let calls = calls.lock().unwrap().clone(); Ok(Output { + bitcoind: self.bitcoind, + calls, stdout: stdout.to_string(), tempdir: self.tempdir, - calls, }) } diff --git a/tests/nft.rs b/tests/nft.rs index 087b7b2838..8acf64e1bb 100644 --- a/tests/nft.rs +++ b/tests/nft.rs @@ -17,7 +17,7 @@ fn mint_and_verify() -> Result { ]) .output()?; - Test::with_tempdir(output.tempdir) + Test::with_tempdir(output.tempdir)? .command("verify foo.nft") .expected_stderr( "NFT is valid! diff --git a/tests/wallet.rs b/tests/wallet.rs index bf8e23dfa7..492c2fe7ee 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -22,7 +22,7 @@ fn init_existing_wallet() -> Result { assert!(tempdir.path().join(path("ord/entropy")).exists()); - Test::with_tempdir(tempdir) + Test::with_tempdir(tempdir)? .command("wallet init") .set_home_to_tempdir() .expected_status(1) @@ -66,7 +66,7 @@ fn load_corrupted_entropy() -> Result { fs::write(&entropy_path, entropy)?; - Test::with_tempdir(tempdir) + Test::with_tempdir(tempdir)? .command("wallet fund") .set_home_to_tempdir() .expected_status(1) @@ -87,7 +87,7 @@ fn fund_existing_wallet() -> Result { .output()? .tempdir; - Test::with_tempdir(tempdir) + Test::with_tempdir(tempdir)? .command("wallet fund") .set_home_to_tempdir() .stdout_regex("^tb1.*\n") @@ -103,3 +103,48 @@ fn fund_nonexistent_wallet() -> Result { .expected_stderr("error: Wallet doesn't exist.\n") .run() } + +#[test] +fn utxos() -> Result { + let output = Test::new()? + .command("wallet init") + .set_home_to_tempdir() + .expected_status(0) + .expected_stderr("Wallet initialized.\n") + .set_home_to_tempdir() + .output()?; + + let output = Test::with_tempdir(output.tempdir)? + .command("wallet fund") + .set_home_to_tempdir() + .stdout_regex("^bcrt1.*\n") + .output()?; + + let core_address = output.bitcoind.client.get_new_address(None, None)?; + + output + .bitcoind + .client + .generate_to_address(101, &core_address)?; + + output.bitcoind.client.send_to_address( + &Address::from_str(&output.stdout.strip_suffix('\n').unwrap())?, + Amount::from_btc(10.0)?, + None, + None, + None, + None, + None, + None, + )?; + + output + .bitcoind + .client + .generate_to_address(1, &core_address)?; + + Test::with_tempdir(output.tempdir)? + .command("wallet utxos") + .set_home_to_tempdir() + .run() +} From 3dba2af09a713b458ee5f025f1ed824f2916904e Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 22 Jul 2022 12:52:29 -0400 Subject: [PATCH 03/61] Initial work --- Cargo.lock | 479 ++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 3 +- tests/index.rs | 2 +- tests/info.rs | 2 +- tests/lib.rs | 166 ++++++++++++----- tests/nft.rs | 2 +- tests/wallet.rs | 6 +- 7 files changed, 595 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d8a66c3d6..d83d921399 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -159,11 +159,17 @@ dependencies = [ "cc", "cfg-if 1.0.0", "libc", - "miniz_oxide", + "miniz_oxide 0.5.3", "object", "rustc-demangle", ] +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + [[package]] name = "base64" version = "0.13.0" @@ -190,6 +196,7 @@ dependencies = [ "bdk-macros", "bip39", "bitcoin", + "bitcoincore-rpc", "electrum-client", "js-sys", "log", @@ -301,6 +308,24 @@ dependencies = [ "serde_json", ] +[[package]] +name = "bitcoind" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0831b9721892ce845a6acadd111311bee84f9e1cc0c5017b8213ec4437ccdfe2" +dependencies = [ + "bitcoin_hashes 0.10.0", + "bitcoincore-rpc", + "filetime", + "flate2", + "home", + "log", + "tar", + "tempfile", + "ureq 1.5.5", + "which", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -343,6 +368,27 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e" +[[package]] +name = "bzip2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cast" version = "0.3.0" @@ -376,10 +422,16 @@ dependencies = [ "libc", "num-integer", "num-traits", - "time", + "time 0.1.44", "winapi", ] +[[package]] +name = "chunked_transfer" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" + [[package]] name = "clap" version = "2.34.0" @@ -445,12 +497,45 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "const_fn" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" + [[package]] name = "convert_case" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "cookie" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" +dependencies = [ + "percent-encoding 2.1.0", + "time 0.2.27", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3" +dependencies = [ + "cookie", + "idna 0.2.1", + "log", + "publicsuffix", + "serde", + "serde_json", + "time 0.2.27", + "url 2.2.2", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -585,7 +670,7 @@ version = "3.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b37feaa84e6861e00a1f5e5aa8da3ee56d605c9992d33e082786754828e20865" dependencies = [ - "nix", + "nix 0.24.2", "winapi", ] @@ -607,7 +692,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version", + "rustc_version 0.4.0", "syn", ] @@ -631,12 +716,33 @@ dependencies = [ "winapi", ] +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + [[package]] name = "either" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" +[[package]] +name = "electrsd" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad65605e022b44ab8c1e489547311bb48b5c605a0aea9ba908e12cae2880111" +dependencies = [ + "bitcoin_hashes 0.10.0", + "bitcoind", + "electrum-client", + "log", + "nix 0.22.3", + "ureq 2.5.0", + "zip", +] + [[package]] name = "electrum-client" version = "0.10.1" @@ -645,12 +751,12 @@ checksum = "8ef9b40020912229e947b45d91f9ff96b10d543e0eddd75ff41b9eda24d9c051" dependencies = [ "bitcoin", "log", - "rustls", + "rustls 0.20.6", "serde", "serde_json", "socks", - "webpki", - "webpki-roots", + "webpki 0.22.0", + "webpki-roots 0.22.4", ] [[package]] @@ -675,6 +781,15 @@ dependencies = [ "termcolor", ] +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "version_check", +] + [[package]] name = "executable-path" version = "1.0.0" @@ -718,14 +833,28 @@ dependencies = [ "instant", ] +[[package]] +name = "filetime" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "winapi", +] + [[package]] name = "flate2" -version = "1.0.24" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" dependencies = [ + "cfg-if 1.0.0", "crc32fast", - "miniz_oxide", + "libc", + "miniz_oxide 0.4.4", ] [[package]] @@ -1019,6 +1148,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "home" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" +dependencies = [ + "winapi", +] + [[package]] name = "html-escape" version = "0.2.11" @@ -1435,6 +1573,16 @@ dependencies = [ "serde", ] +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg 1.1.0", +] + [[package]] name = "miniz_oxide" version = "0.5.3" @@ -1494,6 +1642,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", + "memoffset", +] + [[package]] name = "nix" version = "0.24.2" @@ -1630,6 +1791,7 @@ dependencies = [ "ctrlc", "derive_more", "dirs", + "electrsd", "env_logger", "executable-path", "hex", @@ -1641,7 +1803,7 @@ dependencies = [ "jsonrpc-http-server", "lazy_static", "log", - "nix", + "nix 0.24.2", "qrcode-generator", "rayon", "redb", @@ -1774,7 +1936,7 @@ dependencies = [ "bitflags", "crc32fast", "deflate", - "miniz_oxide", + "miniz_oxide 0.5.3", ] [[package]] @@ -1816,6 +1978,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + [[package]] name = "proc-macro2" version = "1.0.40" @@ -1825,6 +1993,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "publicsuffix" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" +dependencies = [ + "error-chain", + "idna 0.2.1", + "lazy_static", + "regex", + "url 2.2.2", +] + [[package]] name = "pyo3-build-config" version = "0.16.5" @@ -1852,6 +2033,15 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4339fc7a1021c9c1621d87f5e3505f2805c8c105420ba2f2a4df86814590c142" +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding 2.1.0", +] + [[package]] name = "quote" version = "1.0.20" @@ -2176,13 +2366,35 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.12", +] + +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64", + "log", + "ring", + "sct 0.6.1", + "webpki 0.21.4", ] [[package]] @@ -2193,8 +2405,8 @@ checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" dependencies = [ "log", "ring", - "sct", - "webpki", + "sct 0.7.0", + "webpki 0.22.0", ] [[package]] @@ -2234,6 +2446,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "sct" version = "0.7.0" @@ -2287,12 +2509,27 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" version = "1.0.140" @@ -2346,6 +2583,21 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + [[package]] name = "slab" version = "0.4.7" @@ -2422,6 +2674,64 @@ dependencies = [ "lock_api", ] +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version 0.2.3", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + [[package]] name = "strsim" version = "0.10.0" @@ -2445,6 +2755,17 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" +[[package]] +name = "tar" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "target-lexicon" version = "0.12.4" @@ -2540,6 +2861,44 @@ dependencies = [ "winapi", ] +[[package]] +name = "time" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +dependencies = [ + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros", + "version_check", + "winapi", +] + +[[package]] +name = "time-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -2760,6 +3119,42 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "ureq" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8b063c2d59218ae09f22b53c42eaad0d53516457905f5235ca4bc9e99daa71" +dependencies = [ + "base64", + "chunked_transfer", + "cookie", + "cookie_store", + "log", + "once_cell", + "qstring", + "rustls 0.19.1", + "url 2.2.2", + "webpki 0.21.4", + "webpki-roots 0.21.1", +] + +[[package]] +name = "ureq" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97acb4c28a254fd7a4aeec976c46a7fa404eac4d7c134b30c75144846d7cb8f" +dependencies = [ + "base64", + "chunked_transfer", + "flate2", + "log", + "once_cell", + "rustls 0.20.6", + "url 2.2.2", + "webpki 0.22.0", + "webpki-roots 0.22.4", +] + [[package]] name = "url" version = "1.7.2" @@ -2916,6 +3311,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "webpki" version = "0.22.0" @@ -2926,13 +3331,22 @@ dependencies = [ "untrusted", ] +[[package]] +name = "webpki-roots" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +dependencies = [ + "webpki 0.21.4", +] + [[package]] name = "webpki-roots" version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf" dependencies = [ - "webpki", + "webpki 0.22.0", ] [[package]] @@ -2941,6 +3355,17 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" +[[package]] +name = "which" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" +dependencies = [ + "either", + "lazy_static", + "libc", +] + [[package]] name = "winapi" version = "0.3.9" @@ -3023,3 +3448,25 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] + +[[package]] +name = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +dependencies = [ + "libc", +] + +[[package]] +name = "zip" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" +dependencies = [ + "byteorder", + "bzip2", + "crc32fast", + "flate2", + "thiserror", +] diff --git a/Cargo.toml b/Cargo.toml index a60311d5ba..f6e6d0c3ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ autotests = false anyhow = { version = "1.0.56", features = ["backtrace"] } axum = "0.5.6" axum-server = "0.4.0" -bdk = { version = "0.20.0", features = ["keys-bip39", "sqlite"] } +bdk = { version = "0.20.0", features = ["rpc", "keys-bip39", "sqlite"] } bech32 = "0.9.0" bitcoin = "0.28.1" bitcoin_hashes = "0.11.0" @@ -38,6 +38,7 @@ tower-http = { version = "0.3.3", features = ["cors"] } [dev-dependencies] criterion = "0.3.5" +electrsd = { version = "0.19.1", features = ["electrs_0_8_10", "bitcoind_0_20_0"] } hex = "0.4.3" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" diff --git a/tests/index.rs b/tests/index.rs index 7a23a36eab..dc3739e425 100644 --- a/tests/index.rs +++ b/tests/index.rs @@ -10,7 +10,7 @@ fn incremental_indexing() -> Result { assert_eq!(output.calls, &["getblockhash", "getblock", "getblockhash"]); - let output = Test::with_tempdir(output.tempdir) + let output = Test::with_tempdir(output.tempdir)? .command("list 9068a11b8769174363376b606af9a4b8b29dd7b13d013f4b0cbbd457db3c3ce5:0") .expected_stdout("[5000000000,10000000000)\n") .block() diff --git a/tests/info.rs b/tests/info.rs index 44c108f4df..16edfaeecf 100644 --- a/tests/info.rs +++ b/tests/info.rs @@ -4,7 +4,7 @@ use super::*; fn basic() -> Result { let output = Test::new()?.command("index").block().output()?; - Test::with_tempdir(output.tempdir) + Test::with_tempdir(output.tempdir)? .command("info") .stdout_regex( r" diff --git a/tests/lib.rs b/tests/lib.rs index 9a6e3a93e7..51c9944a09 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -6,6 +6,14 @@ use { blockdata::constants::COIN_VALUE, blockdata::script, consensus::Encodable, Block, BlockHash, BlockHeader, OutPoint, Transaction, TxIn, TxOut, Witness, }, + core::str::FromStr, + electrsd::bitcoind::{ + bitcoincore_rpc::{ + bitcoin::{Address, Amount}, + RpcApi, + }, + BitcoinD as Bitcoind, + }, executable_path::executable_path, nix::{ sys::signal::{self, Signal}, @@ -86,6 +94,7 @@ struct TransactionOptions<'a> { struct Test { args: Vec, + bitcoind: Bitcoind, envs: Vec<(OsString, OsString)>, events: Vec, expected_status: i32, @@ -96,19 +105,24 @@ struct Test { impl Test { fn new() -> Result { - Ok(Self::with_tempdir(TempDir::new()?)) + Ok(Self::with_tempdir(TempDir::new()?)?) } - fn with_tempdir(tempdir: TempDir) -> Self { - Self { + fn with_tempdir(tempdir: TempDir) -> Result { + let mut config = electrsd::bitcoind::Conf::default(); + + config.args = vec!["-regtest", "-fallbackfee=0.0001", "-wallet"]; + + Ok(Self { args: Vec::new(), + bitcoind: Bitcoind::with_conf(electrsd::bitcoind::downloaded_exe_path()?, &config)?, envs: Vec::new(), events: Vec::new(), expected_status: 0, expected_stderr: Expected::Ignore, expected_stdout: Expected::String(String::new()), tempdir, - } + }) } fn command(self, args: &str) -> Self { @@ -234,7 +248,14 @@ impl Test { Stdio::inherit() }) .current_dir(&self.tempdir) - .arg(format!("--rpc-url=http://127.0.0.1:{rpc_server_port}")) + .arg(format!( + "--rpc-url={}", + self.bitcoind.params.rpc_socket.to_string() + )) + .arg(format!( + "--cookie-file={}", + self.bitcoind.params.cookie_file.display() + )) .args(self.args) .spawn()?; @@ -352,44 +373,105 @@ impl Test { } fn block_with_coinbase(mut self, coinbase: CoinbaseOptions) -> Self { - self.events.push(Event::Block(Block { - header: BlockHeader { + // basically just need to replace this `Block` construction + // with calls to `bitcoincore_rpc` api + + // 1. Create block + // 2. Create transaction + + let core_address = self.bitcoind.client.get_new_address(None, None).unwrap(); + + let block_hashes = self + .bitcoind + .client + .generate_to_address(101, &core_address) + .unwrap(); + + let mut block = self + .bitcoind + .client + .get_block(block_hashes.first().unwrap()) + .unwrap(); + + block.header = BlockHeader { + version: 0, + prev_blockhash: self + .blocks() + .last() + .map(Block::block_hash) + .unwrap_or_default(), + merkle_root: Default::default(), + time: 0, + bits: 0, + nonce: 0, + }; + + block.txdata = if coinbase.include_coinbase_transaction { + vec![Transaction { version: 0, - prev_blockhash: self - .blocks() - .last() - .map(Block::block_hash) - .unwrap_or_default(), - merkle_root: Default::default(), - time: 0, - bits: 0, - nonce: 0, - }, - txdata: if coinbase.include_coinbase_transaction { - vec![Transaction { - version: 0, - lock_time: 0, - input: vec![TxIn { - previous_output: OutPoint::null(), - script_sig: if coinbase.include_height { - script::Builder::new() - .push_scriptint(self.blocks().count().try_into().unwrap()) - .into_script() - } else { - script::Builder::new().into_script() - }, - sequence: 0, - witness: Witness::new(), - }], - output: vec![TxOut { - value: coinbase.subsidy, - script_pubkey: script::Builder::new().into_script(), - }], - }] - } else { - Vec::new() - }, - })); + lock_time: 0, + input: vec![TxIn { + previous_output: OutPoint::null(), + script_sig: if coinbase.include_height { + script::Builder::new() + .push_scriptint(self.blocks().count().try_into().unwrap()) + .into_script() + } else { + script::Builder::new().into_script() + }, + sequence: 0, + witness: Witness::new(), + }], + output: vec![TxOut { + value: coinbase.subsidy, + script_pubkey: script::Builder::new().into_script(), + }], + }] + } else { + Vec::new() + }; + + // self.events.push(Event::Block(Block { + // header: BlockHeader { + // version: 0, + // prev_blockhash: self + // .blocks() + // .last() + // .map(Block::block_hash) + // .unwrap_or_default(), + // merkle_root: Default::default(), + // time: 0, + // bits: 0, + // nonce: 0, + // }, + // txdata: if coinbase.include_coinbase_transaction { + // vec![Transaction { + // version: 0, + // lock_time: 0, + // input: vec![TxIn { + // previous_output: OutPoint::null(), + // script_sig: if coinbase.include_height { + // script::Builder::new() + // .push_scriptint(self.blocks().count().try_into().unwrap()) + // .into_script() + // } else { + // script::Builder::new().into_script() + // }, + // sequence: 0, + // witness: Witness::new(), + // }], + // output: vec![TxOut { + // value: coinbase.subsidy, + // script_pubkey: script::Builder::new().into_script(), + // }], + // }] + // } else { + // Vec::new() + // }, + // })); + + self.events.push(Event::Block(block)); + self } diff --git a/tests/nft.rs b/tests/nft.rs index 087b7b2838..8acf64e1bb 100644 --- a/tests/nft.rs +++ b/tests/nft.rs @@ -17,7 +17,7 @@ fn mint_and_verify() -> Result { ]) .output()?; - Test::with_tempdir(output.tempdir) + Test::with_tempdir(output.tempdir)? .command("verify foo.nft") .expected_stderr( "NFT is valid! diff --git a/tests/wallet.rs b/tests/wallet.rs index bf8e23dfa7..6a200f0867 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -22,7 +22,7 @@ fn init_existing_wallet() -> Result { assert!(tempdir.path().join(path("ord/entropy")).exists()); - Test::with_tempdir(tempdir) + Test::with_tempdir(tempdir)? .command("wallet init") .set_home_to_tempdir() .expected_status(1) @@ -66,7 +66,7 @@ fn load_corrupted_entropy() -> Result { fs::write(&entropy_path, entropy)?; - Test::with_tempdir(tempdir) + Test::with_tempdir(tempdir)? .command("wallet fund") .set_home_to_tempdir() .expected_status(1) @@ -87,7 +87,7 @@ fn fund_existing_wallet() -> Result { .output()? .tempdir; - Test::with_tempdir(tempdir) + Test::with_tempdir(tempdir)? .command("wallet fund") .set_home_to_tempdir() .stdout_regex("^tb1.*\n") From 79ad708c55ee9790cc80f375b40f000fa278ceb9 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 22 Jul 2022 17:58:58 -0400 Subject: [PATCH 04/61] Get first_coinbase_transaction working --- tests/lib.rs | 17 +++++------------ tests/list.rs | 3 +-- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/tests/lib.rs b/tests/lib.rs index 51c9944a09..260b533afd 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -109,13 +109,12 @@ impl Test { } fn with_tempdir(tempdir: TempDir) -> Result { - let mut config = electrsd::bitcoind::Conf::default(); - - config.args = vec!["-regtest", "-fallbackfee=0.0001", "-wallet"]; - Ok(Self { args: Vec::new(), - bitcoind: Bitcoind::with_conf(electrsd::bitcoind::downloaded_exe_path()?, &config)?, + bitcoind: Bitcoind::with_conf( + electrsd::bitcoind::downloaded_exe_path()?, + &electrsd::bitcoind::Conf::default(), + )?, envs: Vec::new(), events: Vec::new(), expected_status: 0, @@ -373,18 +372,12 @@ impl Test { } fn block_with_coinbase(mut self, coinbase: CoinbaseOptions) -> Self { - // basically just need to replace this `Block` construction - // with calls to `bitcoincore_rpc` api - - // 1. Create block - // 2. Create transaction - let core_address = self.bitcoind.client.get_new_address(None, None).unwrap(); let block_hashes = self .bitcoind .client - .generate_to_address(101, &core_address) + .generate_to_address(1, &core_address) .unwrap(); let mut block = self diff --git a/tests/list.rs b/tests/list.rs index ba12f453e2..e97c77cce9 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -3,8 +3,7 @@ use super::*; #[test] fn first_coinbase_transaction() -> Result { Test::new()? - .command("list 0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0") - .block() + .command("list 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0") .expected_stdout("[0,5000000000)\n") .run() } From 646c9eebade3f550f16461a67a6126430faf5c52 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 25 Jul 2022 10:42:32 -0400 Subject: [PATCH 05/61] Fix two more list tests --- src/index.rs | 4 +++ tests/lib.rs | 97 +++++++++++++++++++++++++++------------------------ tests/list.rs | 6 ++-- 3 files changed, 57 insertions(+), 50 deletions(-) diff --git a/src/index.rs b/src/index.rs index af1de39ff9..29edfbd1f8 100644 --- a/src/index.rs +++ b/src/index.rs @@ -245,6 +245,10 @@ impl Index { input_ordinal_ranges: &mut VecDeque<(u64, u64)>, ordinal_ranges_written: &mut u64, ) -> Result { + eprintln!("{txid}"); + + dbg!(tx); + for (vout, output) in tx.output.iter().enumerate() { let outpoint = OutPoint { vout: vout as u32, diff --git a/tests/lib.rs b/tests/lib.rs index 260b533afd..1f33d8feee 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -109,11 +109,16 @@ impl Test { } fn with_tempdir(tempdir: TempDir) -> Result { + let mut conf = electrsd::bitcoind::Conf::default(); + + conf.args.push("-blockversion=1"); + conf.args.push("-testactivationheight=bip34@100"); + Ok(Self { args: Vec::new(), bitcoind: Bitcoind::with_conf( electrsd::bitcoind::downloaded_exe_path()?, - &electrsd::bitcoind::Conf::default(), + &conf )?, envs: Vec::new(), events: Vec::new(), @@ -225,11 +230,11 @@ impl Test { } fn test(self, port: Option) -> Result { - for (b, block) in self.blocks().enumerate() { - for (t, transaction) in block.txdata.iter().enumerate() { - eprintln!("{b}.{t}: {}", transaction.txid()); - } - } + // for (b, block) in self.blocks().enumerate() { + // for (t, transaction) in block.txdata.iter().enumerate() { + // eprintln!("{b}.{t}: {}", transaction.txid()); + // } + // } let (blocks, close_handle, calls, rpc_server_port) = if port.is_some() { RpcServer::spawn(Vec::new()) @@ -372,57 +377,57 @@ impl Test { } fn block_with_coinbase(mut self, coinbase: CoinbaseOptions) -> Self { - let core_address = self.bitcoind.client.get_new_address(None, None).unwrap(); + let address = Address::from_str("bcrt1qjcgxtte2ttzmvugn874y0n7j9jc82j0y6qvkvn").unwrap(); let block_hashes = self .bitcoind .client - .generate_to_address(1, &core_address) + .generate_to_address(1, &address) .unwrap(); - let mut block = self + let block = self .bitcoind .client .get_block(block_hashes.first().unwrap()) .unwrap(); - block.header = BlockHeader { - version: 0, - prev_blockhash: self - .blocks() - .last() - .map(Block::block_hash) - .unwrap_or_default(), - merkle_root: Default::default(), - time: 0, - bits: 0, - nonce: 0, - }; - - block.txdata = if coinbase.include_coinbase_transaction { - vec![Transaction { - version: 0, - lock_time: 0, - input: vec![TxIn { - previous_output: OutPoint::null(), - script_sig: if coinbase.include_height { - script::Builder::new() - .push_scriptint(self.blocks().count().try_into().unwrap()) - .into_script() - } else { - script::Builder::new().into_script() - }, - sequence: 0, - witness: Witness::new(), - }], - output: vec![TxOut { - value: coinbase.subsidy, - script_pubkey: script::Builder::new().into_script(), - }], - }] - } else { - Vec::new() - }; + // block.header = BlockHeader { + // version: 0, + // prev_blockhash: self + // .blocks() + // .last() + // .map(Block::block_hash) + // .unwrap_or_default(), + // merkle_root: Default::default(), + // time: 0, + // bits: 0, + // nonce: 0, + // }; + + // block.txdata = if coinbase.include_coinbase_transaction { + // vec![Transaction { + // version: 0, + // lock_time: 0, + // input: vec![TxIn { + // previous_output: OutPoint::null(), + // script_sig: if coinbase.include_height { + // script::Builder::new() + // .push_scriptint(self.blocks().count().try_into().unwrap()) + // .into_script() + // } else { + // script::Builder::new().into_script() + // }, + // sequence: 0, + // witness: Witness::new(), + // }], + // output: vec![TxOut { + // value: coinbase.subsidy, + // script_pubkey: script::Builder::new().into_script(), + // }], + // }] + // } else { + // Vec::new() + // }; // self.events.push(Event::Block(Block { // header: BlockHeader { diff --git a/tests/list.rs b/tests/list.rs index e97c77cce9..4856349f8d 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -11,8 +11,7 @@ fn first_coinbase_transaction() -> Result { #[test] fn second_coinbase_transaction() -> Result { Test::new()? - .command("list 9068a11b8769174363376b606af9a4b8b29dd7b13d013f4b0cbbd457db3c3ce5:0") - .block() + .command("list 104a8ee40f039ba83ceda9de4c6eb7d8587704168f687b315974d307c93b9caf:0") .block() .expected_stdout("[5000000000,10000000000)\n") .run() @@ -21,8 +20,7 @@ fn second_coinbase_transaction() -> Result { #[test] fn third_coinbase_transaction_is_not_duplicate() -> Result { Test::new()? - .command("list 8aa5103b13b5b233ac417ee31f21820c9284af2b7a2080a142c2d20e1697b0f4:0") - .block() + .command("list 4e99453697da6fb20ac8cd75113aa56a3e52c341c4bc4a9f8eabfb50a1c1ae70:0") .block() .block() .expected_stdout("[10000000000,15000000000)\n") From c3c418cbb2a6f31a9f903b7afc11daad77a810b0 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 25 Jul 2022 14:51:34 -0400 Subject: [PATCH 06/61] Fix a few find tests --- src/index.rs | 4 ++-- tests/find.rs | 9 +++------ tests/lib.rs | 16 ++++++++++++++-- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/index.rs b/src/index.rs index 29edfbd1f8..b7e7500498 100644 --- a/src/index.rs +++ b/src/index.rs @@ -245,9 +245,9 @@ impl Index { input_ordinal_ranges: &mut VecDeque<(u64, u64)>, ordinal_ranges_written: &mut u64, ) -> Result { - eprintln!("{txid}"); + // eprintln!("{txid}"); - dbg!(tx); + // dbg!(tx); for (vout, output) in tx.output.iter().enumerate() { let outpoint = OutPoint { diff --git a/tests/find.rs b/tests/find.rs index d28466c172..378c2e3b8e 100644 --- a/tests/find.rs +++ b/tests/find.rs @@ -4,8 +4,7 @@ use super::*; fn first_satoshi() -> Result { Test::new()? .command("find 0") - .expected_stdout("0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0:0\n") - .block() + .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") .run() } @@ -23,8 +22,7 @@ fn first_satoshi_slot() -> Result { fn second_satoshi() -> Result { Test::new()? .command("find 1") - .expected_stdout("0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0:1\n") - .block() + .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:1\n") .run() } @@ -42,8 +40,7 @@ fn second_satoshi_slot() -> Result { fn first_satoshi_of_second_block() -> Result { Test::new()? .command("find 5000000000") - .expected_stdout("9068a11b8769174363376b606af9a4b8b29dd7b13d013f4b0cbbd457db3c3ce5:0:0\n") - .block() + .expected_stdout("104a8ee40f039ba83ceda9de4c6eb7d8587704168f687b315974d307c93b9caf:0:0\n") .block() .run() } diff --git a/tests/lib.rs b/tests/lib.rs index 1f33d8feee..206b502989 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -111,8 +111,8 @@ impl Test { fn with_tempdir(tempdir: TempDir) -> Result { let mut conf = electrsd::bitcoind::Conf::default(); - conf.args.push("-blockversion=1"); - conf.args.push("-testactivationheight=bip34@100"); + // conf.args.push("-blockversion=1"); + // conf.args.push("-testactivationheight=bip34@100"); Ok(Self { args: Vec::new(), @@ -474,6 +474,18 @@ impl Test { } fn transaction(mut self, options: TransactionOptions) -> Self { + // slot notation (x, y, z) + // + // x : block index + // y : tx index + // z : output index + // + // 1. Create raw transaction + // - utxos + // - outs + // - locktime + // - replaceable + let input_value = options .slots .iter() From 5e435413402da15d8185ff5feade8aafe674cdb9 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 26 Jul 2022 17:51:28 -0400 Subject: [PATCH 07/61] Get 4th list test working --- Cargo.lock | 87 +------------ Cargo.toml | 2 +- justfile | 4 - src/index.rs | 4 +- tests/find.rs | 45 ++----- tests/lib.rs | 327 ++++++++++++++++++------------------------------ tests/list.rs | 49 +++----- tests/server.rs | 1 - 8 files changed, 154 insertions(+), 365 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d83d921399..b16dce6a8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,7 +322,7 @@ dependencies = [ "log", "tar", "tempfile", - "ureq 1.5.5", + "ureq", "which", ] @@ -368,27 +368,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e" -[[package]] -name = "bzip2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "cast" version = "0.3.0" @@ -670,7 +649,7 @@ version = "3.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b37feaa84e6861e00a1f5e5aa8da3ee56d605c9992d33e082786754828e20865" dependencies = [ - "nix 0.24.2", + "nix", "winapi", ] @@ -728,21 +707,6 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" -[[package]] -name = "electrsd" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad65605e022b44ab8c1e489547311bb48b5c605a0aea9ba908e12cae2880111" -dependencies = [ - "bitcoin_hashes 0.10.0", - "bitcoind", - "electrum-client", - "log", - "nix 0.22.3", - "ureq 2.5.0", - "zip", -] - [[package]] name = "electrum-client" version = "0.10.1" @@ -1642,19 +1606,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "nix" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" -dependencies = [ - "bitflags", - "cc", - "cfg-if 1.0.0", - "libc", - "memoffset", -] - [[package]] name = "nix" version = "0.24.2" @@ -1785,13 +1736,13 @@ dependencies = [ "bitcoin", "bitcoin_hashes 0.11.0", "bitcoincore-rpc", + "bitcoind", "chrono", "clap 3.2.14", "criterion", "ctrlc", "derive_more", "dirs", - "electrsd", "env_logger", "executable-path", "hex", @@ -1803,7 +1754,7 @@ dependencies = [ "jsonrpc-http-server", "lazy_static", "log", - "nix 0.24.2", + "nix", "qrcode-generator", "rayon", "redb", @@ -3138,23 +3089,6 @@ dependencies = [ "webpki-roots 0.21.1", ] -[[package]] -name = "ureq" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97acb4c28a254fd7a4aeec976c46a7fa404eac4d7c134b30c75144846d7cb8f" -dependencies = [ - "base64", - "chunked_transfer", - "flate2", - "log", - "once_cell", - "rustls 0.20.6", - "url 2.2.2", - "webpki 0.22.0", - "webpki-roots 0.22.4", -] - [[package]] name = "url" version = "1.7.2" @@ -3457,16 +3391,3 @@ checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" dependencies = [ "libc", ] - -[[package]] -name = "zip" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" -dependencies = [ - "byteorder", - "bzip2", - "crc32fast", - "flate2", - "thiserror", -] diff --git a/Cargo.toml b/Cargo.toml index f6e6d0c3ef..a144e45c42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,8 +37,8 @@ tokio = { version = "1.17.0", features = ["rt-multi-thread"] } tower-http = { version = "0.3.3", features = ["cors"] } [dev-dependencies] +bitcoind = { version = "0.26.1", features = ["22_0"] } criterion = "0.3.5" -electrsd = { version = "0.19.1", features = ["electrs_0_8_10", "bitcoind_0_20_0"] } hex = "0.4.3" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" diff --git a/justfile b/justfile index f19b59e24a..52c2131b5a 100644 --- a/justfile +++ b/justfile @@ -1,7 +1,3 @@ -log := '0' - -export RUST_LOG := log - ci: clippy forbid cargo fmt -- --check cargo test diff --git a/src/index.rs b/src/index.rs index b7e7500498..e93ca0989a 100644 --- a/src/index.rs +++ b/src/index.rs @@ -245,9 +245,7 @@ impl Index { input_ordinal_ranges: &mut VecDeque<(u64, u64)>, ordinal_ranges_written: &mut u64, ) -> Result { - // eprintln!("{txid}"); - - // dbg!(tx); + log::trace!("{txid}: {:?}", tx); for (vout, output) in tx.output.iter().enumerate() { let outpoint = OutPoint { diff --git a/tests/find.rs b/tests/find.rs index 378c2e3b8e..c712f74d70 100644 --- a/tests/find.rs +++ b/tests/find.rs @@ -87,19 +87,19 @@ fn first_satoshi_spent_in_second_block_slot() -> Result { .run() } -#[test] -#[ignore] -fn regression_empty_block_crash() -> Result { - Test::new()? - .command("find 0 --slot") - .block() - .block_with_coinbase(CoinbaseOptions { - include_coinbase_transaction: false, - ..Default::default() - }) - .expected_stdout("0x0x0x0\n") - .run() -} +// #[test] +// #[ignore] +// fn regression_empty_block_crash() -> Result { +// Test::new()? +// .command("find 0 --slot") +// .block() +// .block_with_coinbase(CoinbaseOptions { +// include_coinbase_transaction: false, +// ..Default::default() +// }) +// .expected_stdout("0x0x0x0\n") +// .run() +// } #[test] #[ignore] @@ -122,30 +122,11 @@ fn mining_and_spending_transaction_in_same_block() -> Result { .run() } -#[test] -fn empty_index() -> Result { - Test::new()? - .expected_stderr("error: Ordinal has not been mined as of index height\n") - .expected_status(1) - .command("find 0") - .run() -} - #[test] fn unmined_satoshi_in_second_block() -> Result { Test::new()? - .block() .expected_stderr("error: Ordinal has not been mined as of index height\n") .expected_status(1) .command("find 5000000000") .run() } - -#[test] -fn unmined_satoshi_in_first_block() -> Result { - Test::new()? - .expected_stderr("error: Ordinal has not been mined as of index height\n") - .expected_status(1) - .command("find 0") - .run() -} diff --git a/tests/lib.rs b/tests/lib.rs index 206b502989..06144435df 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -6,14 +6,14 @@ use { blockdata::constants::COIN_VALUE, blockdata::script, consensus::Encodable, Block, BlockHash, BlockHeader, OutPoint, Transaction, TxIn, TxOut, Witness, }, - core::str::FromStr, - electrsd::bitcoind::{ + bitcoind::{ bitcoincore_rpc::{ bitcoin::{Address, Amount}, RpcApi, }, BitcoinD as Bitcoind, }, + core::str::FromStr, executable_path::executable_path, nix::{ sys::signal::{self, Signal}, @@ -59,9 +59,10 @@ enum Expected { Ignore, } -enum Event { - Block(Block), +enum Event<'a> { + Block, Request(String, u16, String), + Transaction(TransactionOptions<'a>), } struct Output { @@ -70,56 +71,38 @@ struct Output { tempdir: TempDir, } -struct CoinbaseOptions { - include_coinbase_transaction: bool, - include_height: bool, - subsidy: u64, -} - -impl Default for CoinbaseOptions { - fn default() -> Self { - Self { - include_coinbase_transaction: true, - include_height: true, - subsidy: 50 * COIN_VALUE, - } - } -} - struct TransactionOptions<'a> { slots: &'a [(usize, usize, usize)], output_count: usize, fee: u64, } -struct Test { +struct Test<'a> { + address: Address, args: Vec, bitcoind: Bitcoind, envs: Vec<(OsString, OsString)>, - events: Vec, + events: Vec>, expected_status: i32, expected_stderr: Expected, expected_stdout: Expected, tempdir: TempDir, } -impl Test { +impl<'a> Test<'a> { fn new() -> Result { Ok(Self::with_tempdir(TempDir::new()?)?) } fn with_tempdir(tempdir: TempDir) -> Result { - let mut conf = electrsd::bitcoind::Conf::default(); + let mut conf = bitcoind::Conf::default(); - // conf.args.push("-blockversion=1"); - // conf.args.push("-testactivationheight=bip34@100"); + conf.view_stdout = true; Ok(Self { + address: Address::from_str("bcrt1qjcgxtte2ttzmvugn874y0n7j9jc82j0y6qvkvn")?, args: Vec::new(), - bitcoind: Bitcoind::with_conf( - electrsd::bitcoind::downloaded_exe_path()?, - &conf - )?, + bitcoind: Bitcoind::with_conf(bitcoind::downloaded_exe_path()?, &conf)?, envs: Vec::new(), events: Vec::new(), expected_status: 0, @@ -222,14 +205,65 @@ impl Test { self.test(Some(port)).map(|_| ()) } - fn blocks(&self) -> impl Iterator + '_ { - self.events.iter().filter_map(|event| match event { - Event::Block(block) => Some(block), - _ => None, - }) + fn get_block(&self, height: u64) -> Result { + let block = self + .bitcoind + .client + .get_block(&self.bitcoind.client.get_block_hash(height)?)?; + + Ok(block) } fn test(self, port: Option) -> Result { + for event in &self.events { + match event { + Event::Block => { + eprintln!("mining block !"); + self.bitcoind.client.generate_to_address(1, &self.address)?; + } + Event::Request(request, status, expected_response) => { + panic!() + } + Event::Transaction(options) => { + let input_value = options + .slots + .iter() + .map(|slot| { + self.get_block(slot.0 as u64).unwrap().txdata[slot.1].output[slot.2].value + }) + .sum::(); + + let output_value = input_value - options.fee; + + let tx = Transaction { + version: 0, + lock_time: 0, + input: options + .slots + .iter() + .map(|slot| TxIn { + previous_output: OutPoint { + txid: self.get_block(slot.0 as u64).unwrap().txdata[slot.1].txid(), + vout: slot.2 as u32, + }, + script_sig: script::Builder::new().into_script(), + sequence: 0, + witness: Witness::new(), + }) + .collect(), + output: vec![ + TxOut { + value: output_value / options.output_count as u64, + script_pubkey: script::Builder::new().into_script(), + }; + options.output_count + ], + }; + + self.bitcoind.client.send_raw_transaction(&tx)?; + } + } + } // for (b, block) in self.blocks().enumerate() { // for (t, transaction) in block.txdata.iter().enumerate() { // eprintln!("{b}.{t}: {}", transaction.txid()); @@ -239,11 +273,11 @@ impl Test { let (blocks, close_handle, calls, rpc_server_port) = if port.is_some() { RpcServer::spawn(Vec::new()) } else { - RpcServer::spawn(self.blocks().cloned().collect()) + RpcServer::spawn(Vec::new()) }; let child = Command::new(executable_path("ord")) - .envs(self.envs) + .envs(self.envs.clone()) .stdin(Stdio::null()) .stdout(Stdio::piped()) .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { @@ -260,11 +294,13 @@ impl Test { "--cookie-file={}", self.bitcoind.params.cookie_file.display() )) - .args(self.args) + .args(self.args.clone()) .spawn()?; let mut successful_requests = 0; + dbg!(port); + if let Some(port) = port { let client = reqwest::blocking::Client::new(); @@ -289,12 +325,14 @@ impl Test { sleep(Duration::from_millis(100)); } + dbg!(healthy); + if healthy { for event in &self.events { match event { - Event::Block(block) => { - blocks.lock().unwrap().push(block.clone()); - thread::sleep(Duration::from_millis(200)); + Event::Block => { + eprintln!("mining block !"); + self.bitcoind.client.generate_to_address(1, &self.address)?; } Event::Request(request, status, expected_response) => { let response = client @@ -304,6 +342,44 @@ impl Test { assert_eq!(response.text()?, *expected_response); successful_requests += 1; } + Event::Transaction(options) => { + let input_value = options + .slots + .iter() + .map(|slot| { + self.get_block(slot.0 as u64).unwrap().txdata[slot.1].output[slot.2].value + }) + .sum::(); + + let output_value = input_value - options.fee; + + let tx = Transaction { + version: 0, + lock_time: 0, + input: options + .slots + .iter() + .map(|slot| TxIn { + previous_output: OutPoint { + txid: self.get_block(slot.0 as u64).unwrap().txdata[slot.1].txid(), + vout: slot.2 as u32, + }, + script_sig: script::Builder::new().into_script(), + sequence: 0, + witness: Witness::new(), + }) + .collect(), + output: vec![ + TxOut { + value: output_value / options.output_count as u64, + script_pubkey: script::Builder::new().into_script(), + }; + options.output_count + ], + }; + + self.bitcoind.client.send_raw_transaction(&tx)?; + } } } } @@ -372,174 +448,13 @@ impl Test { }) } - fn block(self) -> Self { - self.block_with_coinbase(CoinbaseOptions::default()) - } - - fn block_with_coinbase(mut self, coinbase: CoinbaseOptions) -> Self { - let address = Address::from_str("bcrt1qjcgxtte2ttzmvugn874y0n7j9jc82j0y6qvkvn").unwrap(); - - let block_hashes = self - .bitcoind - .client - .generate_to_address(1, &address) - .unwrap(); - - let block = self - .bitcoind - .client - .get_block(block_hashes.first().unwrap()) - .unwrap(); - - // block.header = BlockHeader { - // version: 0, - // prev_blockhash: self - // .blocks() - // .last() - // .map(Block::block_hash) - // .unwrap_or_default(), - // merkle_root: Default::default(), - // time: 0, - // bits: 0, - // nonce: 0, - // }; - - // block.txdata = if coinbase.include_coinbase_transaction { - // vec![Transaction { - // version: 0, - // lock_time: 0, - // input: vec![TxIn { - // previous_output: OutPoint::null(), - // script_sig: if coinbase.include_height { - // script::Builder::new() - // .push_scriptint(self.blocks().count().try_into().unwrap()) - // .into_script() - // } else { - // script::Builder::new().into_script() - // }, - // sequence: 0, - // witness: Witness::new(), - // }], - // output: vec![TxOut { - // value: coinbase.subsidy, - // script_pubkey: script::Builder::new().into_script(), - // }], - // }] - // } else { - // Vec::new() - // }; - - // self.events.push(Event::Block(Block { - // header: BlockHeader { - // version: 0, - // prev_blockhash: self - // .blocks() - // .last() - // .map(Block::block_hash) - // .unwrap_or_default(), - // merkle_root: Default::default(), - // time: 0, - // bits: 0, - // nonce: 0, - // }, - // txdata: if coinbase.include_coinbase_transaction { - // vec![Transaction { - // version: 0, - // lock_time: 0, - // input: vec![TxIn { - // previous_output: OutPoint::null(), - // script_sig: if coinbase.include_height { - // script::Builder::new() - // .push_scriptint(self.blocks().count().try_into().unwrap()) - // .into_script() - // } else { - // script::Builder::new().into_script() - // }, - // sequence: 0, - // witness: Witness::new(), - // }], - // output: vec![TxOut { - // value: coinbase.subsidy, - // script_pubkey: script::Builder::new().into_script(), - // }], - // }] - // } else { - // Vec::new() - // }, - // })); - - self.events.push(Event::Block(block)); - + fn block(mut self) -> Self { + self.events.push(Event::Block); self } - fn transaction(mut self, options: TransactionOptions) -> Self { - // slot notation (x, y, z) - // - // x : block index - // y : tx index - // z : output index - // - // 1. Create raw transaction - // - utxos - // - outs - // - locktime - // - replaceable - - let input_value = options - .slots - .iter() - .map(|slot| self.blocks().nth(slot.0).unwrap().txdata[slot.1].output[slot.2].value) - .sum::(); - - let output_value = input_value - options.fee; - - let tx = Transaction { - version: 0, - lock_time: 0, - input: options - .slots - .iter() - .map(|slot| TxIn { - previous_output: OutPoint { - txid: self.blocks().nth(slot.0).unwrap().txdata[slot.1].txid(), - vout: slot.2 as u32, - }, - script_sig: script::Builder::new().into_script(), - sequence: 0, - witness: Witness::new(), - }) - .collect(), - output: vec![ - TxOut { - value: output_value / options.output_count as u64, - script_pubkey: script::Builder::new().into_script(), - }; - options.output_count - ], - }; - - let block = self - .events - .iter_mut() - .rev() - .find_map(|event| match event { - Event::Block(block) => Some(block), - _ => None, - }) - .unwrap(); - - block - .txdata - .first_mut() - .unwrap() - .output - .first_mut() - .unwrap() - .value += options.fee; - - block.txdata.push(tx); - + fn transaction(mut self, options: TransactionOptions<'a>) -> Self { + self.events.push(Event::Transaction(options)); self } diff --git a/tests/list.rs b/tests/list.rs index 4856349f8d..15c99b2e9c 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -30,7 +30,7 @@ fn third_coinbase_transaction_is_not_duplicate() -> Result { #[test] fn split_ranges_are_tracked_correctly() -> Result { Test::new()? - .command("list a3f7b03f71988d4f91fea260405dbf3f3586eb134ad01dad15de63053e4985d0:0") + .command("list 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0") .block() .block() .transaction(TransactionOptions { @@ -38,11 +38,12 @@ fn split_ranges_are_tracked_correctly() -> Result { output_count: 2, fee: 0, }) + .block() .expected_stdout("[0,2500000000)\n") .run()?; Test::new()? - .command("list a3f7b03f71988d4f91fea260405dbf3f3586eb134ad01dad15de63053e4985d0:1") + .command("list 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0") .block() .block() .transaction(TransactionOptions { @@ -75,39 +76,17 @@ fn merge_ranges_are_tracked_correctly() -> Result { .run() } -#[test] -fn duplicate_transaction_range() -> Result { - Test::new()? - .command("list d63a320a4b404d7933ca788e8f185f10e31e03bf6ab9fa4595bfedc2fcc5a4a8:0") - .block_with_coinbase(CoinbaseOptions { - include_height: false, - ..Default::default() - }) - .block_with_coinbase(CoinbaseOptions { - include_height: false, - ..Default::default() - }) - .block() - .transaction(TransactionOptions { - slots: &[(0, 0, 0)], - output_count: 1, - fee: 0, - }) - .expected_stdout("[5000000000,10000000000)\n") - .run() -} - -#[test] -fn underpay_subsidy() -> Result { - Test::new()? - .command("list 12d57183977a1df616bafbb7dafbb4249e59d8f796ba556ad6bb75f0fa9fe0ea:0") - .block_with_coinbase(CoinbaseOptions { - subsidy: 50 * COIN_VALUE - 1, - ..Default::default() - }) - .expected_stdout("[0,4999999999)\n") - .run() -} +// #[test] +// fn underpay_subsidy() -> Result { +// Test::new()? +// .command("list 12d57183977a1df616bafbb7dafbb4249e59d8f796ba556ad6bb75f0fa9fe0ea:0") +// .block_with_coinbase(CoinbaseOptions { +// subsidy: 50 * COIN_VALUE - 1, +// ..Default::default() +// }) +// .expected_stdout("[0,4999999999)\n") +// .run() +// } #[test] fn fee_paying_transaction_range() -> Result { diff --git a/tests/server.rs b/tests/server.rs index 59ea7ac129..b8ecb2a7ed 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -10,7 +10,6 @@ fn list() -> Result { Test::new()? .command(&format!("server --address 127.0.0.1 --port {port}")) - .block() .request( "list/0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0", 200, From 9f498b720939de1551281a337b72900bd3b744ef Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 27 Jul 2022 15:33:32 -0400 Subject: [PATCH 08/61] Start adding bdk wallet in tests --- src/index.rs | 2 +- tests/lib.rs | 143 +++++++++++++++++++++++++++++++++++++------------- tests/list.rs | 12 +---- 3 files changed, 108 insertions(+), 49 deletions(-) diff --git a/src/index.rs b/src/index.rs index e93ca0989a..f3902a65f4 100644 --- a/src/index.rs +++ b/src/index.rs @@ -245,7 +245,7 @@ impl Index { input_ordinal_ranges: &mut VecDeque<(u64, u64)>, ordinal_ranges_written: &mut u64, ) -> Result { - log::trace!("{txid}: {:?}", tx); + log::trace!("TRANSACTION: {txid}: {:?}", tx); for (vout, output) in tx.output.iter().enumerate() { let outpoint = OutPoint { diff --git a/tests/lib.rs b/tests/lib.rs index 06144435df..3488d24a5e 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -2,10 +2,31 @@ use { crate::rpc_server::RpcServer, + bdk::{ + bitcoin::secp256k1::Secp256k1, + blockchain::{ + rpc::{Auth, RpcBlockchain, RpcConfig}, + ConfigurableBlockchain, LogProgress, + }, + database::MemoryDatabase, + keys::{ + bip39::{Language, Mnemonic, WordCount}, + DerivableKey, GeneratableKey, + }, + miniscript::miniscript::Segwitv0, + template::Bip84, + wallet::{ + signer::SignOptions, wallet_name_from_descriptor, AddressIndex, AddressIndex::LastUnused, + SyncOptions, Wallet, + }, + KeychainKind, + }, bitcoin::{ - blockdata::constants::COIN_VALUE, blockdata::script, consensus::Encodable, Block, BlockHash, - BlockHeader, OutPoint, Transaction, TxIn, TxOut, Witness, + blockdata::constants::COIN_VALUE, blockdata::script, consensus::Encodable, + network::constants::Network, Block, BlockHash, BlockHeader, OutPoint, Transaction, TxIn, TxOut, + Witness, }, + core::str::FromStr, bitcoind::{ bitcoincore_rpc::{ bitcoin::{Address, Amount}, @@ -13,7 +34,6 @@ use { }, BitcoinD as Bitcoind, }, - core::str::FromStr, executable_path::executable_path, nix::{ sys::signal::{self, Signal}, @@ -26,6 +46,7 @@ use { ffi::OsString, fs, net::TcpListener, + path::PathBuf, process::{Command, Stdio}, str, sync::{Arc, Mutex}, @@ -78,7 +99,6 @@ struct TransactionOptions<'a> { } struct Test<'a> { - address: Address, args: Vec, bitcoind: Bitcoind, envs: Vec<(OsString, OsString)>, @@ -87,6 +107,7 @@ struct Test<'a> { expected_stderr: Expected, expected_stdout: Expected, tempdir: TempDir, + wallet: Wallet, } impl<'a> Test<'a> { @@ -94,21 +115,58 @@ impl<'a> Test<'a> { Ok(Self::with_tempdir(TempDir::new()?)?) } + fn get_key() -> Result + Clone> { + Ok(( + Mnemonic::parse("book fit fly ketchup also elevator scout mind edit fatal where rookie")?, + None, + )) + } + fn with_tempdir(tempdir: TempDir) -> Result { let mut conf = bitcoind::Conf::default(); conf.view_stdout = true; + let bitcoind = Bitcoind::with_conf(bitcoind::downloaded_exe_path()?, &conf)?; + + let block = bitcoind + .client + .get_block(&bitcoind.client.get_block_hash(0)?)?; + + dbg!(block); + + let wallet = Wallet::new( + Bip84(Self::get_key()?, KeychainKind::External), + None, + Network::Regtest, + MemoryDatabase::new(), + )?; + + wallet.sync( + &RpcBlockchain::from_config(&RpcConfig { + url: bitcoind.params.rpc_socket.to_string(), + auth: Auth::Cookie { + file: bitcoind.params.cookie_file.clone() + }, + network: Network::Regtest, + wallet_name: "test".to_string(), + skip_blocks: None, + })?, + SyncOptions { + progress: Some(Box::new(LogProgress)), + }, + )?; + Ok(Self { - address: Address::from_str("bcrt1qjcgxtte2ttzmvugn874y0n7j9jc82j0y6qvkvn")?, args: Vec::new(), - bitcoind: Bitcoind::with_conf(bitcoind::downloaded_exe_path()?, &conf)?, + bitcoind, envs: Vec::new(), events: Vec::new(), expected_status: 0, expected_stderr: Expected::Ignore, expected_stdout: Expected::String(String::new()), tempdir, + wallet, }) } @@ -218,8 +276,10 @@ impl<'a> Test<'a> { for event in &self.events { match event { Event::Block => { - eprintln!("mining block !"); - self.bitcoind.client.generate_to_address(1, &self.address)?; + self + .bitcoind + .client + .generate_to_address(1, &self.wallet.get_address(AddressIndex::Peek(0))?.address)?; } Event::Request(request, status, expected_response) => { panic!() @@ -228,42 +288,49 @@ impl<'a> Test<'a> { let input_value = options .slots .iter() - .map(|slot| { - self.get_block(slot.0 as u64).unwrap().txdata[slot.1].output[slot.2].value - }) + .map(|slot| self.get_block(slot.0 as u64).unwrap().txdata[slot.1].output[slot.2].value) .sum::(); let output_value = input_value - options.fee; - let tx = Transaction { - version: 0, - lock_time: 0, - input: options - .slots - .iter() - .map(|slot| TxIn { - previous_output: OutPoint { - txid: self.get_block(slot.0 as u64).unwrap().txdata[slot.1].txid(), - vout: slot.2 as u32, - }, - script_sig: script::Builder::new().into_script(), - sequence: 0, - witness: Witness::new(), - }) - .collect(), - output: vec![ - TxOut { - value: output_value / options.output_count as u64, - script_pubkey: script::Builder::new().into_script(), - }; - options.output_count - ], + let (mut psbt, _) = { + let mut builder = self.wallet.build_tx(); + + builder + .add_utxos( + &options + .slots + .iter() + .map(|slot| OutPoint { + txid: self.get_block(slot.0 as u64).unwrap().txdata[slot.1].txid(), + vout: slot.2 as u32, + }) + .collect::>(), + ) + .unwrap() + .set_recipients(vec![ + ( + script::Builder::new().into_script(), + output_value / options.output_count as u64 + ); + options.output_count + ]); + + builder.finish()? }; - self.bitcoind.client.send_raw_transaction(&tx)?; + if !self.wallet.sign(&mut psbt, SignOptions::default())? { + panic!("Failed to sign transaction"); + } + + self + .bitcoind + .client + .send_raw_transaction(&psbt.extract_tx())?; } } } + // for (b, block) in self.blocks().enumerate() { // for (t, transaction) in block.txdata.iter().enumerate() { // eprintln!("{b}.{t}: {}", transaction.txid()); @@ -331,8 +398,10 @@ impl<'a> Test<'a> { for event in &self.events { match event { Event::Block => { - eprintln!("mining block !"); - self.bitcoind.client.generate_to_address(1, &self.address)?; + self.bitcoind.client.generate_to_address( + 1, + &self.wallet.get_address(AddressIndex::LastUnused)?.address, + )?; } Event::Request(request, status, expected_response) => { let response = client diff --git a/tests/list.rs b/tests/list.rs index 15c99b2e9c..14234950c3 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -11,22 +11,12 @@ fn first_coinbase_transaction() -> Result { #[test] fn second_coinbase_transaction() -> Result { Test::new()? - .command("list 104a8ee40f039ba83ceda9de4c6eb7d8587704168f687b315974d307c93b9caf:0") + .command("list 150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0") .block() .expected_stdout("[5000000000,10000000000)\n") .run() } -#[test] -fn third_coinbase_transaction_is_not_duplicate() -> Result { - Test::new()? - .command("list 4e99453697da6fb20ac8cd75113aa56a3e52c341c4bc4a9f8eabfb50a1c1ae70:0") - .block() - .block() - .expected_stdout("[10000000000,15000000000)\n") - .run() -} - #[test] fn split_ranges_are_tracked_correctly() -> Result { Test::new()? From 6cfd1f4de1620be14df028ff965bf50e0bb589e3 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 27 Jul 2022 16:16:27 -0400 Subject: [PATCH 09/61] Cleanup --- Cargo.lock | 356 +++++++------------------------------------- Cargo.toml | 7 +- src/index.rs | 4 +- tests/index.rs | 4 +- tests/lib.rs | 18 +-- tests/rpc_server.rs | 87 ----------- 6 files changed, 58 insertions(+), 418 deletions(-) delete mode 100644 tests/rpc_server.rs diff --git a/Cargo.lock b/Cargo.lock index b16dce6a8a..9041fabec7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,7 +107,7 @@ dependencies = [ "matchit", "memchr", "mime", - "percent-encoding 2.1.0", + "percent-encoding", "pin-project-lite", "serde", "serde_json", @@ -157,7 +157,7 @@ checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide 0.5.3", "object", @@ -311,8 +311,6 @@ dependencies = [ [[package]] name = "bitcoind" version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0831b9721892ce845a6acadd111311bee84f9e1cc0c5017b8213ec4437ccdfe2" dependencies = [ "bitcoin_hashes 0.10.0", "bitcoincore-rpc", @@ -380,12 +378,6 @@ version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -494,7 +486,7 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" dependencies = [ - "percent-encoding 2.1.0", + "percent-encoding", "time 0.2.27", "version_check", ] @@ -506,13 +498,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3" dependencies = [ "cookie", - "idna 0.2.1", + "idna", "log", "publicsuffix", "serde", "serde_json", "time 0.2.27", - "url 2.2.2", + "url", ] [[package]] @@ -537,7 +529,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -582,7 +574,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] @@ -592,7 +584,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] @@ -604,7 +596,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" dependencies = [ "autocfg 1.1.0", - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", "memoffset", "once_cell", @@ -617,7 +609,7 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", ] @@ -729,7 +721,7 @@ version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -803,7 +795,7 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "winapi", @@ -815,7 +807,7 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crc32fast", "libc", "miniz_oxide 0.4.4", @@ -862,7 +854,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", - "percent-encoding 2.1.0", + "percent-encoding", ] [[package]] @@ -881,27 +873,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -[[package]] -name = "futures" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" - -[[package]] -name = "futures" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.21" @@ -909,7 +880,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", - "futures-sink", ] [[package]] @@ -918,35 +888,12 @@ version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" -[[package]] -name = "futures-executor" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", - "num_cpus", -] - [[package]] name = "futures-io" version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" -[[package]] -name = "futures-macro" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "futures-sink" version = "0.3.21" @@ -965,12 +912,8 @@ version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ - "futures 0.1.31", - "futures-channel", "futures-core", "futures-io", - "futures-macro", - "futures-sink", "futures-task", "memchr", "pin-project-lite", @@ -993,7 +936,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", @@ -1006,7 +949,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -1029,19 +972,6 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" -[[package]] -name = "globset" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - [[package]] name = "h2" version = "0.3.13" @@ -1057,7 +987,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.7.3", + "tokio-util", "tracing", ] @@ -1213,17 +1143,6 @@ dependencies = [ "tokio-native-tls", ] -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.2.1" @@ -1279,7 +1198,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1339,108 +1258,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "jsonrpc-client-transports" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a" -dependencies = [ - "derive_more", - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-pubsub", - "log", - "serde", - "serde_json", - "url 1.7.2", -] - -[[package]] -name = "jsonrpc-core" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" -dependencies = [ - "futures 0.3.21", - "futures-executor", - "futures-util", - "log", - "serde", - "serde_derive", - "serde_json", -] - -[[package]] -name = "jsonrpc-core-client" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0" -dependencies = [ - "futures 0.3.21", - "jsonrpc-client-transports", -] - -[[package]] -name = "jsonrpc-derive" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b939a78fa820cdfcb7ee7484466746a7377760970f6f9c6fe19f9edcc8a38d2" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "jsonrpc-http-server" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff" -dependencies = [ - "futures 0.3.21", - "hyper", - "jsonrpc-core", - "jsonrpc-server-utils", - "log", - "net2", - "parking_lot", - "unicase", -] - -[[package]] -name = "jsonrpc-pubsub" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011" -dependencies = [ - "futures 0.3.21", - "jsonrpc-core", - "lazy_static", - "log", - "parking_lot", - "rand 0.7.3", - "serde", -] - -[[package]] -name = "jsonrpc-server-utils" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4" -dependencies = [ - "bytes", - "futures 0.3.21", - "globset", - "jsonrpc-core", - "lazy_static", - "log", - "tokio", - "tokio-stream", - "tokio-util 0.6.10", - "unicase", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -1485,7 +1302,7 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1595,17 +1412,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "net2" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi", -] - [[package]] name = "nix" version = "0.24.2" @@ -1613,7 +1419,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" dependencies = [ "bitflags", - "cfg-if 1.0.0", + "cfg-if", "libc", "memoffset", ] @@ -1686,7 +1492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0" dependencies = [ "bitflags", - "cfg-if 1.0.0", + "cfg-if", "foreign-types", "libc", "once_cell", @@ -1747,11 +1553,6 @@ dependencies = [ "executable-path", "hex", "http", - "jsonrpc", - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", - "jsonrpc-http-server", "lazy_static", "log", "nix", @@ -1792,7 +1593,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "instant", "libc", "redox_syscall", @@ -1800,12 +1601,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - [[package]] name = "percent-encoding" version = "2.1.0" @@ -1896,15 +1691,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1951,10 +1737,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" dependencies = [ "error-chain", - "idna 0.2.1", + "idna", "lazy_static", "regex", - "url 2.2.2", + "url", ] [[package]] @@ -1990,7 +1776,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" dependencies = [ - "percent-encoding 2.1.0", + "percent-encoding", ] [[package]] @@ -2266,7 +2052,7 @@ dependencies = [ "log", "mime", "native-tls", - "percent-encoding 2.1.0", + "percent-encoding", "pin-project-lite", "serde", "serde_json", @@ -2274,7 +2060,7 @@ dependencies = [ "tokio", "tokio-native-tls", "tower-service", - "url 2.2.2", + "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -2729,7 +2515,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "libc", "redox_syscall", @@ -2862,9 +2648,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57aec3cfa4c296db7255446efb4928a6be304b431a806216105542a67b6ca82e" +checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" dependencies = [ "autocfg 1.1.0", "bytes", @@ -2900,36 +2686,11 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-stream" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" -version = "0.7.3" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c" dependencies = [ "bytes", "futures-core", @@ -2939,15 +2700,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "toml" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" -dependencies = [ - "serde", -] - [[package]] name = "tower" version = "0.4.13" @@ -3001,12 +2753,24 @@ version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.28" @@ -3022,15 +2786,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.8" @@ -3084,22 +2839,11 @@ dependencies = [ "once_cell", "qstring", "rustls 0.19.1", - "url 2.2.2", + "url", "webpki 0.21.4", "webpki-roots 0.21.1", ] -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna 0.1.5", - "matches", - "percent-encoding 1.0.1", -] - [[package]] name = "url" version = "2.2.2" @@ -3107,9 +2851,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", - "idna 0.2.1", + "idna", "matches", - "percent-encoding 2.1.0", + "percent-encoding", ] [[package]] @@ -3175,7 +2919,7 @@ version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] @@ -3200,7 +2944,7 @@ version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", diff --git a/Cargo.toml b/Cargo.toml index a144e45c42..26af56d093 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ dirs = "4.0.0" env_logger = "0.9.0" executable-path = "1.0.0" http = "0.2.6" -jsonrpc = "0.12.1" lazy_static = "1.4.0" log = "0.4.14" qrcode-generator = "4.1.6" @@ -37,13 +36,9 @@ tokio = { version = "1.17.0", features = ["rt-multi-thread"] } tower-http = { version = "0.3.3", features = ["cors"] } [dev-dependencies] -bitcoind = { version = "0.26.1", features = ["22_0"] } +bitcoind = { path = "../bitcoind", features = ["23_0"] } criterion = "0.3.5" hex = "0.4.3" -jsonrpc-core = "18.0.0" -jsonrpc-core-client = "18.0.0" -jsonrpc-derive = "18.0.0" -jsonrpc-http-server = "18.0.0" nix = "0.24.1" regex = "1.5.4" reqwest = { version = "0.11.9", features = ["blocking"] } diff --git a/src/index.rs b/src/index.rs index f3902a65f4..bd213e18d4 100644 --- a/src/index.rs +++ b/src/index.rs @@ -293,8 +293,8 @@ impl Index { pub(crate) fn block(&self, height: u64) -> Result> { match self.client.get_block_hash(height) { Ok(hash) => Ok(Some(self.client.get_block(&hash)?)), - Err(bitcoincore_rpc::Error::JsonRpc(jsonrpc::error::Error::Rpc( - jsonrpc::error::RpcError { code: -8, .. }, + Err(bitcoincore_rpc::Error::JsonRpc(bitcoincore_rpc::jsonrpc::error::Error::Rpc( + bitcoincore_rpc::jsonrpc::error::RpcError { code: -8, .. }, ))) => Ok(None), Err(err) => Err(err.into()), } diff --git a/tests/index.rs b/tests/index.rs index dc3739e425..c237af2769 100644 --- a/tests/index.rs +++ b/tests/index.rs @@ -8,7 +8,7 @@ fn incremental_indexing() -> Result { .block() .output()?; - assert_eq!(output.calls, &["getblockhash", "getblock", "getblockhash"]); + // assert_eq!(output.calls, &["getblockhash", "getblock", "getblockhash"]); let output = Test::with_tempdir(output.tempdir)? .command("list 9068a11b8769174363376b606af9a4b8b29dd7b13d013f4b0cbbd457db3c3ce5:0") @@ -17,7 +17,7 @@ fn incremental_indexing() -> Result { .block() .output()?; - assert_eq!(output.calls, &["getblockhash", "getblock", "getblockhash"]); + // assert_eq!(output.calls, &["getblockhash", "getblock", "getblockhash"]); Ok(()) } diff --git a/tests/lib.rs b/tests/lib.rs index 3488d24a5e..790a395a9a 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,7 +1,6 @@ #![allow(clippy::type_complexity)] use { - crate::rpc_server::RpcServer, bdk::{ bitcoin::secp256k1::Secp256k1, blockchain::{ @@ -65,7 +64,6 @@ mod list; mod name; mod nft; mod range; -mod rpc_server; mod server; mod supply; mod traits; @@ -87,7 +85,6 @@ enum Event<'a> { } struct Output { - calls: Vec, stdout: String, tempdir: TempDir, } @@ -127,7 +124,9 @@ impl<'a> Test<'a> { conf.view_stdout = true; - let bitcoind = Bitcoind::with_conf(bitcoind::downloaded_exe_path()?, &conf)?; + eprintln!("{}", bitcoind::downloaded_exe_path()?); + + let bitcoind = Bitcoind::with_conf("bitcoind", &conf)?; let block = bitcoind .client @@ -337,12 +336,6 @@ impl<'a> Test<'a> { // } // } - let (blocks, close_handle, calls, rpc_server_port) = if port.is_some() { - RpcServer::spawn(Vec::new()) - } else { - RpcServer::spawn(Vec::new()) - }; - let child = Command::new(executable_path("ord")) .envs(self.envs.clone()) .stdin(Stdio::null()) @@ -458,8 +451,6 @@ impl<'a> Test<'a> { let output = child.wait_with_output()?; - close_handle.close(); - let stdout = str::from_utf8(&output.stdout)?; let stderr = str::from_utf8(&output.stderr)?; @@ -508,12 +499,9 @@ impl<'a> Test<'a> { "Unsuccessful requests" ); - let calls = calls.lock().unwrap().clone(); - Ok(Output { stdout: stdout.to_string(), tempdir: self.tempdir, - calls, }) } diff --git a/tests/rpc_server.rs b/tests/rpc_server.rs deleted file mode 100644 index e3ea298702..0000000000 --- a/tests/rpc_server.rs +++ /dev/null @@ -1,87 +0,0 @@ -use { - super::*, jsonrpc_core::IoHandler, jsonrpc_core::Result, jsonrpc_derive::rpc, - jsonrpc_http_server::CloseHandle, jsonrpc_http_server::ServerBuilder, -}; - -#[rpc] -pub trait RpcApi { - #[rpc(name = "getblockhash")] - fn getblockhash(&self, height: usize) -> Result; - - #[rpc(name = "getblock")] - fn getblock(&self, blockhash: BlockHash, verbosity: u64) -> Result; -} - -pub struct RpcServer { - blocks: Arc>>, - calls: Arc>>, -} - -impl RpcServer { - pub(crate) fn spawn( - blocks: Vec, - ) -> ( - Arc>>, - CloseHandle, - Arc>>, - u16, - ) { - let calls = Arc::new(Mutex::new(Vec::new())); - - let blocks = Arc::new(Mutex::new(blocks)); - - let server = Self { - blocks: blocks.clone(), - calls: calls.clone(), - }; - - let mut io = IoHandler::default(); - io.extend_with(server.to_delegate()); - - let server = ServerBuilder::new(io) - .threads(1) - .start_http(&"127.0.0.1:0".parse().unwrap()) - .unwrap(); - - let close_handle = server.close_handle(); - - let port = server.address().port(); - - thread::spawn(|| server.wait()); - - (blocks, close_handle, calls, port) - } - - fn call(&self, method: &str) { - self.calls.lock().unwrap().push(method.into()); - } -} - -impl RpcApi for RpcServer { - fn getblockhash(&self, height: usize) -> Result { - self.call("getblockhash"); - - match self.blocks.lock().unwrap().get(height) { - Some(block) => Ok(block.block_hash()), - None => Err(jsonrpc_core::Error::new( - jsonrpc_core::types::error::ErrorCode::ServerError(-8), - )), - } - } - - fn getblock(&self, blockhash: BlockHash, verbosity: u64) -> Result { - self.call("getblock"); - - assert_eq!(verbosity, 0, "Verbosity level {verbosity} is unsupported"); - - for block in self.blocks.lock().unwrap().iter() { - if block.block_hash() == blockhash { - let mut encoded = Vec::new(); - block.consensus_encode(&mut encoded).unwrap(); - return Ok(hex::encode(encoded)); - } - } - - panic!("No block with hash {blockhash}") - } -} From 6e6b1d094778c5d58789c15a1e002f8a8260c45a Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 27 Jul 2022 18:13:10 -0400 Subject: [PATCH 10/61] Semi-working --- src/index.rs | 2 +- tests/lib.rs | 87 +++++++++++++++++++++++++++++++++------------------ tests/list.rs | 3 +- 3 files changed, 59 insertions(+), 33 deletions(-) diff --git a/src/index.rs b/src/index.rs index bd213e18d4..4a4e8efe80 100644 --- a/src/index.rs +++ b/src/index.rs @@ -245,7 +245,7 @@ impl Index { input_ordinal_ranges: &mut VecDeque<(u64, u64)>, ordinal_ranges_written: &mut u64, ) -> Result { - log::trace!("TRANSACTION: {txid}: {:?}", tx); + log::trace!("{txid}: {:?}", tx); for (vout, output) in tx.output.iter().enumerate() { let outpoint = OutPoint { diff --git a/tests/lib.rs b/tests/lib.rs index 790a395a9a..e0646be0c8 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -5,7 +5,7 @@ use { bitcoin::secp256k1::Secp256k1, blockchain::{ rpc::{Auth, RpcBlockchain, RpcConfig}, - ConfigurableBlockchain, LogProgress, + Blockchain, ConfigurableBlockchain, LogProgress, }, database::MemoryDatabase, keys::{ @@ -25,7 +25,6 @@ use { network::constants::Network, Block, BlockHash, BlockHeader, OutPoint, Transaction, TxIn, TxOut, Witness, }, - core::str::FromStr, bitcoind::{ bitcoincore_rpc::{ bitcoin::{Address, Amount}, @@ -33,6 +32,7 @@ use { }, BitcoinD as Bitcoind, }, + core::str::FromStr, executable_path::executable_path, nix::{ sys::signal::{self, Signal}, @@ -98,6 +98,7 @@ struct TransactionOptions<'a> { struct Test<'a> { args: Vec, bitcoind: Bitcoind, + blockchain: RpcBlockchain, envs: Vec<(OsString, OsString)>, events: Vec>, expected_status: i32, @@ -120,20 +121,14 @@ impl<'a> Test<'a> { } fn with_tempdir(tempdir: TempDir) -> Result { - let mut conf = bitcoind::Conf::default(); + env_logger::init(); - conf.view_stdout = true; + let mut conf = bitcoind::Conf::default(); - eprintln!("{}", bitcoind::downloaded_exe_path()?); + conf.view_stdout = false; let bitcoind = Bitcoind::with_conf("bitcoind", &conf)?; - let block = bitcoind - .client - .get_block(&bitcoind.client.get_block_hash(0)?)?; - - dbg!(block); - let wallet = Wallet::new( Bip84(Self::get_key()?, KeychainKind::External), None, @@ -141,24 +136,22 @@ impl<'a> Test<'a> { MemoryDatabase::new(), )?; - wallet.sync( - &RpcBlockchain::from_config(&RpcConfig { - url: bitcoind.params.rpc_socket.to_string(), - auth: Auth::Cookie { - file: bitcoind.params.cookie_file.clone() - }, - network: Network::Regtest, - wallet_name: "test".to_string(), - skip_blocks: None, - })?, - SyncOptions { - progress: Some(Box::new(LogProgress)), + let blockchain = RpcBlockchain::from_config(&RpcConfig { + url: bitcoind.params.rpc_socket.to_string(), + auth: Auth::Cookie { + file: bitcoind.params.cookie_file.clone(), }, - )?; + network: Network::Regtest, + wallet_name: "test".to_string(), + skip_blocks: None, + })?; + + wallet.sync(&blockchain, SyncOptions::default())?; Ok(Self { args: Vec::new(), bitcoind, + blockchain, envs: Vec::new(), events: Vec::new(), expected_status: 0, @@ -271,6 +264,33 @@ impl<'a> Test<'a> { Ok(block) } + fn sync(&self) -> Result { + self.wallet.sync( + &RpcBlockchain::from_config(&RpcConfig { + url: self.bitcoind.params.rpc_socket.to_string(), + auth: Auth::Cookie { + file: self.bitcoind.params.cookie_file.clone(), + }, + network: Network::Regtest, + wallet_name: "test".to_string(), + skip_blocks: None, + })?, + SyncOptions { + progress: Some(Box::new(LogProgress)), + }, + )?; + + Ok(()) + } + + fn blocks(mut self, n: u64) -> Self { + for _ in 0..n { + self.events.push(Event::Block); + } + + self + } + fn test(self, port: Option) -> Result { for event in &self.events { match event { @@ -279,11 +299,15 @@ impl<'a> Test<'a> { .bitcoind .client .generate_to_address(1, &self.wallet.get_address(AddressIndex::Peek(0))?.address)?; + + self.sync()?; } Event::Request(request, status, expected_response) => { panic!() } Event::Transaction(options) => { + self.sync()?; + let input_value = options .slots .iter() @@ -300,9 +324,13 @@ impl<'a> Test<'a> { &options .slots .iter() - .map(|slot| OutPoint { - txid: self.get_block(slot.0 as u64).unwrap().txdata[slot.1].txid(), - vout: slot.2 as u32, + .map(|slot| { + let tx = &self.get_block(slot.0 as u64).unwrap().txdata[slot.1]; + dbg!(tx.txid(), tx.wtxid()); + OutPoint { + txid: tx.txid(), + vout: slot.2 as u32, + } }) .collect::>(), ) @@ -322,10 +350,7 @@ impl<'a> Test<'a> { panic!("Failed to sign transaction"); } - self - .bitcoind - .client - .send_raw_transaction(&psbt.extract_tx())?; + self.blockchain.broadcast(&psbt.extract_tx())?; } } } diff --git a/tests/list.rs b/tests/list.rs index 14234950c3..b00f336ca5 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -23,8 +23,9 @@ fn split_ranges_are_tracked_correctly() -> Result { .command("list 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0") .block() .block() + .blocks(100) .transaction(TransactionOptions { - slots: &[(0, 0, 0)], + slots: &[(1, 0, 0)], output_count: 2, fee: 0, }) From 1fdbc82c2342fc87f3991f43fed798646b83f89b Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 27 Jul 2022 18:17:35 -0400 Subject: [PATCH 11/61] Clearer output --- tests/index.rs | 2 +- tests/lib.rs | 29 ++++++----------------------- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/tests/index.rs b/tests/index.rs index c237af2769..4418d3b31b 100644 --- a/tests/index.rs +++ b/tests/index.rs @@ -10,7 +10,7 @@ fn incremental_indexing() -> Result { // assert_eq!(output.calls, &["getblockhash", "getblock", "getblockhash"]); - let output = Test::with_tempdir(output.tempdir)? + let _output = Test::with_tempdir(output.tempdir)? .command("list 9068a11b8769174363376b606af9a4b8b29dd7b13d013f4b0cbbd457db3c3ce5:0") .expected_stdout("[5000000000,10000000000)\n") .block() diff --git a/tests/lib.rs b/tests/lib.rs index e0646be0c8..80586d90c3 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -2,37 +2,22 @@ use { bdk::{ - bitcoin::secp256k1::Secp256k1, blockchain::{ rpc::{Auth, RpcBlockchain, RpcConfig}, Blockchain, ConfigurableBlockchain, LogProgress, }, database::MemoryDatabase, - keys::{ - bip39::{Language, Mnemonic, WordCount}, - DerivableKey, GeneratableKey, - }, + keys::{bip39::Mnemonic, DerivableKey}, miniscript::miniscript::Segwitv0, template::Bip84, - wallet::{ - signer::SignOptions, wallet_name_from_descriptor, AddressIndex, AddressIndex::LastUnused, - SyncOptions, Wallet, - }, + wallet::{signer::SignOptions, AddressIndex, SyncOptions, Wallet}, KeychainKind, }, bitcoin::{ - blockdata::constants::COIN_VALUE, blockdata::script, consensus::Encodable, - network::constants::Network, Block, BlockHash, BlockHeader, OutPoint, Transaction, TxIn, TxOut, + blockdata::script, network::constants::Network, Block, OutPoint, Transaction, TxIn, TxOut, Witness, }, - bitcoind::{ - bitcoincore_rpc::{ - bitcoin::{Address, Amount}, - RpcApi, - }, - BitcoinD as Bitcoind, - }, - core::str::FromStr, + bitcoind::{bitcoincore_rpc::RpcApi, BitcoinD as Bitcoind}, executable_path::executable_path, nix::{ sys::signal::{self, Signal}, @@ -45,11 +30,9 @@ use { ffi::OsString, fs, net::TcpListener, - path::PathBuf, process::{Command, Stdio}, str, - sync::{Arc, Mutex}, - thread::{self, sleep}, + thread::sleep, time::{Duration, Instant}, }, tempfile::TempDir, @@ -302,7 +285,7 @@ impl<'a> Test<'a> { self.sync()?; } - Event::Request(request, status, expected_response) => { + Event::Request(_request, _status, _expected_response) => { panic!() } Event::Transaction(options) => { From be6fb0e0d29112f77cd8e676e5b3b26279222f0b Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 27 Jul 2022 18:50:32 -0400 Subject: [PATCH 12/61] Get first part of split_ranges_are_tracked_correctly working --- tests/lib.rs | 33 +++++++++++++++++++-------------- tests/list.rs | 29 +++++++++++++++-------------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/tests/lib.rs b/tests/lib.rs index 80586d90c3..3ef289cdeb 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -109,6 +109,8 @@ impl<'a> Test<'a> { let mut conf = bitcoind::Conf::default(); conf.view_stdout = false; + conf.args.push("-minrelaytxfee=0"); + conf.args.push("-blockmintxfee=0"); let bitcoind = Bitcoind::with_conf("bitcoind", &conf)?; @@ -275,6 +277,8 @@ impl<'a> Test<'a> { } fn test(self, port: Option) -> Result { + let mut height = 0; + for event in &self.events { match event { Event::Block => { @@ -283,6 +287,12 @@ impl<'a> Test<'a> { .client .generate_to_address(1, &self.wallet.get_address(AddressIndex::Peek(0))?.address)?; + height += 1; + + for (t, transaction) in self.get_block(height)?.txdata.iter().enumerate() { + eprintln!("{height}.{t}: {}", transaction.txid()); + } + self.sync()?; } Event::Request(_request, _status, _expected_response) => { @@ -303,6 +313,8 @@ impl<'a> Test<'a> { let mut builder = self.wallet.build_tx(); builder + .manually_selected_only() + .fee_absolute(0) .add_utxos( &options .slots @@ -316,11 +328,14 @@ impl<'a> Test<'a> { } }) .collect::>(), - ) - .unwrap() + )? .set_recipients(vec![ ( - script::Builder::new().into_script(), + self + .wallet + .get_address(AddressIndex::Peek(0))? + .address + .script_pubkey(), output_value / options.output_count as u64 ); options.output_count @@ -333,17 +348,11 @@ impl<'a> Test<'a> { panic!("Failed to sign transaction"); } - self.blockchain.broadcast(&psbt.extract_tx())?; + self.blockchain.broadcast(dbg!(&psbt.extract_tx()))?; } } } - // for (b, block) in self.blocks().enumerate() { - // for (t, transaction) in block.txdata.iter().enumerate() { - // eprintln!("{b}.{t}: {}", transaction.txid()); - // } - // } - let child = Command::new(executable_path("ord")) .envs(self.envs.clone()) .stdin(Stdio::null()) @@ -367,8 +376,6 @@ impl<'a> Test<'a> { let mut successful_requests = 0; - dbg!(port); - if let Some(port) = port { let client = reqwest::blocking::Client::new(); @@ -393,8 +400,6 @@ impl<'a> Test<'a> { sleep(Duration::from_millis(100)); } - dbg!(healthy); - if healthy { for event in &self.events { match event { diff --git a/tests/list.rs b/tests/list.rs index b00f336ca5..023f2481b9 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -20,7 +20,8 @@ fn second_coinbase_transaction() -> Result { #[test] fn split_ranges_are_tracked_correctly() -> Result { Test::new()? - .command("list 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0") + .command("list bebb64fc274348e2033981e3935bf0cf30105deb1cc00d770b2e96dff7f31149:0") + // TODO: useless block generation .block() .block() .blocks(100) @@ -30,20 +31,20 @@ fn split_ranges_are_tracked_correctly() -> Result { fee: 0, }) .block() - .expected_stdout("[0,2500000000)\n") - .run()?; - - Test::new()? - .command("list 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0") - .block() - .block() - .transaction(TransactionOptions { - slots: &[(0, 0, 0)], - output_count: 2, - fee: 0, - }) - .expected_stdout("[2500000000,5000000000)\n") + .expected_stdout("[5000000000,7500000000)\n") .run() + + // Test::new()? + // .command("list 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0") + // .block() + // .block() + // .transaction(TransactionOptions { + // slots: &[(0, 0, 0)], + // output_count: 2, + // fee: 0, + // }) + // .expected_stdout("[2500000000,5000000000)\n") + // .run() } #[test] From 1ad4cc20ef41e31cd18566aabfc6c991fb7f2a96 Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 28 Jul 2022 14:55:32 -0400 Subject: [PATCH 13/61] Fix merge_ranges test --- tests/lib.rs | 14 ++++----- tests/list.rs | 79 +++++++++++++++++++++------------------------------ 2 files changed, 37 insertions(+), 56 deletions(-) diff --git a/tests/lib.rs b/tests/lib.rs index 3ef289cdeb..d1f892c475 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -104,7 +104,7 @@ impl<'a> Test<'a> { } fn with_tempdir(tempdir: TempDir) -> Result { - env_logger::init(); + // env_logger::init(); let mut conf = bitcoind::Conf::default(); @@ -319,13 +319,9 @@ impl<'a> Test<'a> { &options .slots .iter() - .map(|slot| { - let tx = &self.get_block(slot.0 as u64).unwrap().txdata[slot.1]; - dbg!(tx.txid(), tx.wtxid()); - OutPoint { - txid: tx.txid(), - vout: slot.2 as u32, - } + .map(|slot| OutPoint { + txid: self.get_block(slot.0 as u64).unwrap().txdata[slot.1].txid(), + vout: slot.2 as u32, }) .collect::>(), )? @@ -348,7 +344,7 @@ impl<'a> Test<'a> { panic!("Failed to sign transaction"); } - self.blockchain.broadcast(dbg!(&psbt.extract_tx()))?; + self.blockchain.broadcast(&psbt.extract_tx())?; } } } diff --git a/tests/list.rs b/tests/list.rs index 023f2481b9..66bf91c5fb 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -20,11 +20,8 @@ fn second_coinbase_transaction() -> Result { #[test] fn split_ranges_are_tracked_correctly() -> Result { Test::new()? - .command("list bebb64fc274348e2033981e3935bf0cf30105deb1cc00d770b2e96dff7f31149:0") - // TODO: useless block generation - .block() - .block() - .blocks(100) + .command("list 36b5e3d6454fdadf762e8adc28140bbf38ee673c68bf05aaac82add84c0ff862:0") + .blocks(101) .transaction(TransactionOptions { slots: &[(1, 0, 0)], output_count: 2, @@ -32,89 +29,77 @@ fn split_ranges_are_tracked_correctly() -> Result { }) .block() .expected_stdout("[5000000000,7500000000)\n") - .run() + .run()?; - // Test::new()? - // .command("list 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0") - // .block() - // .block() - // .transaction(TransactionOptions { - // slots: &[(0, 0, 0)], - // output_count: 2, - // fee: 0, - // }) - // .expected_stdout("[2500000000,5000000000)\n") - // .run() + Test::new()? + .command("list 36b5e3d6454fdadf762e8adc28140bbf38ee673c68bf05aaac82add84c0ff862:1") + .blocks(101) + .transaction(TransactionOptions { + slots: &[(1, 0, 0)], + output_count: 2, + fee: 0, + }) + .block() + .expected_stdout("[7500000000,10000000000)\n") + .run() } #[test] fn merge_ranges_are_tracked_correctly() -> Result { Test::new()? - .command("list db7d0407c1548d2ceb00fd37447dfe723b954cc69cd5cbfd6b020f667db807a2:0") - .block() - .block() + .command("list 430f77dcea637d90d82ac561f9f1955119c0d25b690da250ba98872e15e9069f:0") + .blocks(101) .transaction(TransactionOptions { - slots: &[(0, 0, 0)], + slots: &[(1, 0, 0)], output_count: 2, fee: 0, }) .block() .transaction(TransactionOptions { - slots: &[(1, 1, 0), (1, 1, 1)], + slots: &[(102, 1, 0), (102, 1, 1)], output_count: 1, fee: 0, }) - .expected_stdout("[0,2500000000)\n[2500000000,5000000000)\n") + .block() + .expected_stdout("[5000000000,7500000000)\n[7500000000,10000000000)\n") .run() } -// #[test] -// fn underpay_subsidy() -> Result { -// Test::new()? -// .command("list 12d57183977a1df616bafbb7dafbb4249e59d8f796ba556ad6bb75f0fa9fe0ea:0") -// .block_with_coinbase(CoinbaseOptions { -// subsidy: 50 * COIN_VALUE - 1, -// ..Default::default() -// }) -// .expected_stdout("[0,4999999999)\n") -// .run() -// } - #[test] fn fee_paying_transaction_range() -> Result { Test::new()? - .command("list fa8e9a127d8030727ce6f2190ddfd87d0910e3aa31985da529ee5c20ca120941:0") - .block() - .block() + .command("list 0e1565c54057e5480da52d9ea1a24dad4a31462ffc049ab701dd681fb06d2535:0") + .blocks(101) .transaction(TransactionOptions { - slots: &[(0, 0, 0)], + slots: &[(1, 0, 0)], output_count: 2, fee: 10, }) + .block() .expected_stdout("[0,2499999995)\n") .run()?; Test::new()? - .command("list fa8e9a127d8030727ce6f2190ddfd87d0910e3aa31985da529ee5c20ca120941:1") - .block() - .block() + .command("list 0e1565c54057e5480da52d9ea1a24dad4a31462ffc049ab701dd681fb06d2535:1") + .blocks(101) .transaction(TransactionOptions { - slots: &[(0, 0, 0)], + slots: &[(1, 0, 0)], output_count: 2, fee: 10, }) + .block() .expected_stdout("[2499999995,4999999990)\n") .run()?; Test::new()? - .command("list e99b3ae1f13c5335222148496220d36026c595861c916c297e3483188312c915:0") - .block() - .block() + .command("list 0e1565c54057e5480da52d9ea1a24dad4a31462ffc049ab701dd681fb06d2535:0") + .blocks(101) .transaction(TransactionOptions { - slots: &[(0, 0, 0)], + slots: &[(1, 0, 0)], output_count: 2, fee: 10, }) + .block() .expected_stdout("[5000000000,10000000000)\n[4999999990,5000000000)\n") .run() } From 041695d5b8f4ec2be23854fc8d256e761ceee247 Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 28 Jul 2022 17:10:35 -0400 Subject: [PATCH 14/61] Fix fee_paying_transaction_range --- tests/list.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/list.rs b/tests/list.rs index 66bf91c5fb..ab066ab339 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -68,7 +68,7 @@ fn merge_ranges_are_tracked_correctly() -> Result { #[test] fn fee_paying_transaction_range() -> Result { Test::new()? - .command("list 0e1565c54057e5480da52d9ea1a24dad4a31462ffc049ab701dd681fb06d2535:0") + .command("list a57ccabdca48ada30a5e58459584e43691a56f4fcc51121d8aa9bf1d1c682603:0") .blocks(101) .transaction(TransactionOptions { slots: &[(1, 0, 0)], @@ -76,11 +76,11 @@ fn fee_paying_transaction_range() -> Result { fee: 10, }) .block() - .expected_stdout("[0,2499999995)\n") + .expected_stdout("[5000000000,7499999995)\n") .run()?; Test::new()? - .command("list 0e1565c54057e5480da52d9ea1a24dad4a31462ffc049ab701dd681fb06d2535:1") + .command("list a57ccabdca48ada30a5e58459584e43691a56f4fcc51121d8aa9bf1d1c682603:1") .blocks(101) .transaction(TransactionOptions { slots: &[(1, 0, 0)], @@ -88,11 +88,11 @@ fn fee_paying_transaction_range() -> Result { fee: 10, }) .block() - .expected_stdout("[2499999995,4999999990)\n") + .expected_stdout("[7499999995,9999999990)\n") .run()?; Test::new()? - .command("list 0e1565c54057e5480da52d9ea1a24dad4a31462ffc049ab701dd681fb06d2535:0") + .command("list 721792011e3200abd01693490de5215b570da0048e55b66514201cb62396e376:0") .blocks(101) .transaction(TransactionOptions { slots: &[(1, 0, 0)], @@ -100,27 +100,27 @@ fn fee_paying_transaction_range() -> Result { fee: 10, }) .block() - .expected_stdout("[5000000000,10000000000)\n[4999999990,5000000000)\n") + .expected_stdout("[510000000000,515000000000)\n[9999999990,10000000000)\n") .run() } #[test] fn two_fee_paying_transaction_range() -> Result { Test::new()? - .command("list 1ed7b177c6886e33d987b15c41407b3b91afcdf211225902f37260678362794b:0") - .block() - .block() - .block() + .command("list 669a930de72f7a48e7ca2254fbf6ed056bc15e74dfedd484d02ea727e872c9db:0") + .blocks(101) .transaction(TransactionOptions { - slots: &[(0, 0, 0)], + slots: &[(1, 0, 0)], output_count: 2, fee: 10, }) + .block() .transaction(TransactionOptions { - slots: &[(1, 0, 0)], + slots: &[(102, 1, 0)], output_count: 2, fee: 10, }) + .block() .expected_stdout( "[10000000000,15000000000)\n[4999999990,5000000000)\n[9999999990,10000000000)\n", ) From 2868785f3c29ff96d4f5d495535c0c27c0fd7f5c Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 29 Jul 2022 11:51:05 -0400 Subject: [PATCH 15/61] Small refactors --- tests/lib.rs | 59 ++++++++++++++++++++++++++------------------------- tests/list.rs | 24 ++++++++++----------- 2 files changed, 41 insertions(+), 42 deletions(-) diff --git a/tests/lib.rs b/tests/lib.rs index d1f892c475..772bc9386d 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -7,8 +7,7 @@ use { Blockchain, ConfigurableBlockchain, LogProgress, }, database::MemoryDatabase, - keys::{bip39::Mnemonic, DerivableKey}, - miniscript::miniscript::Segwitv0, + keys::bip39::Mnemonic, template::Bip84, wallet::{signer::SignOptions, AddressIndex, SyncOptions, Wallet}, KeychainKind, @@ -32,6 +31,7 @@ use { net::TcpListener, process::{Command, Stdio}, str, + sync::Once, thread::sleep, time::{Duration, Instant}, }, @@ -55,6 +55,8 @@ mod wallet; type Result = std::result::Result>; +static ONCE: Once = Once::new(); + enum Expected { String(String), Regex(Regex), @@ -93,18 +95,13 @@ struct Test<'a> { impl<'a> Test<'a> { fn new() -> Result { - Ok(Self::with_tempdir(TempDir::new()?)?) - } - - fn get_key() -> Result + Clone> { - Ok(( - Mnemonic::parse("book fit fly ketchup also elevator scout mind edit fatal where rookie")?, - None, - )) + Self::with_tempdir(TempDir::new()?) } fn with_tempdir(tempdir: TempDir) -> Result { - // env_logger::init(); + ONCE.call_once(|| { + env_logger::init(); + }); let mut conf = bitcoind::Conf::default(); @@ -115,7 +112,13 @@ impl<'a> Test<'a> { let bitcoind = Bitcoind::with_conf("bitcoind", &conf)?; let wallet = Wallet::new( - Bip84(Self::get_key()?, KeychainKind::External), + Bip84( + ( + Mnemonic::parse("book fit fly ketchup also elevator scout mind edit fatal where rookie")?, + None, + ), + KeychainKind::External, + ), None, Network::Regtest, MemoryDatabase::new(), @@ -131,9 +134,7 @@ impl<'a> Test<'a> { skip_blocks: None, })?; - wallet.sync(&blockchain, SyncOptions::default())?; - - Ok(Self { + let test = Self { args: Vec::new(), bitcoind, blockchain, @@ -144,7 +145,11 @@ impl<'a> Test<'a> { expected_stdout: Expected::String(String::new()), tempdir, wallet, - }) + }; + + test.sync()?; + + Ok(test) } fn command(self, args: &str) -> Self { @@ -241,12 +246,12 @@ impl<'a> Test<'a> { } fn get_block(&self, height: u64) -> Result { - let block = self - .bitcoind - .client - .get_block(&self.bitcoind.client.get_block_hash(height)?)?; - - Ok(block) + Ok( + self + .bitcoind + .client + .get_block(&self.bitcoind.client.get_block_hash(height)?)?, + ) } fn sync(&self) -> Result { @@ -264,15 +269,13 @@ impl<'a> Test<'a> { progress: Some(Box::new(LogProgress)), }, )?; - Ok(()) } fn blocks(mut self, n: u64) -> Self { - for _ in 0..n { - self.events.push(Event::Block); - } - + self + .events + .extend((0..n).map(|_| Event::Block).collect::>()); self } @@ -299,8 +302,6 @@ impl<'a> Test<'a> { panic!() } Event::Transaction(options) => { - self.sync()?; - let input_value = options .slots .iter() diff --git a/tests/list.rs b/tests/list.rs index ab066ab339..8895b30514 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -130,14 +130,14 @@ fn two_fee_paying_transaction_range() -> Result { #[test] fn null_output() -> Result { Test::new()? - .command("list dbae83e031d45cb5cd9c41ba8030347c3965049792f508be1e5248c92e4cafd4:0") - .block() - .block() + .command("list 0e1565c54057e5480da52d9ea1a24dad4a31462ffc049ab701dd681fb06d2535:0") + .blocks(101) .transaction(TransactionOptions { - slots: &[(0, 0, 0)], + slots: &[(1, 0, 0)], output_count: 1, fee: 50 * 100_000_000, }) + .block() .expected_stdout("") .run() } @@ -145,17 +145,16 @@ fn null_output() -> Result { #[test] fn null_input() -> Result { Test::new()? - .command("list d14f4614fa016228ac097fd29b591703e68a2b9672bbdb59039dc953ff3e9714:0") - .block() - .block() + .command("list 0e1565c54057e5480da52d9ea1a24dad4a31462ffc049ab701dd681fb06d2535:0") + .blocks(101) .transaction(TransactionOptions { - slots: &[(0, 0, 0)], + slots: &[(1, 0, 0)], output_count: 1, fee: 50 * 100_000_000, }) .block() .transaction(TransactionOptions { - slots: &[(1, 1, 0)], + slots: &[(102, 1, 0)], output_count: 1, fee: 0, }) @@ -166,11 +165,10 @@ fn null_input() -> Result { #[test] fn old_transactions_are_pruned() -> Result { Test::new()? - .command("list 0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0") - .block() - .block() + .command("list 0e1565c54057e5480da52d9ea1a24dad4a31462ffc049ab701dd681fb06d2535:0") + .blocks(101) .transaction(TransactionOptions { - slots: &[(0, 0, 0)], + slots: &[(1, 0, 0)], output_count: 1, fee: 50 * 100_000_000, }) From 94f84fbc4dddf8402baf6e2a1dab92f61611f10d Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 29 Jul 2022 15:29:33 -0400 Subject: [PATCH 16/61] Fix null_output test --- Cargo.lock | 4 +--- Cargo.toml | 2 +- tests/lib.rs | 21 ++++++++++++++++----- tests/list.rs | 4 ++-- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9041fabec7..93a60d0100 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -187,9 +187,7 @@ dependencies = [ [[package]] name = "bdk" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a0becbf5a97855daca6717ff920c52a779cebf655b23ae1427e5366d2661e82" +version = "0.20.1-dev" dependencies = [ "ahash", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 26af56d093..2b36bf895e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ autotests = false anyhow = { version = "1.0.56", features = ["backtrace"] } axum = "0.5.6" axum-server = "0.4.0" -bdk = { version = "0.20.0", features = ["rpc", "keys-bip39", "sqlite"] } +bdk = { path = "../bdk", version = "0.20.1-dev", features = ["rpc", "keys-bip39", "sqlite"] } bech32 = "0.9.0" bitcoin = "0.28.1" bitcoin_hashes = "0.11.0" diff --git a/tests/lib.rs b/tests/lib.rs index 772bc9386d..277ec2cf1f 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -12,10 +12,12 @@ use { wallet::{signer::SignOptions, AddressIndex, SyncOptions, Wallet}, KeychainKind, }, + bitcoin::hash_types::Txid, bitcoin::{ blockdata::script, network::constants::Network, Block, OutPoint, Transaction, TxIn, TxOut, Witness, }, + bitcoincore_rpc::RawTx, bitcoind::{bitcoincore_rpc::RpcApi, BitcoinD as Bitcoind}, executable_path::executable_path, nix::{ @@ -108,6 +110,8 @@ impl<'a> Test<'a> { conf.view_stdout = false; conf.args.push("-minrelaytxfee=0"); conf.args.push("-blockmintxfee=0"); + conf.args.push("-dustrelayfee=0"); + conf.args.push("-maxtxfee=21000000"); let bitcoind = Bitcoind::with_conf("bitcoind", &conf)?; @@ -293,7 +297,7 @@ impl<'a> Test<'a> { height += 1; for (t, transaction) in self.get_block(height)?.txdata.iter().enumerate() { - eprintln!("{height}.{t}: {}", transaction.txid()); + log::info!("tx: {height}x{t}: {}", transaction.txid()); } self.sync()?; @@ -315,7 +319,8 @@ impl<'a> Test<'a> { builder .manually_selected_only() - .fee_absolute(0) + .fee_absolute(options.fee) + .allow_dust(true) .add_utxos( &options .slots @@ -325,7 +330,8 @@ impl<'a> Test<'a> { vout: slot.2 as u32, }) .collect::>(), - )? + ) + .unwrap() .set_recipients(vec![ ( self @@ -338,14 +344,19 @@ impl<'a> Test<'a> { options.output_count ]); - builder.finish()? + builder.finish().unwrap() }; if !self.wallet.sign(&mut psbt, SignOptions::default())? { panic!("Failed to sign transaction"); } - self.blockchain.broadcast(&psbt.extract_tx())?; + // self.blockchain.broadcast(dbg!(&psbt.extract_tx()))?; + + self.bitcoind.client.call::( + "sendrawtransaction", + &[dbg!(psbt.extract_tx()).raw_hex().into(), 21000000.into()], + )?; } } } diff --git a/tests/list.rs b/tests/list.rs index 8895b30514..2eae605306 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -107,7 +107,7 @@ fn fee_paying_transaction_range() -> Result { #[test] fn two_fee_paying_transaction_range() -> Result { Test::new()? - .command("list 669a930de72f7a48e7ca2254fbf6ed056bc15e74dfedd484d02ea727e872c9db:0") + .command("list fc37a02d47927a482b67934b9ecaaef687b632efe1a0a49738cd1c177fc3459f:0") .blocks(101) .transaction(TransactionOptions { slots: &[(1, 0, 0)], @@ -130,7 +130,7 @@ fn two_fee_paying_transaction_range() -> Result { #[test] fn null_output() -> Result { Test::new()? - .command("list 0e1565c54057e5480da52d9ea1a24dad4a31462ffc049ab701dd681fb06d2535:0") + .command("list 3dbc87de25bf5a52ddfa8038bda36e09622f4dec7951d81ac43e4b0e8c54bc5b:0") .blocks(101) .transaction(TransactionOptions { slots: &[(1, 0, 0)], From 01417c388a22793950ff0dc3cd3d042c1212ad2d Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 29 Jul 2022 15:43:43 -0400 Subject: [PATCH 17/61] Use git dependency --- Cargo.lock | 1 + Cargo.toml | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 93a60d0100..2677f7f6e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -188,6 +188,7 @@ dependencies = [ [[package]] name = "bdk" version = "0.20.1-dev" +source = "git+https://github.com/terror/bdk.git?branch=dust-limit#eccef3bdadb89dd1b3c0558b7f19bb67b9ae3311" dependencies = [ "ahash", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 2b36bf895e..50e8a445b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ autotests = false anyhow = { version = "1.0.56", features = ["backtrace"] } axum = "0.5.6" axum-server = "0.4.0" -bdk = { path = "../bdk", version = "0.20.1-dev", features = ["rpc", "keys-bip39", "sqlite"] } bech32 = "0.9.0" bitcoin = "0.28.1" bitcoin_hashes = "0.11.0" @@ -35,6 +34,12 @@ serde_json = "1.0.81" tokio = { version = "1.17.0", features = ["rt-multi-thread"] } tower-http = { version = "0.3.3", features = ["cors"] } +[dependencies.bdk] +git = "https://github.com/terror/bdk.git" +branch = "dust-limit" +version = "0.20.1-dev" +features = ["rpc", "keys-bip39", "sqlite"] + [dev-dependencies] bitcoind = { path = "../bitcoind", features = ["23_0"] } criterion = "0.3.5" From c9fc0170045a044a09cea6cb2bdbc2bcb6e0c2a8 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 29 Jul 2022 16:48:21 -0400 Subject: [PATCH 18/61] Fix two_fee test --- tests/lib.rs | 4 ++-- tests/list.rs | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/lib.rs b/tests/lib.rs index 277ec2cf1f..13cd0c1f0e 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -306,6 +306,8 @@ impl<'a> Test<'a> { panic!() } Event::Transaction(options) => { + self.sync()?; + let input_value = options .slots .iter() @@ -351,8 +353,6 @@ impl<'a> Test<'a> { panic!("Failed to sign transaction"); } - // self.blockchain.broadcast(dbg!(&psbt.extract_tx()))?; - self.bitcoind.client.call::( "sendrawtransaction", &[dbg!(psbt.extract_tx()).raw_hex().into(), 21000000.into()], diff --git a/tests/list.rs b/tests/list.rs index 2eae605306..e77d81a8fa 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -107,22 +107,21 @@ fn fee_paying_transaction_range() -> Result { #[test] fn two_fee_paying_transaction_range() -> Result { Test::new()? - .command("list fc37a02d47927a482b67934b9ecaaef687b632efe1a0a49738cd1c177fc3459f:0") - .blocks(101) + .command("list 7f3b38a0bc60f581fd7f4b178ca2a697575000e212c8752b455ec134d160ea9a:0") + .blocks(102) .transaction(TransactionOptions { slots: &[(1, 0, 0)], - output_count: 2, + output_count: 1, fee: 10, }) - .block() .transaction(TransactionOptions { - slots: &[(102, 1, 0)], - output_count: 2, + slots: &[(2, 0, 0)], + output_count: 1, fee: 10, }) .block() .expected_stdout( - "[10000000000,15000000000)\n[4999999990,5000000000)\n[9999999990,10000000000)\n", + "[515000000000,520000000000)\n[9999999990,10000000000)\n[14999999990,15000000000)\n", ) .run() } From 380c647ae1826693d9b0296389f25323365ef037 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 29 Jul 2022 17:07:48 -0400 Subject: [PATCH 19/61] Fix null_input test --- tests/list.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/list.rs b/tests/list.rs index e77d81a8fa..cc33cd0f45 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -144,7 +144,7 @@ fn null_output() -> Result { #[test] fn null_input() -> Result { Test::new()? - .command("list 0e1565c54057e5480da52d9ea1a24dad4a31462ffc049ab701dd681fb06d2535:0") + .command("list 3dbc87de25bf5a52ddfa8038bda36e09622f4dec7951d81ac43e4b0e8c54bc5b:0") .blocks(101) .transaction(TransactionOptions { slots: &[(1, 0, 0)], From 5aa0cde514988ff537533a9fbe505b1697c828e3 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 29 Jul 2022 17:17:00 -0400 Subject: [PATCH 20/61] Get all list tests to pass invidiually --- tests/lib.rs | 19 ++----------------- tests/list.rs | 3 ++- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/tests/lib.rs b/tests/lib.rs index 13cd0c1f0e..d8d114706d 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -4,7 +4,7 @@ use { bdk::{ blockchain::{ rpc::{Auth, RpcBlockchain, RpcConfig}, - Blockchain, ConfigurableBlockchain, LogProgress, + ConfigurableBlockchain, }, database::MemoryDatabase, keys::bip39::Mnemonic, @@ -259,20 +259,7 @@ impl<'a> Test<'a> { } fn sync(&self) -> Result { - self.wallet.sync( - &RpcBlockchain::from_config(&RpcConfig { - url: self.bitcoind.params.rpc_socket.to_string(), - auth: Auth::Cookie { - file: self.bitcoind.params.cookie_file.clone(), - }, - network: Network::Regtest, - wallet_name: "test".to_string(), - skip_blocks: None, - })?, - SyncOptions { - progress: Some(Box::new(LogProgress)), - }, - )?; + self.wallet.sync(&self.blockchain, SyncOptions::default())?; Ok(()) } @@ -306,8 +293,6 @@ impl<'a> Test<'a> { panic!() } Event::Transaction(options) => { - self.sync()?; - let input_value = options .slots .iter() diff --git a/tests/list.rs b/tests/list.rs index cc33cd0f45..5fc189e32e 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -164,13 +164,14 @@ fn null_input() -> Result { #[test] fn old_transactions_are_pruned() -> Result { Test::new()? - .command("list 0e1565c54057e5480da52d9ea1a24dad4a31462ffc049ab701dd681fb06d2535:0") + .command("list 150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0") .blocks(101) .transaction(TransactionOptions { slots: &[(1, 0, 0)], output_count: 1, fee: 50 * 100_000_000, }) + .block() .expected_stderr("error: Output not found\n") .expected_status(1) .run() From c8cc1df2fd7f4ca5a4ab989165801e6fe3c24938 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 29 Jul 2022 18:16:56 -0400 Subject: [PATCH 21/61] Fix find tests --- tests/find.rs | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/tests/find.rs b/tests/find.rs index c712f74d70..772075c5c5 100644 --- a/tests/find.rs +++ b/tests/find.rs @@ -40,8 +40,8 @@ fn second_satoshi_slot() -> Result { fn first_satoshi_of_second_block() -> Result { Test::new()? .command("find 5000000000") - .expected_stdout("104a8ee40f039ba83ceda9de4c6eb7d8587704168f687b315974d307c93b9caf:0:0\n") .block() + .expected_stdout("150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0:0\n") .run() } @@ -60,14 +60,14 @@ fn first_satoshi_of_second_block_slot() -> Result { fn first_satoshi_spent_in_second_block() -> Result { Test::new()? .command("find 0") - .expected_stdout("d0a9c70e6c8d890ee5883973a716edc1609eab42a9bc32594bdafc935bb4fad0:0:0\n") - .block() - .block() + .blocks(101) .transaction(TransactionOptions { - slots: &[(0, 0, 0)], + slots: &[(1, 0, 0)], output_count: 1, fee: 0, }) + .block() + .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") .run() } @@ -87,20 +87,6 @@ fn first_satoshi_spent_in_second_block_slot() -> Result { .run() } -// #[test] -// #[ignore] -// fn regression_empty_block_crash() -> Result { -// Test::new()? -// .command("find 0 --slot") -// .block() -// .block_with_coinbase(CoinbaseOptions { -// include_coinbase_transaction: false, -// ..Default::default() -// }) -// .expected_stdout("0x0x0x0\n") -// .run() -// } - #[test] #[ignore] fn mining_and_spending_transaction_in_same_block() -> Result { From f106d2a024727d772eb11b9e234bcfdae4d5c12a Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 29 Jul 2022 18:31:21 -0400 Subject: [PATCH 22/61] Fix info and index tests --- tests/index.rs | 26 ++------------------------ tests/info.rs | 2 +- 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/tests/index.rs b/tests/index.rs index 4418d3b31b..6f4aac2739 100644 --- a/tests/index.rs +++ b/tests/index.rs @@ -1,32 +1,10 @@ use super::*; -#[test] -fn incremental_indexing() -> Result { - let output = Test::new()? - .command("list 0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0") - .expected_stdout("[0,5000000000)\n") - .block() - .output()?; - - // assert_eq!(output.calls, &["getblockhash", "getblock", "getblockhash"]); - - let _output = Test::with_tempdir(output.tempdir)? - .command("list 9068a11b8769174363376b606af9a4b8b29dd7b13d013f4b0cbbd457db3c3ce5:0") - .expected_stdout("[5000000000,10000000000)\n") - .block() - .block() - .output()?; - - // assert_eq!(output.calls, &["getblockhash", "getblock", "getblockhash"]); - - Ok(()) -} - #[test] fn default_index_size() -> Result { let tempdir = Test::new()? .command("find 0") - .expected_stdout("0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0:0\n") + .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") .block() .output()? .tempdir; @@ -40,7 +18,7 @@ fn default_index_size() -> Result { fn custom_index_size() -> Result { let tempdir = Test::new()? .command("--max-index-size 1mib find 0") - .expected_stdout("0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0:0\n") + .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") .block() .output()? .tempdir; diff --git a/tests/info.rs b/tests/info.rs index 16edfaeecf..0347def6cf 100644 --- a/tests/info.rs +++ b/tests/info.rs @@ -2,7 +2,7 @@ use super::*; #[test] fn basic() -> Result { - let output = Test::new()?.command("index").block().output()?; + let output = Test::new()?.command("index").output()?; Test::with_tempdir(output.tempdir)? .command("info") From efcfcc24306b2c0c7295fc31d0faf62364db21fe Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 29 Jul 2022 19:19:06 -0400 Subject: [PATCH 23/61] Get server tests to pass --- Cargo.lock | 4 +- Cargo.toml | 2 +- tests/lib.rs | 188 ++++++++++++++++++------------------------------ tests/server.rs | 10 +-- 4 files changed, 80 insertions(+), 124 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2677f7f6e0..2214c4a166 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1969,9 +1969,9 @@ dependencies = [ [[package]] name = "redb" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dfbe4e6a60b6f8f02c2da9f9c614e71a9da2eac6aaa516aacb980fd1555e577" +checksum = "43908055ae1fd6233b365cfc372bc3d911e1b5831ca5daa53fe95bd0fba80583" dependencies = [ "libc", "pyo3-build-config", diff --git a/Cargo.toml b/Cargo.toml index 50e8a445b6..d6872c30fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ lazy_static = "1.4.0" log = "0.4.14" qrcode-generator = "4.1.6" rayon = "1.5.1" -redb = "0.3.1" +redb = "0.4.0" reqwest = { version = "0.11.10", features = ["blocking", "json"] } serde = { version = "1.0.137", features = ["derive"] } serde_cbor = "0.11.2" diff --git a/tests/lib.rs b/tests/lib.rs index d8d114706d..27893d6e42 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -13,10 +13,7 @@ use { KeychainKind, }, bitcoin::hash_types::Txid, - bitcoin::{ - blockdata::script, network::constants::Network, Block, OutPoint, Transaction, TxIn, TxOut, - Witness, - }, + bitcoin::{network::constants::Network, Block, OutPoint}, bitcoincore_rpc::RawTx, bitcoind::{bitcoincore_rpc::RpcApi, BitcoinD as Bitcoind}, executable_path::executable_path, @@ -271,7 +268,60 @@ impl<'a> Test<'a> { } fn test(self, port: Option) -> Result { + let child = Command::new(executable_path("ord")) + .envs(self.envs.clone()) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { + Stdio::piped() + } else { + Stdio::inherit() + }) + .current_dir(&self.tempdir) + .arg(format!( + "--rpc-url={}", + self.bitcoind.params.rpc_socket.to_string() + )) + .arg(format!( + "--cookie-file={}", + self.bitcoind.params.cookie_file.display() + )) + .args(self.args.clone()) + .spawn()?; + + log::info!("{}", self.bitcoind.params.rpc_socket.to_string()); + + let client = reqwest::blocking::Client::new(); + + let healthy = if let Some(port) = port { + let start = Instant::now(); + let mut healthy = false; + + loop { + if let Ok(response) = client + .get(&format!("http://127.0.0.1:{port}/status")) + .send() + { + if response.status().is_success() { + healthy = true; + break; + } + } + + if Instant::now() - start > Duration::from_secs(1) { + break; + } + + sleep(Duration::from_millis(100)); + } + + healthy + } else { + false + }; + let mut height = 0; + let mut successful_requests = 0; for event in &self.events { match event { @@ -288,9 +338,21 @@ impl<'a> Test<'a> { } self.sync()?; + + std::thread::sleep(Duration::from_millis(200)); } - Event::Request(_request, _status, _expected_response) => { - panic!() + Event::Request(request, status, expected_response) => { + if healthy { + let response = client + .get(&format!("http://127.0.0.1:{}/{request}", port.unwrap())) + .send()?; + log::info!("{:?}", response); + assert_eq!(response.status().as_u16(), *status); + assert_eq!(response.text()?, *expected_response); + successful_requests += 1; + } else { + panic!("Tried to make a request when unhealthy"); + } } Event::Transaction(options) => { let input_value = options @@ -317,8 +379,7 @@ impl<'a> Test<'a> { vout: slot.2 as u32, }) .collect::>(), - ) - .unwrap() + )? .set_recipients(vec![ ( self @@ -331,7 +392,7 @@ impl<'a> Test<'a> { options.output_count ]); - builder.finish().unwrap() + builder.finish()? }; if !self.wallet.sign(&mut psbt, SignOptions::default())? { @@ -346,114 +407,7 @@ impl<'a> Test<'a> { } } - let child = Command::new(executable_path("ord")) - .envs(self.envs.clone()) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { - Stdio::piped() - } else { - Stdio::inherit() - }) - .current_dir(&self.tempdir) - .arg(format!( - "--rpc-url={}", - self.bitcoind.params.rpc_socket.to_string() - )) - .arg(format!( - "--cookie-file={}", - self.bitcoind.params.cookie_file.display() - )) - .args(self.args.clone()) - .spawn()?; - - let mut successful_requests = 0; - - if let Some(port) = port { - let client = reqwest::blocking::Client::new(); - - let start = Instant::now(); - let mut healthy = false; - - loop { - if let Ok(response) = client - .get(&format!("http://127.0.0.1:{port}/status")) - .send() - { - if response.status().is_success() { - healthy = true; - break; - } - } - - if Instant::now() - start > Duration::from_secs(1) { - break; - } - - sleep(Duration::from_millis(100)); - } - - if healthy { - for event in &self.events { - match event { - Event::Block => { - self.bitcoind.client.generate_to_address( - 1, - &self.wallet.get_address(AddressIndex::LastUnused)?.address, - )?; - } - Event::Request(request, status, expected_response) => { - let response = client - .get(&format!("http://127.0.0.1:{port}/{request}")) - .send()?; - assert_eq!(response.status().as_u16(), *status); - assert_eq!(response.text()?, *expected_response); - successful_requests += 1; - } - Event::Transaction(options) => { - let input_value = options - .slots - .iter() - .map(|slot| { - self.get_block(slot.0 as u64).unwrap().txdata[slot.1].output[slot.2].value - }) - .sum::(); - - let output_value = input_value - options.fee; - - let tx = Transaction { - version: 0, - lock_time: 0, - input: options - .slots - .iter() - .map(|slot| TxIn { - previous_output: OutPoint { - txid: self.get_block(slot.0 as u64).unwrap().txdata[slot.1].txid(), - vout: slot.2 as u32, - }, - script_sig: script::Builder::new().into_script(), - sequence: 0, - witness: Witness::new(), - }) - .collect(), - output: vec![ - TxOut { - value: output_value / options.output_count as u64, - script_pubkey: script::Builder::new().into_script(), - }; - options.output_count - ], - }; - - self.bitcoind.client.send_raw_transaction(&tx)?; - } - } - } - } - - signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT)?; - } + signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT)?; let output = child.wait_with_output()?; diff --git a/tests/server.rs b/tests/server.rs index b8ecb2a7ed..793b9990f8 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -8,10 +8,12 @@ fn free_port() -> Result { fn list() -> Result { let port = free_port()?; + log::info!("port: {}", port); + Test::new()? .command(&format!("server --address 127.0.0.1 --port {port}")) .request( - "list/0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0", + "list/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0", 200, "[[0,5000000000]]", ) @@ -35,15 +37,15 @@ fn continuously_index_ranges() -> Result { Test::new()? .command(&format!("server --address 127.0.0.1 --port {port}")) .request( - "list/0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0", + "list/150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0", 404, "null", ) .block() .request( - "list/0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0", + "list/150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0", 200, - "[[0,5000000000]]", + "[[5000000000,10000000000]]", ) .run_server(port) } From 26b67cc1e611aee8e775d02e106e7ca7bfeb7a62 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 29 Jul 2022 20:21:31 -0400 Subject: [PATCH 24/61] Only kill process if healthy --- tests/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/lib.rs b/tests/lib.rs index 27893d6e42..fdf6adb0a7 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -407,7 +407,9 @@ impl<'a> Test<'a> { } } - signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT)?; + if healthy { + signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT)?; + } let output = child.wait_with_output()?; From 353b78fdad486c2534d0461cccf4da98a1c066e8 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 1 Aug 2022 12:21:03 -0400 Subject: [PATCH 25/61] Get all non-ignored tests to pass --- tests/lib.rs | 91 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/tests/lib.rs b/tests/lib.rs index fdf6adb0a7..98a0a5a4be 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -105,10 +105,13 @@ impl<'a> Test<'a> { let mut conf = bitcoind::Conf::default(); conf.view_stdout = false; - conf.args.push("-minrelaytxfee=0"); - conf.args.push("-blockmintxfee=0"); - conf.args.push("-dustrelayfee=0"); - conf.args.push("-maxtxfee=21000000"); + + conf.args.extend(&[ + "-minrelaytxfee=0", + "-blockmintxfee=0", + "-dustrelayfee=0", + "-maxtxfee=21000000", + ]); let bitcoind = Bitcoind::with_conf("bitcoind", &conf)?; @@ -268,32 +271,30 @@ impl<'a> Test<'a> { } fn test(self, port: Option) -> Result { - let child = Command::new(executable_path("ord")) - .envs(self.envs.clone()) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { - Stdio::piped() - } else { - Stdio::inherit() - }) - .current_dir(&self.tempdir) - .arg(format!( - "--rpc-url={}", - self.bitcoind.params.rpc_socket.to_string() - )) - .arg(format!( - "--cookie-file={}", - self.bitcoind.params.cookie_file.display() - )) - .args(self.args.clone()) - .spawn()?; - - log::info!("{}", self.bitcoind.params.rpc_socket.to_string()); - let client = reqwest::blocking::Client::new(); - let healthy = if let Some(port) = port { + let (healthy, child) = if let Some(port) = port { + let child = Command::new(executable_path("ord")) + .envs(self.envs.clone()) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { + Stdio::piped() + } else { + Stdio::inherit() + }) + .current_dir(&self.tempdir) + .arg(format!( + "--rpc-url={}", + self.bitcoind.params.rpc_socket.to_string() + )) + .arg(format!( + "--cookie-file={}", + self.bitcoind.params.cookie_file.display() + )) + .args(self.args.clone()) + .spawn()?; + let start = Instant::now(); let mut healthy = false; @@ -315,9 +316,9 @@ impl<'a> Test<'a> { sleep(Duration::from_millis(100)); } - healthy + (healthy, Some(child)) } else { - false + (false, None) }; let mut height = 0; @@ -339,7 +340,7 @@ impl<'a> Test<'a> { self.sync()?; - std::thread::sleep(Duration::from_millis(200)); + sleep(Duration::from_millis(200)); } Event::Request(request, status, expected_response) => { if healthy { @@ -401,15 +402,37 @@ impl<'a> Test<'a> { self.bitcoind.client.call::( "sendrawtransaction", - &[dbg!(psbt.extract_tx()).raw_hex().into(), 21000000.into()], + &[psbt.extract_tx().raw_hex().into(), 21000000.into()], )?; } } } - if healthy { + let child = if let Some(child) = child { signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT)?; - } + child + } else { + Command::new(executable_path("ord")) + .envs(self.envs.clone()) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { + Stdio::piped() + } else { + Stdio::inherit() + }) + .current_dir(&self.tempdir) + .arg(format!( + "--rpc-url={}", + self.bitcoind.params.rpc_socket.to_string() + )) + .arg(format!( + "--cookie-file={}", + self.bitcoind.params.cookie_file.display() + )) + .args(self.args.clone()) + .spawn()? + }; let output = child.wait_with_output()?; From 0ad28c0d665ba470677a2e45e7bd3f0fa0006e43 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 1 Aug 2022 15:52:09 -0400 Subject: [PATCH 26/61] Make tests slightly faster --- Cargo.lock | 37 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 +- tests/lib.rs | 27 +++++++++++++-------------- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eff3d516c2..787fa36a1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -286,6 +286,7 @@ dependencies = [ [[package]] name = "bitcoind" version = "0.26.1" +source = "git+https://github.com/terror/bitcoind.git?branch=wallet#2f7bb652f5d4dfbfad41478c84563aff64f7eae3" dependencies = [ "bitcoin_hashes 0.10.0", "bitcoincore-rpc", @@ -297,6 +298,7 @@ dependencies = [ "tempfile", "ureq", "which", + "zip", ] [[package]] @@ -323,6 +325,27 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +[[package]] +name = "bzip2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cc" version = "1.0.73" @@ -2697,3 +2720,17 @@ checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" dependencies = [ "libc", ] + +[[package]] +name = "zip" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" +dependencies = [ + "byteorder", + "bzip2", + "crc32fast", + "flate2", + "thiserror", + "time 0.1.44", +] diff --git a/Cargo.toml b/Cargo.toml index f79189fc8d..965b0aa814 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ version = "0.20.1-dev" features = ["rpc", "keys-bip39", "sqlite"] [dev-dependencies] -bitcoind = { path = "../bitcoind", features = ["23_0"] } +bitcoind = { git = "https://github.com/terror/bitcoind.git", branch = "wallet", features = ["23_0"] } executable-path = "1.0.0" hex = "0.4.3" nix = "0.24.1" diff --git a/tests/lib.rs b/tests/lib.rs index 98a0a5a4be..f7bb26b055 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -63,7 +63,7 @@ enum Expected { } enum Event<'a> { - Block, + Blocks(u64), Request(String, u16, String), Transaction(TransactionOptions<'a>), } @@ -266,7 +266,7 @@ impl<'a> Test<'a> { fn blocks(mut self, n: u64) -> Self { self .events - .extend((0..n).map(|_| Event::Block).collect::>()); + .push(Event::Blocks(n)); self } @@ -321,26 +321,22 @@ impl<'a> Test<'a> { (false, None) }; - let mut height = 0; + // let mut height = 0; let mut successful_requests = 0; for event in &self.events { match event { - Event::Block => { + Event::Blocks(n) => { self .bitcoind .client - .generate_to_address(1, &self.wallet.get_address(AddressIndex::Peek(0))?.address)?; + .generate_to_address(*n, &self.wallet.get_address(AddressIndex::Peek(0))?.address)?; - height += 1; + // height += 1; - for (t, transaction) in self.get_block(height)?.txdata.iter().enumerate() { - log::info!("tx: {height}x{t}: {}", transaction.txid()); - } - - self.sync()?; - - sleep(Duration::from_millis(200)); + // for (t, transaction) in self.get_block(height)?.txdata.iter().enumerate() { + // log::info!("tx: {height}x{t}: {}", transaction.txid()); + // } } Event::Request(request, status, expected_response) => { if healthy { @@ -356,6 +352,8 @@ impl<'a> Test<'a> { } } Event::Transaction(options) => { + self.sync()?; + let input_value = options .slots .iter() @@ -490,8 +488,9 @@ impl<'a> Test<'a> { }) } + // todo: remove this fn block(mut self) -> Self { - self.events.push(Event::Block); + self.events.push(Event::Blocks(1)); self } From 1eca6dc76c666ae32c3497d0289fb1be1326d42f Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Mon, 1 Aug 2022 13:29:17 -0700 Subject: [PATCH 27/61] Add our own bitcoind wrapper --- Cargo.lock | 432 ++---------------------------------------------- Cargo.toml | 1 - tests/lib.rs | 113 ++++++++----- tests/server.rs | 4 - 4 files changed, 81 insertions(+), 469 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 787fa36a1d..03e740855f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,17 +153,11 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide 0.5.3", + "miniz_oxide", "object", "rustc-demangle", ] -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - [[package]] name = "base64" version = "0.13.0" @@ -283,24 +277,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "bitcoind" -version = "0.26.1" -source = "git+https://github.com/terror/bitcoind.git?branch=wallet#2f7bb652f5d4dfbfad41478c84563aff64f7eae3" -dependencies = [ - "bitcoin_hashes 0.10.0", - "bitcoincore-rpc", - "filetime", - "flate2", - "home", - "log", - "tar", - "tempfile", - "ureq", - "which", - "zip", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -325,27 +301,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" -[[package]] -name = "bzip2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "cc" version = "1.0.73" @@ -367,16 +322,10 @@ dependencies = [ "libc", "num-integer", "num-traits", - "time 0.1.44", + "time", "winapi", ] -[[package]] -name = "chunked_transfer" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" - [[package]] name = "clap" version = "3.2.16" @@ -425,45 +374,12 @@ dependencies = [ "bitflags", ] -[[package]] -name = "const_fn" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" - [[package]] name = "convert_case" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" -[[package]] -name = "cookie" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" -dependencies = [ - "percent-encoding", - "time 0.2.27", - "version_check", -] - -[[package]] -name = "cookie_store" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3" -dependencies = [ - "cookie", - "idna", - "log", - "publicsuffix", - "serde", - "serde_json", - "time 0.2.27", - "url", -] - [[package]] name = "core-foundation" version = "0.9.3" @@ -553,7 +469,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.0", + "rustc_version", "syn", ] @@ -577,12 +493,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "either" version = "1.7.0" @@ -597,12 +507,12 @@ checksum = "25ae36f27655f7705dd8e9105600a79e4f23d390649abbbc57aa87adbc57245d" dependencies = [ "bitcoin", "log", - "rustls 0.20.6", + "rustls", "serde", "serde_json", "socks", - "webpki 0.22.0", - "webpki-roots 0.22.4", + "webpki", + "webpki-roots", ] [[package]] @@ -627,15 +537,6 @@ dependencies = [ "termcolor", ] -[[package]] -name = "error-chain" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "version_check", -] - [[package]] name = "executable-path" version = "1.0.0" @@ -663,30 +564,6 @@ dependencies = [ "instant", ] -[[package]] -name = "filetime" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "winapi", -] - -[[package]] -name = "flate2" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" -dependencies = [ - "cfg-if", - "crc32fast", - "libc", - "miniz_oxide 0.4.4", -] - [[package]] name = "fnv" version = "1.0.7" @@ -891,15 +768,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "home" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" -dependencies = [ - "winapi", -] - [[package]] name = "http" version = "0.2.8" @@ -1136,16 +1004,6 @@ dependencies = [ "serde", ] -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg 1.1.0", -] - [[package]] name = "miniz_oxide" version = "0.5.3" @@ -1296,7 +1154,6 @@ dependencies = [ "bdk", "bitcoin", "bitcoincore-rpc", - "bitcoind", "chrono", "clap", "ctrlc", @@ -1427,12 +1284,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - [[package]] name = "proc-macro2" version = "1.0.42" @@ -1442,19 +1293,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "publicsuffix" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" -dependencies = [ - "error-chain", - "idna", - "lazy_static", - "regex", - "url", -] - [[package]] name = "pyo3-build-config" version = "0.16.5" @@ -1465,15 +1303,6 @@ dependencies = [ "target-lexicon", ] -[[package]] -name = "qstring" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" -dependencies = [ - "percent-encoding", -] - [[package]] name = "quote" version = "1.0.20" @@ -1792,35 +1621,13 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.12", -] - -[[package]] -name = "rustls" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" -dependencies = [ - "base64", - "log", - "ring", - "sct 0.6.1", - "webpki 0.21.4", + "semver", ] [[package]] @@ -1831,8 +1638,8 @@ checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" dependencies = [ "log", "ring", - "sct 0.7.0", - "webpki 0.22.0", + "sct", + "webpki", ] [[package]] @@ -1857,16 +1664,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "sct" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "sct" version = "0.7.0" @@ -1920,27 +1717,12 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.141" @@ -1994,21 +1776,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - [[package]] name = "slab" version = "0.4.7" @@ -2076,64 +1843,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "strsim" version = "0.10.0" @@ -2157,17 +1866,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" -[[package]] -name = "tar" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" -dependencies = [ - "filetime", - "libc", - "xattr", -] - [[package]] name = "target-lexicon" version = "0.12.4" @@ -2234,44 +1932,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "time" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros", - "version_check", - "winapi", -] - -[[package]] -name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - -[[package]] -name = "time-macros-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn", -] - [[package]] name = "tokio" version = "1.20.1" @@ -2433,25 +2093,6 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" -[[package]] -name = "ureq" -version = "1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8b063c2d59218ae09f22b53c42eaad0d53516457905f5235ca4bc9e99daa71" -dependencies = [ - "base64", - "chunked_transfer", - "cookie", - "cookie_store", - "log", - "once_cell", - "qstring", - "rustls 0.19.1", - "url", - "webpki 0.21.4", - "webpki-roots 0.21.1", -] - [[package]] name = "url" version = "2.2.2" @@ -2580,16 +2221,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki" version = "0.22.0" @@ -2600,33 +2231,13 @@ dependencies = [ "untrusted", ] -[[package]] -name = "webpki-roots" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" -dependencies = [ - "webpki 0.21.4", -] - [[package]] name = "webpki-roots" version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf" dependencies = [ - "webpki 0.22.0", -] - -[[package]] -name = "which" -version = "4.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" -dependencies = [ - "either", - "lazy_static", - "libc", + "webpki", ] [[package]] @@ -2711,26 +2322,3 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] - -[[package]] -name = "xattr" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" -dependencies = [ - "libc", -] - -[[package]] -name = "zip" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" -dependencies = [ - "byteorder", - "bzip2", - "crc32fast", - "flate2", - "thiserror", - "time 0.1.44", -] diff --git a/Cargo.toml b/Cargo.toml index 965b0aa814..187d29a1fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,6 @@ version = "0.20.1-dev" features = ["rpc", "keys-bip39", "sqlite"] [dev-dependencies] -bitcoind = { git = "https://github.com/terror/bitcoind.git", branch = "wallet", features = ["23_0"] } executable-path = "1.0.0" hex = "0.4.3" nix = "0.24.1" diff --git a/tests/lib.rs b/tests/lib.rs index f7bb26b055..ef5b006bfa 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -3,7 +3,7 @@ use { bdk::{ blockchain::{ - rpc::{Auth, RpcBlockchain, RpcConfig}, + rpc::{RpcBlockchain, RpcConfig}, ConfigurableBlockchain, }, database::MemoryDatabase, @@ -14,8 +14,7 @@ use { }, bitcoin::hash_types::Txid, bitcoin::{network::constants::Network, Block, OutPoint}, - bitcoincore_rpc::RawTx, - bitcoind::{bitcoincore_rpc::RpcApi, BitcoinD as Bitcoind}, + bitcoincore_rpc::{Client, RawTx, RpcApi}, executable_path::executable_path, nix::{ sys::signal::{self, Signal}, @@ -28,7 +27,7 @@ use { ffi::OsString, fs, net::TcpListener, - process::{Command, Stdio}, + process::{Child, Command, Stdio}, str, sync::Once, thread::sleep, @@ -56,6 +55,10 @@ type Result = std::result::Result>; static ONCE: Once = Once::new(); +fn free_port() -> Result { + Ok(TcpListener::bind("127.0.0.1:0")?.local_addr()?.port()) +} + enum Expected { String(String), Regex(Regex), @@ -81,8 +84,10 @@ struct TransactionOptions<'a> { struct Test<'a> { args: Vec, - bitcoind: Bitcoind, + _bitcoind: Bitcoind, blockchain: RpcBlockchain, + client: Client, + rpc_port: u16, envs: Vec<(OsString, OsString)>, events: Vec>, expected_status: i32, @@ -92,6 +97,14 @@ struct Test<'a> { wallet: Wallet, } +struct Bitcoind(Child); + +impl Drop for Bitcoind { + fn drop(&mut self) { + self.0.kill().unwrap(); + } +} + impl<'a> Test<'a> { fn new() -> Result { Self::with_tempdir(TempDir::new()?) @@ -102,18 +115,50 @@ impl<'a> Test<'a> { env_logger::init(); }); - let mut conf = bitcoind::Conf::default(); + let datadir = tempdir.path().join("bitcoin"); + + fs::create_dir(&datadir).unwrap(); + + let rpc_port = free_port()?; - conf.view_stdout = false; + let bitcoind = Command::new("bitcoind") + // todo: + // disable network? + .args(&[ + "-minrelaytxfee=0", + "-blockmintxfee=0", + "-dustrelayfee=0", + "-maxtxfee=21000000", + "-datadir=bitcoin", + "-regtest", + &format!("-rpcport={rpc_port}"), + ]) + .current_dir(&tempdir.path()) + .spawn() + .unwrap(); - conf.args.extend(&[ - "-minrelaytxfee=0", - "-blockmintxfee=0", - "-dustrelayfee=0", - "-maxtxfee=21000000", - ]); + let cookiefile = datadir.join("regtest/.cookie"); - let bitcoind = Bitcoind::with_conf("bitcoind", &conf)?; + while !cookiefile.is_file() {} + + let client = Client::new( + &format!("localhost:{rpc_port}"), + bitcoincore_rpc::Auth::CookieFile(cookiefile.clone()), + )?; + + loop { + let mut attempts = 0; + match client.get_blockchain_info() { + Ok(_) => break, + Err(error) => { + attempts += 1; + if attempts > 300 { + panic!("Failed to connect to bitcoind: {error}"); + } + sleep(Duration::from_millis(100)); + } + } + } let wallet = Wallet::new( Bip84( @@ -129,10 +174,8 @@ impl<'a> Test<'a> { )?; let blockchain = RpcBlockchain::from_config(&RpcConfig { - url: bitcoind.params.rpc_socket.to_string(), - auth: Auth::Cookie { - file: bitcoind.params.cookie_file.clone(), - }, + url: format!("localhost:{rpc_port}"), + auth: bdk::blockchain::rpc::Auth::Cookie { file: cookiefile }, network: Network::Regtest, wallet_name: "test".to_string(), skip_blocks: None, @@ -140,13 +183,15 @@ impl<'a> Test<'a> { let test = Self { args: Vec::new(), - bitcoind, + client, blockchain, + _bitcoind: Bitcoind(bitcoind), envs: Vec::new(), events: Vec::new(), expected_status: 0, expected_stderr: Expected::Ignore, expected_stdout: Expected::String(String::new()), + rpc_port, tempdir, wallet, }; @@ -252,9 +297,8 @@ impl<'a> Test<'a> { fn get_block(&self, height: u64) -> Result { Ok( self - .bitcoind .client - .get_block(&self.bitcoind.client.get_block_hash(height)?)?, + .get_block(&self.client.get_block_hash(height)?)?, ) } @@ -264,9 +308,7 @@ impl<'a> Test<'a> { } fn blocks(mut self, n: u64) -> Self { - self - .events - .push(Event::Blocks(n)); + self.events.push(Event::Blocks(n)); self } @@ -284,14 +326,8 @@ impl<'a> Test<'a> { Stdio::inherit() }) .current_dir(&self.tempdir) - .arg(format!( - "--rpc-url={}", - self.bitcoind.params.rpc_socket.to_string() - )) - .arg(format!( - "--cookie-file={}", - self.bitcoind.params.cookie_file.display() - )) + .arg(format!("--rpc-url=localhost:{}", self.rpc_port)) + .arg("--cookie-file=bitcoin/regtest/.cookie") .args(self.args.clone()) .spawn()?; @@ -328,7 +364,6 @@ impl<'a> Test<'a> { match event { Event::Blocks(n) => { self - .bitcoind .client .generate_to_address(*n, &self.wallet.get_address(AddressIndex::Peek(0))?.address)?; @@ -398,7 +433,7 @@ impl<'a> Test<'a> { panic!("Failed to sign transaction"); } - self.bitcoind.client.call::( + self.client.call::( "sendrawtransaction", &[psbt.extract_tx().raw_hex().into(), 21000000.into()], )?; @@ -420,14 +455,8 @@ impl<'a> Test<'a> { Stdio::inherit() }) .current_dir(&self.tempdir) - .arg(format!( - "--rpc-url={}", - self.bitcoind.params.rpc_socket.to_string() - )) - .arg(format!( - "--cookie-file={}", - self.bitcoind.params.cookie_file.display() - )) + .arg(format!("--rpc-url=localhost:{}", self.rpc_port)) + .arg("--cookie-file=bitcoin/regtest/.cookie") .args(self.args.clone()) .spawn()? }; diff --git a/tests/server.rs b/tests/server.rs index 793b9990f8..d359d43281 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -1,9 +1,5 @@ use super::*; -fn free_port() -> Result { - Ok(TcpListener::bind("127.0.0.1:0")?.local_addr()?.port()) -} - #[test] fn list() -> Result { let port = free_port()?; From 10f92cc664a260602f6d5bfc536dbb52b7cdfbd6 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 1 Aug 2022 16:47:29 -0400 Subject: [PATCH 28/61] Remove todo's --- tests/find.rs | 20 ++++++++++---------- tests/index.rs | 4 ++-- tests/lib.rs | 20 +++----------------- tests/list.rs | 24 ++++++++++++------------ tests/server.rs | 4 ++-- tests/version.rs | 2 +- 6 files changed, 30 insertions(+), 44 deletions(-) diff --git a/tests/find.rs b/tests/find.rs index 772075c5c5..39e0995ded 100644 --- a/tests/find.rs +++ b/tests/find.rs @@ -14,7 +14,7 @@ fn first_satoshi_slot() -> Result { Test::new()? .command("find 0 --slot") .expected_stdout("0x0x0x0\n") - .block() + .blocks(1) .run() } @@ -32,7 +32,7 @@ fn second_satoshi_slot() -> Result { Test::new()? .command("find 1 --slot") .expected_stdout("0x0x0x1\n") - .block() + .blocks(1) .run() } @@ -40,7 +40,7 @@ fn second_satoshi_slot() -> Result { fn first_satoshi_of_second_block() -> Result { Test::new()? .command("find 5000000000") - .block() + .blocks(1) .expected_stdout("150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0:0\n") .run() } @@ -51,8 +51,8 @@ fn first_satoshi_of_second_block_slot() -> Result { Test::new()? .command("find 5000000000 --slot") .expected_stdout("1x0x0x0\n") - .block() - .block() + .blocks(1) + .blocks(1) .run() } @@ -66,7 +66,7 @@ fn first_satoshi_spent_in_second_block() -> Result { output_count: 1, fee: 0, }) - .block() + .blocks(1) .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") .run() } @@ -77,8 +77,8 @@ fn first_satoshi_spent_in_second_block_slot() -> Result { Test::new()? .command("find 0 --slot") .expected_stdout("1x1x0x0\n") - .block() - .block() + .blocks(1) + .blocks(1) .transaction(TransactionOptions { slots: &[(0, 0, 0)], output_count: 1, @@ -92,8 +92,8 @@ fn first_satoshi_spent_in_second_block_slot() -> Result { fn mining_and_spending_transaction_in_same_block() -> Result { Test::new()? .command("find 0 --slot") - .block() - .block() + .blocks(1) + .blocks(1) .transaction(TransactionOptions { slots: &[(0, 0, 0)], output_count: 1, diff --git a/tests/index.rs b/tests/index.rs index 6f4aac2739..312c14feba 100644 --- a/tests/index.rs +++ b/tests/index.rs @@ -5,7 +5,7 @@ fn default_index_size() -> Result { let tempdir = Test::new()? .command("find 0") .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") - .block() + .blocks(1) .output()? .tempdir; @@ -19,7 +19,7 @@ fn custom_index_size() -> Result { let tempdir = Test::new()? .command("--max-index-size 1mib find 0") .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") - .block() + .blocks(1) .output()? .tempdir; diff --git a/tests/lib.rs b/tests/lib.rs index 1ca15ac4a3..c70c3066e9 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -141,8 +141,6 @@ impl<'a> Test<'a> { let rpc_port = free_port()?; let bitcoind = Command::new("bitcoind") - // todo: - // disable network? .args(&[ "-minrelaytxfee=0", "-blockmintxfee=0", @@ -150,6 +148,7 @@ impl<'a> Test<'a> { "-maxtxfee=21000000", "-datadir=bitcoin", "-regtest", + "-networkactive=0", &format!("-rpcport={rpc_port}"), ]) .current_dir(&tempdir.path()) @@ -326,11 +325,6 @@ impl<'a> Test<'a> { Ok(()) } - fn blocks(mut self, n: u64) -> Self { - self.events.push(Event::Blocks(n)); - self - } - fn test(self, port: Option) -> Result { let client = reqwest::blocking::Client::new(); @@ -376,7 +370,6 @@ impl<'a> Test<'a> { (false, None) }; - // let mut height = 0; let mut successful_requests = 0; for event in &self.events { @@ -385,12 +378,6 @@ impl<'a> Test<'a> { self .client .generate_to_address(*n, &self.wallet.get_address(AddressIndex::Peek(0))?.address)?; - - // height += 1; - - // for (t, transaction) in self.get_block(height)?.txdata.iter().enumerate() { - // log::info!("tx: {height}x{t}: {}", transaction.txid()); - // } } Event::Request(request, status, expected_response) => { if healthy { @@ -519,9 +506,8 @@ impl<'a> Test<'a> { }) } - // todo: remove this - fn block(mut self) -> Self { - self.events.push(Event::Blocks(1)); + fn blocks(mut self, n: u64) -> Self { + self.events.push(Event::Blocks(n)); self } diff --git a/tests/list.rs b/tests/list.rs index 5fc189e32e..48cbc4fe45 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -12,7 +12,7 @@ fn first_coinbase_transaction() -> Result { fn second_coinbase_transaction() -> Result { Test::new()? .command("list 150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0") - .block() + .blocks(1) .expected_stdout("[5000000000,10000000000)\n") .run() } @@ -27,7 +27,7 @@ fn split_ranges_are_tracked_correctly() -> Result { output_count: 2, fee: 0, }) - .block() + .blocks(1) .expected_stdout("[5000000000,7500000000)\n") .run()?; @@ -39,7 +39,7 @@ fn split_ranges_are_tracked_correctly() -> Result { output_count: 2, fee: 0, }) - .block() + .blocks(1) .expected_stdout("[7500000000,10000000000)\n") .run() } @@ -54,13 +54,13 @@ fn merge_ranges_are_tracked_correctly() -> Result { output_count: 2, fee: 0, }) - .block() + .blocks(1) .transaction(TransactionOptions { slots: &[(102, 1, 0), (102, 1, 1)], output_count: 1, fee: 0, }) - .block() + .blocks(1) .expected_stdout("[5000000000,7500000000)\n[7500000000,10000000000)\n") .run() } @@ -75,7 +75,7 @@ fn fee_paying_transaction_range() -> Result { output_count: 2, fee: 10, }) - .block() + .blocks(1) .expected_stdout("[5000000000,7499999995)\n") .run()?; @@ -87,7 +87,7 @@ fn fee_paying_transaction_range() -> Result { output_count: 2, fee: 10, }) - .block() + .blocks(1) .expected_stdout("[7499999995,9999999990)\n") .run()?; @@ -99,7 +99,7 @@ fn fee_paying_transaction_range() -> Result { output_count: 2, fee: 10, }) - .block() + .blocks(1) .expected_stdout("[510000000000,515000000000)\n[9999999990,10000000000)\n") .run() } @@ -119,7 +119,7 @@ fn two_fee_paying_transaction_range() -> Result { output_count: 1, fee: 10, }) - .block() + .blocks(1) .expected_stdout( "[515000000000,520000000000)\n[9999999990,10000000000)\n[14999999990,15000000000)\n", ) @@ -136,7 +136,7 @@ fn null_output() -> Result { output_count: 1, fee: 50 * 100_000_000, }) - .block() + .blocks(1) .expected_stdout("") .run() } @@ -151,7 +151,7 @@ fn null_input() -> Result { output_count: 1, fee: 50 * 100_000_000, }) - .block() + .blocks(1) .transaction(TransactionOptions { slots: &[(102, 1, 0)], output_count: 1, @@ -171,7 +171,7 @@ fn old_transactions_are_pruned() -> Result { output_count: 1, fee: 50 * 100_000_000, }) - .block() + .blocks(1) .expected_stderr("error: Output not found\n") .expected_status(1) .run() diff --git a/tests/server.rs b/tests/server.rs index 6120cdbc1c..4a6cd592de 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -8,7 +8,7 @@ fn list() -> Result { Test::new()? .command(&format!("server --address 127.0.0.1 --http-port {port}")) - .block() + .blocks(1) .request( "list/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0", 200, @@ -38,7 +38,7 @@ fn continuously_index_ranges() -> Result { 404, "null", ) - .block() + .blocks(1) .request( "list/150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0", 200, diff --git a/tests/version.rs b/tests/version.rs index f7cc29ca88..e70d16e47b 100644 --- a/tests/version.rs +++ b/tests/version.rs @@ -5,6 +5,6 @@ fn flag() -> Result { Test::new()? .command("--version") .stdout_regex("ord .*\n") - .block() + .blocks(1) .run() } From ff89123a385cde8bc0fa1e27015917abbff617e6 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 2 Aug 2022 14:35:54 -0400 Subject: [PATCH 29/61] Add logging --- Cargo.toml | 1 + tests/lib.rs | 72 +++++++++++++++++++++++++--------------------------- 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d2d513ba95..94e29e6be9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ reqwest = { version = "0.11.10", features = ["blocking"] } regex = "1.6.0" tempfile = "3.2.0" unindent = "0.1.7" +log = "0.4.14" [[test]] name = "integration" diff --git a/tests/lib.rs b/tests/lib.rs index c70c3066e9..41f59f4179 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -16,6 +16,7 @@ use { bitcoin::{network::constants::Network, Block, OutPoint}, bitcoincore_rpc::{Client, RawTx, RpcApi}, executable_path::executable_path, + log::LevelFilter, nix::{ sys::signal::{self, Signal}, unistd::Pid, @@ -141,6 +142,11 @@ impl<'a> Test<'a> { let rpc_port = free_port()?; let bitcoind = Command::new("bitcoind") + .stdout(if log::max_level() >= LevelFilter::Info { + Stdio::inherit() + } else { + Stdio::piped() + }) .args(&[ "-minrelaytxfee=0", "-blockmintxfee=0", @@ -152,8 +158,7 @@ impl<'a> Test<'a> { &format!("-rpcport={rpc_port}"), ]) .current_dir(&tempdir.path()) - .spawn() - .unwrap(); + .spawn()?; let cookiefile = datadir.join("regtest/.cookie"); @@ -328,22 +333,24 @@ impl<'a> Test<'a> { fn test(self, port: Option) -> Result { let client = reqwest::blocking::Client::new(); - let (healthy, child) = if let Some(port) = port { - let child = Command::new(executable_path("ord")) - .envs(self.envs.clone()) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { - Stdio::piped() - } else { - Stdio::inherit() - }) - .current_dir(&self.tempdir) - .arg(format!("--rpc-url=localhost:{}", self.rpc_port)) - .arg("--cookie-file=bitcoin/regtest/.cookie") - .args(self.args.clone()) - .spawn()?; - + log::info!("Spawning child process..."); + + let child = Command::new(executable_path("ord")) + .envs(self.envs.clone()) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { + Stdio::piped() + } else { + Stdio::inherit() + }) + .current_dir(&self.tempdir) + .arg(format!("--rpc-url=localhost:{}", self.rpc_port)) + .arg("--cookie-file=bitcoin/regtest/.cookie") + .args(self.args.clone()) + .spawn()?; + + let healthy = if let Some(port) = port { let start = Instant::now(); let mut healthy = false; @@ -365,11 +372,16 @@ impl<'a> Test<'a> { sleep(Duration::from_millis(100)); } - (healthy, Some(child)) + healthy } else { - (false, None) + false }; + log::info!( + "Server status: {}", + if healthy { "healthy" } else { "not healthy " } + ); + let mut successful_requests = 0; for event in &self.events { @@ -447,25 +459,9 @@ impl<'a> Test<'a> { } } - let child = if let Some(child) = child { + if port.is_some() { signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT)?; - child - } else { - Command::new(executable_path("ord")) - .envs(self.envs.clone()) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { - Stdio::piped() - } else { - Stdio::inherit() - }) - .current_dir(&self.tempdir) - .arg(format!("--rpc-url=localhost:{}", self.rpc_port)) - .arg("--cookie-file=bitcoin/regtest/.cookie") - .args(self.args.clone()) - .spawn()? - }; + } let output = child.wait_with_output()?; From f268fea346d8f0ee0c6f73f4a9495940344c9058 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 2 Aug 2022 14:49:58 -0400 Subject: [PATCH 30/61] Get tests to pass individually again --- tests/lib.rs | 54 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/tests/lib.rs b/tests/lib.rs index 41f59f4179..dfd39069b8 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -335,22 +335,22 @@ impl<'a> Test<'a> { log::info!("Spawning child process..."); - let child = Command::new(executable_path("ord")) - .envs(self.envs.clone()) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { - Stdio::piped() - } else { - Stdio::inherit() - }) - .current_dir(&self.tempdir) - .arg(format!("--rpc-url=localhost:{}", self.rpc_port)) - .arg("--cookie-file=bitcoin/regtest/.cookie") - .args(self.args.clone()) - .spawn()?; + let (healthy, child) = if let Some(port) = port { + let child = Command::new(executable_path("ord")) + .envs(self.envs.clone()) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { + Stdio::piped() + } else { + Stdio::inherit() + }) + .current_dir(&self.tempdir) + .arg(format!("--rpc-url=localhost:{}", self.rpc_port)) + .arg("--cookie-file=bitcoin/regtest/.cookie") + .args(self.args.clone()) + .spawn()?; - let healthy = if let Some(port) = port { let start = Instant::now(); let mut healthy = false; @@ -372,9 +372,9 @@ impl<'a> Test<'a> { sleep(Duration::from_millis(100)); } - healthy + (healthy, Some(child)) } else { - false + (false, None) }; log::info!( @@ -459,9 +459,25 @@ impl<'a> Test<'a> { } } - if port.is_some() { + let child = if let Some(child) = child { signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT)?; - } + child + } else { + Command::new(executable_path("ord")) + .envs(self.envs.clone()) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { + Stdio::piped() + } else { + Stdio::inherit() + }) + .current_dir(&self.tempdir) + .arg(format!("--rpc-url=localhost:{}", self.rpc_port)) + .arg("--cookie-file=bitcoin/regtest/.cookie") + .args(self.args.clone()) + .spawn()? + }; let output = child.wait_with_output()?; From ce154d2b8ed54d06aaefb38142a6263301fa4e64 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 2 Aug 2022 15:06:17 -0400 Subject: [PATCH 31/61] Small refactors --- src/main.rs | 3 +++ src/subcommand/wallet.rs | 4 ---- src/subcommand/wallet/fund.rs | 9 ++++----- src/subcommand/wallet/utxos.rs | 6 +----- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2920dced3b..fd9a749da5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,10 +9,13 @@ use { axum::{extract, http::StatusCode, response::IntoResponse, routing::get, Json, Router}, axum_server::Handle, bdk::{ + blockchain::rpc::{Auth, RpcBlockchain, RpcConfig}, + blockchain::ConfigurableBlockchain, database::SqliteDatabase, keys::bip39::{Language, Mnemonic}, template::Bip84, wallet::AddressIndex::LastUnused, + wallet::{wallet_name_from_descriptor, SyncOptions}, KeychainKind, }, bitcoin::{ diff --git a/src/subcommand/wallet.rs b/src/subcommand/wallet.rs index 5f24a05790..996543ae61 100644 --- a/src/subcommand/wallet.rs +++ b/src/subcommand/wallet.rs @@ -4,10 +4,6 @@ mod fund; mod init; mod utxos; -use bdk::blockchain::rpc::{Auth, RpcBlockchain, RpcConfig}; -use bdk::blockchain::ConfigurableBlockchain; -use bdk::wallet::{wallet_name_from_descriptor, SyncOptions}; - fn get_wallet(options: Options) -> Result> { let path = data_dir() .ok_or_else(|| anyhow!("Failed to retrieve data dir"))? diff --git a/src/subcommand/wallet/fund.rs b/src/subcommand/wallet/fund.rs index 03a935a015..22299a54d1 100644 --- a/src/subcommand/wallet/fund.rs +++ b/src/subcommand/wallet/fund.rs @@ -1,9 +1,8 @@ use super::*; pub(crate) fn run(options: Options) -> Result { - let wallet = get_wallet(options)?; - - println!("{}", wallet.get_address(LastUnused)?.address); - - Ok(()) + Ok(println!( + "{}", + get_wallet(options)?.get_address(LastUnused)?.address + )) } diff --git a/src/subcommand/wallet/utxos.rs b/src/subcommand/wallet/utxos.rs index 8e022f4b0d..c37101cad3 100644 --- a/src/subcommand/wallet/utxos.rs +++ b/src/subcommand/wallet/utxos.rs @@ -1,9 +1,5 @@ use super::*; pub(crate) fn run(options: Options) -> Result { - let wallet = get_wallet(options)?; - - println!("{:?}", wallet.get_balance()?); - - Ok(()) + Ok(println!("{:?}", get_wallet(options)?.list_unspent()?)) } From 295c19f4d88991902c1c1d3ef5f389f4221781fe Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 2 Aug 2022 12:22:34 -0700 Subject: [PATCH 32/61] Refactor to use State object --- tests/index.rs | 18 ++++-- tests/info.rs | 2 +- tests/lib.rs | 158 ++++++++++++++++++++++++++++-------------------- tests/nft.rs | 2 +- tests/server.rs | 16 ++--- tests/wallet.rs | 51 ++++++++++------ 6 files changed, 148 insertions(+), 99 deletions(-) diff --git a/tests/index.rs b/tests/index.rs index 312c14feba..11612291c0 100644 --- a/tests/index.rs +++ b/tests/index.rs @@ -2,28 +2,34 @@ use super::*; #[test] fn default_index_size() -> Result { - let tempdir = Test::new()? + let state = Test::new()? .command("find 0") .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") .blocks(1) .output()? - .tempdir; + .state; - assert_eq!(tempdir.path().join("index.redb").metadata()?.len(), 1 << 20); + assert_eq!( + state.tempdir.path().join("index.redb").metadata()?.len(), + 1 << 20 + ); Ok(()) } #[test] fn custom_index_size() -> Result { - let tempdir = Test::new()? + let state = Test::new()? .command("--max-index-size 1mib find 0") .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") .blocks(1) .output()? - .tempdir; + .state; - assert_eq!(tempdir.path().join("index.redb").metadata()?.len(), 1 << 20); + assert_eq!( + state.tempdir.path().join("index.redb").metadata()?.len(), + 1 << 20 + ); Ok(()) } diff --git a/tests/info.rs b/tests/info.rs index 0347def6cf..c763be271f 100644 --- a/tests/info.rs +++ b/tests/info.rs @@ -4,7 +4,7 @@ use super::*; fn basic() -> Result { let output = Test::new()?.command("index").output()?; - Test::with_tempdir(output.tempdir)? + Test::with_state(output.state)? .command("info") .stdout_regex( r" diff --git a/tests/lib.rs b/tests/lib.rs index dfd39069b8..bcfcf9a2d9 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -56,8 +56,12 @@ type Result = std::result::Result>; static ONCE: Once = Once::new(); -fn free_port() -> Result { - Ok(TcpListener::bind("127.0.0.1:0")?.local_addr()?.port()) +fn free_port() -> u16 { + TcpListener::bind("127.0.0.1:0") + .unwrap() + .local_addr() + .unwrap() + .port() } #[derive(Debug)] @@ -93,7 +97,7 @@ enum Event<'a> { struct Output { stdout: String, - tempdir: TempDir, + state: State, } struct TransactionOptions<'a> { @@ -104,42 +108,30 @@ struct TransactionOptions<'a> { struct Test<'a> { args: Vec, - _bitcoind: Bitcoind, - blockchain: RpcBlockchain, - client: Client, - rpc_port: u16, envs: Vec<(OsString, OsString)>, events: Vec>, expected_status: i32, expected_stderr: Expected, expected_stdout: Expected, - tempdir: TempDir, - wallet: Wallet, + state: State, } -struct Bitcoind(Child); - -impl Drop for Bitcoind { - fn drop(&mut self) { - self.0.kill().unwrap(); - } +struct State { + bitcoind: Child, + tempdir: TempDir, + client: Client, + wallet: Wallet, + blockchain: RpcBlockchain, + rpc_port: u16, } -impl<'a> Test<'a> { - fn new() -> Result { - Self::with_tempdir(TempDir::new()?) - } - - fn with_tempdir(tempdir: TempDir) -> Result { - ONCE.call_once(|| { - env_logger::init(); - }); +impl State { + fn new() -> Self { + let tempdir = TempDir::new().unwrap(); - let datadir = tempdir.path().join("bitcoin"); + fs::create_dir(tempdir.path().join("bitcoin")).unwrap(); - fs::create_dir(&datadir).unwrap(); - - let rpc_port = free_port()?; + let rpc_port = free_port(); let bitcoind = Command::new("bitcoind") .stdout(if log::max_level() >= LevelFilter::Info { @@ -155,38 +147,40 @@ impl<'a> Test<'a> { "-datadir=bitcoin", "-regtest", "-networkactive=0", + "-listen=0", &format!("-rpcport={rpc_port}"), ]) .current_dir(&tempdir.path()) - .spawn()?; + .spawn() + .unwrap(); - let cookiefile = datadir.join("regtest/.cookie"); + let cookiefile = tempdir.path().join("bitcoin/regtest/.cookie"); while !cookiefile.is_file() {} let client = Client::new( &format!("localhost:{rpc_port}"), bitcoincore_rpc::Auth::CookieFile(cookiefile.clone()), - )?; + ) + .unwrap(); - loop { - let mut attempts = 0; + for attempt in 0..=300 { match client.get_blockchain_info() { Ok(_) => break, - Err(error) => { - attempts += 1; - if attempts > 300 { - panic!("Failed to connect to bitcoind: {error}"); + Err(err) => { + if attempt == 300 { + panic!("Failed to connect to bitcoind: {err}"); } - sleep(Duration::from_millis(100)); } } + sleep(Duration::from_millis(100)); } let wallet = Wallet::new( Bip84( ( - Mnemonic::parse("book fit fly ketchup also elevator scout mind edit fatal where rookie")?, + Mnemonic::parse("book fit fly ketchup also elevator scout mind edit fatal where rookie") + .unwrap(), None, ), KeychainKind::External, @@ -194,7 +188,8 @@ impl<'a> Test<'a> { None, Network::Regtest, MemoryDatabase::new(), - )?; + ) + .unwrap(); let blockchain = RpcBlockchain::from_config(&RpcConfig { url: format!("localhost:{rpc_port}"), @@ -202,21 +197,44 @@ impl<'a> Test<'a> { network: Network::Regtest, wallet_name: "test".to_string(), skip_blocks: None, - })?; + }) + .unwrap(); - let test = Self { - args: Vec::new(), + State { + tempdir, + rpc_port, + bitcoind, client, + wallet, blockchain, - _bitcoind: Bitcoind(bitcoind), + } + } +} + +impl Drop for State { + fn drop(&mut self) { + self.bitcoind.kill().unwrap(); + } +} + +impl<'a> Test<'a> { + fn new() -> Result { + Self::with_state(State::new()) + } + + fn with_state(state: State) -> Result { + ONCE.call_once(|| { + env_logger::init(); + }); + + let test = Self { + args: Vec::new(), + state, envs: Vec::new(), events: Vec::new(), expected_status: 0, expected_stderr: Expected::Ignore, expected_stdout: Expected::String(String::new()), - rpc_port, - tempdir, - wallet, }; test.sync()?; @@ -256,10 +274,12 @@ impl<'a> Test<'a> { } } + // TODO: do this always fn set_home_to_tempdir(mut self) -> Self { - self - .envs - .push((OsString::from("HOME"), OsString::from(self.tempdir.path()))); + self.envs.push(( + OsString::from("HOME"), + OsString::from(self.state.tempdir.path()), + )); self } @@ -316,8 +336,9 @@ impl<'a> Test<'a> { fn get_block(&self, height: u64) -> Result { Ok( self + .state .client - .get_block(&self.client.get_block_hash(height)?)?, + .get_block(&self.state.client.get_block_hash(height)?)?, ) } @@ -326,7 +347,10 @@ impl<'a> Test<'a> { } fn sync(&self) -> Result { - self.wallet.sync(&self.blockchain, SyncOptions::default())?; + self + .state + .wallet + .sync(&self.state.blockchain, SyncOptions::default())?; Ok(()) } @@ -345,8 +369,8 @@ impl<'a> Test<'a> { } else { Stdio::inherit() }) - .current_dir(&self.tempdir) - .arg(format!("--rpc-url=localhost:{}", self.rpc_port)) + .current_dir(&self.state.tempdir) + .arg(format!("--rpc-url=localhost:{}", self.state.rpc_port)) .arg("--cookie-file=bitcoin/regtest/.cookie") .args(self.args.clone()) .spawn()?; @@ -387,9 +411,14 @@ impl<'a> Test<'a> { for event in &self.events { match event { Event::Blocks(n) => { - self - .client - .generate_to_address(*n, &self.wallet.get_address(AddressIndex::Peek(0))?.address)?; + self.state.client.generate_to_address( + *n, + &self + .state + .wallet + .get_address(AddressIndex::Peek(0))? + .address, + )?; } Event::Request(request, status, expected_response) => { if healthy { @@ -416,7 +445,7 @@ impl<'a> Test<'a> { let output_value = input_value - options.fee; let (mut psbt, _) = { - let mut builder = self.wallet.build_tx(); + let mut builder = self.state.wallet.build_tx(); builder .manually_selected_only() @@ -435,6 +464,7 @@ impl<'a> Test<'a> { .set_recipients(vec![ ( self + .state .wallet .get_address(AddressIndex::Peek(0))? .address @@ -447,11 +477,11 @@ impl<'a> Test<'a> { builder.finish()? }; - if !self.wallet.sign(&mut psbt, SignOptions::default())? { + if !self.state.wallet.sign(&mut psbt, SignOptions::default())? { panic!("Failed to sign transaction"); } - self.client.call::( + self.state.client.call::( "sendrawtransaction", &[psbt.extract_tx().raw_hex().into(), 21000000.into()], )?; @@ -472,8 +502,8 @@ impl<'a> Test<'a> { } else { Stdio::inherit() }) - .current_dir(&self.tempdir) - .arg(format!("--rpc-url=localhost:{}", self.rpc_port)) + .current_dir(&self.state.tempdir) + .arg(format!("--rpc-url=localhost:{}", self.state.rpc_port)) .arg("--cookie-file=bitcoin/regtest/.cookie") .args(self.args.clone()) .spawn()? @@ -514,7 +544,7 @@ impl<'a> Test<'a> { Ok(Output { stdout: stdout.to_string(), - tempdir: self.tempdir, + state: self.state, }) } @@ -529,7 +559,7 @@ impl<'a> Test<'a> { } fn write(self, path: &str, contents: &str) -> Result { - fs::write(self.tempdir.path().join(path), contents)?; + fs::write(self.state.tempdir.path().join(path), contents)?; Ok(self) } } diff --git a/tests/nft.rs b/tests/nft.rs index 8acf64e1bb..a2a7812b61 100644 --- a/tests/nft.rs +++ b/tests/nft.rs @@ -17,7 +17,7 @@ fn mint_and_verify() -> Result { ]) .output()?; - Test::with_tempdir(output.tempdir)? + Test::with_state(output.state)? .command("verify foo.nft") .expected_stderr( "NFT is valid! diff --git a/tests/server.rs b/tests/server.rs index 4a6cd592de..e62e4e8cf3 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -2,7 +2,7 @@ use super::*; #[test] fn list() -> Result { - let port = free_port()?; + let port = free_port(); log::info!("port: {}", port); @@ -19,7 +19,7 @@ fn list() -> Result { #[test] fn status() -> Result { - let port = free_port()?; + let port = free_port(); Test::new()? .command(&format!("server --address 127.0.0.1 --http-port {port}")) @@ -29,7 +29,7 @@ fn status() -> Result { #[test] fn continuously_index_ranges() -> Result { - let port = free_port()?; + let port = free_port(); Test::new()? .command(&format!("server --address 127.0.0.1 --http-port {port}")) @@ -67,7 +67,7 @@ fn http_and_https_port_conflict() -> Result { #[test] fn http_port_requires_acme_flags() -> Result { - let port = free_port()?; + let port = free_port(); Test::new()? .command("server --address 127.0.0.1 --https-port 0") @@ -78,7 +78,7 @@ fn http_port_requires_acme_flags() -> Result { #[test] fn acme_contact_accepts_multiple_values() -> Result { - let port = free_port()?; + let port = free_port(); Test::new()? .command("server --address 127.0.0.1 --http-port 0 --acme-contact foo --acme-contact bar") @@ -87,7 +87,7 @@ fn acme_contact_accepts_multiple_values() -> Result { #[test] fn acme_domain_accepts_multiple_values() -> Result { - let port = free_port()?; + let port = free_port(); Test::new()? .command("server --address 127.0.0.1 --http-port 0 --acme-domain foo --acme-domain bar") @@ -96,11 +96,11 @@ fn acme_domain_accepts_multiple_values() -> Result { #[test] fn creates_acme_cache() { - let port = free_port().unwrap(); + let port = free_port(); let output = Test::new().unwrap() .command("server --address 127.0.0.1 --https-port 0 --acme-domain foo --acme-cache bar --acme-contact mailto:foo@bar.com") .run_server_output(port); - assert!(output.tempdir.path().join("bar").is_dir()); + assert!(output.state.tempdir.path().join("bar").is_dir()); } diff --git a/tests/wallet.rs b/tests/wallet.rs index 6a200f0867..cdf721119d 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -10,19 +10,23 @@ fn path(path: &str) -> String { #[test] fn init_existing_wallet() -> Result { - let tempdir = Test::new()? + let state = Test::new()? .command("wallet init") .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") .output()? - .tempdir; + .state; - assert!(tempdir.path().join(path("ord/wallet.sqlite")).exists()); + assert!(state + .tempdir + .path() + .join(path("ord/wallet.sqlite")) + .exists()); - assert!(tempdir.path().join(path("ord/entropy")).exists()); + assert!(state.tempdir.path().join(path("ord/entropy")).exists()); - Test::with_tempdir(tempdir)? + Test::with_state(state)? .command("wallet init") .set_home_to_tempdir() .expected_status(1) @@ -32,32 +36,41 @@ fn init_existing_wallet() -> Result { #[test] fn init_nonexistent_wallet() -> Result { - let tempdir = Test::new()? + let output = Test::new()? .command("wallet init") .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") - .output()? - .tempdir; - - assert!(tempdir.path().join(path("ord/wallet.sqlite")).exists()); - - assert!(tempdir.path().join(path("ord/entropy")).exists()); + .output()?; + + assert!(output + .state + .tempdir + .path() + .join(path("ord/wallet.sqlite")) + .exists()); + + assert!(output + .state + .tempdir + .path() + .join(path("ord/entropy")) + .exists()); Ok(()) } #[test] fn load_corrupted_entropy() -> Result { - let tempdir = Test::new()? + let state = Test::new()? .command("wallet init") .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") .output()? - .tempdir; + .state; - let entropy_path = tempdir.path().join(path("ord/entropy")); + let entropy_path = state.tempdir.path().join(path("ord/entropy")); assert!(entropy_path.exists()); @@ -66,7 +79,7 @@ fn load_corrupted_entropy() -> Result { fs::write(&entropy_path, entropy)?; - Test::with_tempdir(tempdir)? + Test::with_state(state)? .command("wallet fund") .set_home_to_tempdir() .expected_status(1) @@ -78,16 +91,16 @@ fn load_corrupted_entropy() -> Result { #[test] fn fund_existing_wallet() -> Result { - let tempdir = Test::new()? + let state = Test::new()? .command("wallet init") .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") .set_home_to_tempdir() .output()? - .tempdir; + .state; - Test::with_tempdir(tempdir)? + Test::with_state(state)? .command("wallet fund") .set_home_to_tempdir() .stdout_regex("^tb1.*\n") From 9443fe9621fb86ea155d2cc50e8e05278d389275 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 2 Aug 2022 12:35:47 -0700 Subject: [PATCH 33/61] Use unwrap --- tests/epochs.rs | 6 +-- tests/find.rs | 59 +++++++++++----------- tests/index.rs | 32 +++++++----- tests/info.rs | 8 +-- tests/lib.rs | 129 ++++++++++++++++++++++++++--------------------- tests/list.rs | 58 ++++++++++----------- tests/name.rs | 24 ++++----- tests/nft.rs | 14 +++-- tests/range.rs | 32 ++++++------ tests/server.rs | 34 ++++++------- tests/supply.rs | 6 +-- tests/traits.rs | 8 ++- tests/version.rs | 6 +-- tests/wallet.rs | 48 ++++++++---------- 14 files changed, 240 insertions(+), 224 deletions(-) diff --git a/tests/epochs.rs b/tests/epochs.rs index 69c758f4fc..a828f6edac 100644 --- a/tests/epochs.rs +++ b/tests/epochs.rs @@ -1,8 +1,8 @@ use super::*; #[test] -fn empty() -> Result { - Test::new()? +fn empty() { + Test::new() .args(&["epochs"]) .expected_stdout( " @@ -43,5 +43,5 @@ fn empty() -> Result { " .unindent(), ) - .run() + .run(); } diff --git a/tests/find.rs b/tests/find.rs index 39e0995ded..58b233c617 100644 --- a/tests/find.rs +++ b/tests/find.rs @@ -1,35 +1,36 @@ use super::*; #[test] -fn first_satoshi() -> Result { - Test::new()? +fn first_satoshi() { + Test::new() .command("find 0") .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") - .run() + .run(); } #[test] #[ignore] -fn first_satoshi_slot() -> Result { - Test::new()? +fn first_satoshi_slot() { + Test::new() .command("find 0 --slot") .expected_stdout("0x0x0x0\n") .blocks(1) - .run() + .run(); } #[test] -fn second_satoshi() -> Result { - Test::new()? +fn second_satoshi() { + Test::new() .command("find 1") .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:1\n") - .run() + .run(); } +// TODO: fix ignore tests #[test] #[ignore] -fn second_satoshi_slot() -> Result { - Test::new()? +fn second_satoshi_slot() { + Test::new() .command("find 1 --slot") .expected_stdout("0x0x0x1\n") .blocks(1) @@ -37,28 +38,28 @@ fn second_satoshi_slot() -> Result { } #[test] -fn first_satoshi_of_second_block() -> Result { - Test::new()? +fn first_satoshi_of_second_block() { + Test::new() .command("find 5000000000") .blocks(1) .expected_stdout("150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0:0\n") - .run() + .run(); } #[test] #[ignore] -fn first_satoshi_of_second_block_slot() -> Result { - Test::new()? +fn first_satoshi_of_second_block_slot() { + Test::new() .command("find 5000000000 --slot") .expected_stdout("1x0x0x0\n") .blocks(1) .blocks(1) - .run() + .run(); } #[test] -fn first_satoshi_spent_in_second_block() -> Result { - Test::new()? +fn first_satoshi_spent_in_second_block() { + Test::new() .command("find 0") .blocks(101) .transaction(TransactionOptions { @@ -68,13 +69,13 @@ fn first_satoshi_spent_in_second_block() -> Result { }) .blocks(1) .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") - .run() + .run(); } #[test] #[ignore] -fn first_satoshi_spent_in_second_block_slot() -> Result { - Test::new()? +fn first_satoshi_spent_in_second_block_slot() { + Test::new() .command("find 0 --slot") .expected_stdout("1x1x0x0\n") .blocks(1) @@ -84,13 +85,13 @@ fn first_satoshi_spent_in_second_block_slot() -> Result { output_count: 1, fee: 0, }) - .run() + .run(); } #[test] #[ignore] -fn mining_and_spending_transaction_in_same_block() -> Result { - Test::new()? +fn mining_and_spending_transaction_in_same_block() { + Test::new() .command("find 0 --slot") .blocks(1) .blocks(1) @@ -105,14 +106,14 @@ fn mining_and_spending_transaction_in_same_block() -> Result { fee: 0, }) .expected_stdout("1x2x0x0\n") - .run() + .run(); } #[test] -fn unmined_satoshi_in_second_block() -> Result { - Test::new()? +fn unmined_satoshi_in_second_block() { + Test::new() .expected_stderr("error: Ordinal has not been mined as of index height\n") .expected_status(1) .command("find 5000000000") - .run() + .run(); } diff --git a/tests/index.rs b/tests/index.rs index 11612291c0..6807b465d7 100644 --- a/tests/index.rs +++ b/tests/index.rs @@ -1,35 +1,43 @@ use super::*; #[test] -fn default_index_size() -> Result { - let state = Test::new()? +fn default_index_size() { + let state = Test::new() .command("find 0") .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") .blocks(1) - .output()? + .output() .state; assert_eq!( - state.tempdir.path().join("index.redb").metadata()?.len(), + state + .tempdir + .path() + .join("index.redb") + .metadata() + .unwrap() + .len(), 1 << 20 ); - - Ok(()) } #[test] -fn custom_index_size() -> Result { - let state = Test::new()? +fn custom_index_size() { + let state = Test::new() .command("--max-index-size 1mib find 0") .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") .blocks(1) - .output()? + .output() .state; assert_eq!( - state.tempdir.path().join("index.redb").metadata()?.len(), + state + .tempdir + .path() + .join("index.redb") + .metadata() + .unwrap() + .len(), 1 << 20 ); - - Ok(()) } diff --git a/tests/info.rs b/tests/info.rs index c763be271f..f9003de7a9 100644 --- a/tests/info.rs +++ b/tests/info.rs @@ -1,10 +1,10 @@ use super::*; #[test] -fn basic() -> Result { - let output = Test::new()?.command("index").output()?; +fn basic() { + let output = Test::new().command("index").output(); - Test::with_state(output.state)? + Test::with_state(output.state) .command("info") .stdout_regex( r" @@ -19,5 +19,5 @@ fn basic() -> Result { " .unindent(), ) - .run() + .run(); } diff --git a/tests/lib.rs b/tests/lib.rs index bcfcf9a2d9..3162d8b55a 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -24,7 +24,6 @@ use { regex::Regex, std::{ collections::BTreeMap, - error::Error, ffi::OsString, fs, net::TcpListener, @@ -52,8 +51,6 @@ mod traits; mod version; mod wallet; -type Result = std::result::Result>; - static ONCE: Once = Once::new(); fn free_port() -> u16 { @@ -218,11 +215,11 @@ impl Drop for State { } impl<'a> Test<'a> { - fn new() -> Result { + fn new() -> Self { Self::with_state(State::new()) } - fn with_state(state: State) -> Result { + fn with_state(state: State) -> Self { ONCE.call_once(|| { env_logger::init(); }); @@ -237,9 +234,9 @@ impl<'a> Test<'a> { expected_stdout: Expected::String(String::new()), }; - test.sync()?; + test.sync(); - Ok(test) + test } fn command(self, args: &str) -> Self { @@ -321,40 +318,39 @@ impl<'a> Test<'a> { self } - fn run(self) -> Result { - self.test(None).map(|_| ()) + fn run(self) { + self.test(None); } - fn output(self) -> Result { + fn output(self) -> Output { self.test(None) } - fn run_server(self, port: u16) -> Result { - self.test(Some(port)).map(|_| ()) + fn run_server(self, port: u16) { + self.test(Some(port)); } - fn get_block(&self, height: u64) -> Result { - Ok( - self - .state - .client - .get_block(&self.state.client.get_block_hash(height)?)?, - ) + fn get_block(&self, height: u64) -> Block { + self + .state + .client + .get_block(&self.state.client.get_block_hash(height).unwrap()) + .unwrap() } fn run_server_output(self, port: u16) -> Output { - self.test(Some(port)).unwrap() + self.test(Some(port)) } - fn sync(&self) -> Result { + fn sync(&self) { self .state .wallet - .sync(&self.state.blockchain, SyncOptions::default())?; - Ok(()) + .sync(&self.state.blockchain, SyncOptions::default()) + .unwrap(); } - fn test(self, port: Option) -> Result { + fn test(self, port: Option) -> Output { let client = reqwest::blocking::Client::new(); log::info!("Spawning child process..."); @@ -373,7 +369,8 @@ impl<'a> Test<'a> { .arg(format!("--rpc-url=localhost:{}", self.state.rpc_port)) .arg("--cookie-file=bitcoin/regtest/.cookie") .args(self.args.clone()) - .spawn()?; + .spawn() + .unwrap(); let start = Instant::now(); let mut healthy = false; @@ -411,35 +408,41 @@ impl<'a> Test<'a> { for event in &self.events { match event { Event::Blocks(n) => { - self.state.client.generate_to_address( - *n, - &self - .state - .wallet - .get_address(AddressIndex::Peek(0))? - .address, - )?; + self + .state + .client + .generate_to_address( + *n, + &self + .state + .wallet + .get_address(AddressIndex::Peek(0)) + .unwrap() + .address, + ) + .unwrap(); } Event::Request(request, status, expected_response) => { if healthy { let response = client .get(&format!("http://127.0.0.1:{}/{request}", port.unwrap())) - .send()?; + .send() + .unwrap(); log::info!("{:?}", response); assert_eq!(response.status().as_u16(), *status); - assert_eq!(response.text()?, *expected_response); + assert_eq!(response.text().unwrap(), *expected_response); successful_requests += 1; } else { panic!("Tried to make a request when unhealthy"); } } Event::Transaction(options) => { - self.sync()?; + self.sync(); let input_value = options .slots .iter() - .map(|slot| self.get_block(slot.0 as u64).unwrap().txdata[slot.1].output[slot.2].value) + .map(|slot| self.get_block(slot.0 as u64).txdata[slot.1].output[slot.2].value) .sum::(); let output_value = input_value - options.fee; @@ -456,17 +459,19 @@ impl<'a> Test<'a> { .slots .iter() .map(|slot| OutPoint { - txid: self.get_block(slot.0 as u64).unwrap().txdata[slot.1].txid(), + txid: self.get_block(slot.0 as u64).txdata[slot.1].txid(), vout: slot.2 as u32, }) .collect::>(), - )? + ) + .unwrap() .set_recipients(vec![ ( self .state .wallet - .get_address(AddressIndex::Peek(0))? + .get_address(AddressIndex::Peek(0)) + .unwrap() .address .script_pubkey(), output_value / options.output_count as u64 @@ -474,23 +479,32 @@ impl<'a> Test<'a> { options.output_count ]); - builder.finish()? + builder.finish().unwrap() }; - if !self.state.wallet.sign(&mut psbt, SignOptions::default())? { + if !self + .state + .wallet + .sign(&mut psbt, SignOptions::default()) + .unwrap() + { panic!("Failed to sign transaction"); } - self.state.client.call::( - "sendrawtransaction", - &[psbt.extract_tx().raw_hex().into(), 21000000.into()], - )?; + self + .state + .client + .call::( + "sendrawtransaction", + &[psbt.extract_tx().raw_hex().into(), 21000000.into()], + ) + .unwrap(); } } } let child = if let Some(child) = child { - signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT)?; + signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT).unwrap(); child } else { Command::new(executable_path("ord")) @@ -506,13 +520,14 @@ impl<'a> Test<'a> { .arg(format!("--rpc-url=localhost:{}", self.state.rpc_port)) .arg("--cookie-file=bitcoin/regtest/.cookie") .args(self.args.clone()) - .spawn()? + .spawn() + .unwrap() }; - let output = child.wait_with_output()?; + let output = child.wait_with_output().unwrap(); - let stdout = str::from_utf8(&output.stdout)?; - let stderr = str::from_utf8(&output.stderr)?; + let stdout = str::from_utf8(&output.stdout).unwrap(); + let stderr = str::from_utf8(&output.stderr).unwrap(); if output.status.code() != Some(self.expected_status) { panic!( @@ -521,7 +536,7 @@ impl<'a> Test<'a> { ); } - let log_line_re = Regex::new(r"(?m)^\[.*\n")?; + let log_line_re = Regex::new(r"(?m)^\[.*\n").unwrap(); for log_line in log_line_re.find_iter(stderr) { print!("{}", log_line.as_str()) @@ -542,10 +557,10 @@ impl<'a> Test<'a> { "Unsuccessful requests" ); - Ok(Output { + Output { stdout: stdout.to_string(), state: self.state, - }) + } } fn blocks(mut self, n: u64) -> Self { @@ -558,8 +573,8 @@ impl<'a> Test<'a> { self } - fn write(self, path: &str, contents: &str) -> Result { - fs::write(self.state.tempdir.path().join(path), contents)?; - Ok(self) + fn write(self, path: &str, contents: &str) -> Self { + fs::write(self.state.tempdir.path().join(path), contents).unwrap(); + self } } diff --git a/tests/list.rs b/tests/list.rs index 48cbc4fe45..5b0324db6d 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -1,25 +1,25 @@ use super::*; #[test] -fn first_coinbase_transaction() -> Result { - Test::new()? +fn first_coinbase_transaction() { + Test::new() .command("list 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0") .expected_stdout("[0,5000000000)\n") - .run() + .run(); } #[test] -fn second_coinbase_transaction() -> Result { - Test::new()? +fn second_coinbase_transaction() { + Test::new() .command("list 150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0") .blocks(1) .expected_stdout("[5000000000,10000000000)\n") - .run() + .run(); } #[test] -fn split_ranges_are_tracked_correctly() -> Result { - Test::new()? +fn split_ranges_are_tracked_correctly() { + Test::new() .command("list 36b5e3d6454fdadf762e8adc28140bbf38ee673c68bf05aaac82add84c0ff862:0") .blocks(101) .transaction(TransactionOptions { @@ -29,9 +29,9 @@ fn split_ranges_are_tracked_correctly() -> Result { }) .blocks(1) .expected_stdout("[5000000000,7500000000)\n") - .run()?; + .run(); - Test::new()? + Test::new() .command("list 36b5e3d6454fdadf762e8adc28140bbf38ee673c68bf05aaac82add84c0ff862:1") .blocks(101) .transaction(TransactionOptions { @@ -41,12 +41,12 @@ fn split_ranges_are_tracked_correctly() -> Result { }) .blocks(1) .expected_stdout("[7500000000,10000000000)\n") - .run() + .run(); } #[test] -fn merge_ranges_are_tracked_correctly() -> Result { - Test::new()? +fn merge_ranges_are_tracked_correctly() { + Test::new() .command("list 430f77dcea637d90d82ac561f9f1955119c0d25b690da250ba98872e15e9069f:0") .blocks(101) .transaction(TransactionOptions { @@ -62,12 +62,12 @@ fn merge_ranges_are_tracked_correctly() -> Result { }) .blocks(1) .expected_stdout("[5000000000,7500000000)\n[7500000000,10000000000)\n") - .run() + .run(); } #[test] -fn fee_paying_transaction_range() -> Result { - Test::new()? +fn fee_paying_transaction_range() { + Test::new() .command("list a57ccabdca48ada30a5e58459584e43691a56f4fcc51121d8aa9bf1d1c682603:0") .blocks(101) .transaction(TransactionOptions { @@ -77,9 +77,9 @@ fn fee_paying_transaction_range() -> Result { }) .blocks(1) .expected_stdout("[5000000000,7499999995)\n") - .run()?; + .run(); - Test::new()? + Test::new() .command("list a57ccabdca48ada30a5e58459584e43691a56f4fcc51121d8aa9bf1d1c682603:1") .blocks(101) .transaction(TransactionOptions { @@ -89,9 +89,9 @@ fn fee_paying_transaction_range() -> Result { }) .blocks(1) .expected_stdout("[7499999995,9999999990)\n") - .run()?; + .run(); - Test::new()? + Test::new() .command("list 721792011e3200abd01693490de5215b570da0048e55b66514201cb62396e376:0") .blocks(101) .transaction(TransactionOptions { @@ -101,12 +101,12 @@ fn fee_paying_transaction_range() -> Result { }) .blocks(1) .expected_stdout("[510000000000,515000000000)\n[9999999990,10000000000)\n") - .run() + .run(); } #[test] -fn two_fee_paying_transaction_range() -> Result { - Test::new()? +fn two_fee_paying_transaction_range() { + Test::new() .command("list 7f3b38a0bc60f581fd7f4b178ca2a697575000e212c8752b455ec134d160ea9a:0") .blocks(102) .transaction(TransactionOptions { @@ -127,8 +127,8 @@ fn two_fee_paying_transaction_range() -> Result { } #[test] -fn null_output() -> Result { - Test::new()? +fn null_output() { + Test::new() .command("list 3dbc87de25bf5a52ddfa8038bda36e09622f4dec7951d81ac43e4b0e8c54bc5b:0") .blocks(101) .transaction(TransactionOptions { @@ -142,8 +142,8 @@ fn null_output() -> Result { } #[test] -fn null_input() -> Result { - Test::new()? +fn null_input() { + Test::new() .command("list 3dbc87de25bf5a52ddfa8038bda36e09622f4dec7951d81ac43e4b0e8c54bc5b:0") .blocks(101) .transaction(TransactionOptions { @@ -162,8 +162,8 @@ fn null_input() -> Result { } #[test] -fn old_transactions_are_pruned() -> Result { - Test::new()? +fn old_transactions_are_pruned() { + Test::new() .command("list 150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0") .blocks(101) .transaction(TransactionOptions { diff --git a/tests/name.rs b/tests/name.rs index 6c3859481e..defc915530 100644 --- a/tests/name.rs +++ b/tests/name.rs @@ -1,8 +1,8 @@ use super::*; #[test] -fn empty() -> Result { - Test::new()? +fn empty() { + Test::new() .args(&["name", ""]) .expected_stderr("error: Invalid name\n") .expected_status(1) @@ -10,32 +10,32 @@ fn empty() -> Result { } #[test] -fn a() -> Result { - Test::new()? +fn a() { + Test::new() .args(&["name", "a"]) .expected_stdout("2099999997689999\n") .run() } #[test] -fn b() -> Result { - Test::new()? +fn b() { + Test::new() .args(&["name", "b"]) .expected_stdout("2099999997689998\n") .run() } #[test] -fn end_of_range() -> Result { - Test::new()? +fn end_of_range() { + Test::new() .args(&["name", "nvtdijuwxlp"]) .expected_stdout("0\n") .run() } #[test] -fn out_of_range() -> Result { - Test::new()? +fn out_of_range() { + Test::new() .args(&["name", "nvtdijuwxlr"]) .expected_stderr("error: Name out of range\n") .expected_status(1) @@ -43,8 +43,8 @@ fn out_of_range() -> Result { } #[test] -fn invalid() -> Result { - Test::new()? +fn invalid() { + Test::new() .args(&["name", "0"]) .expected_stderr("error: Invalid name\n") .expected_status(1) diff --git a/tests/nft.rs b/tests/nft.rs index a2a7812b61..6fee7129b9 100644 --- a/tests/nft.rs +++ b/tests/nft.rs @@ -1,9 +1,9 @@ use super::*; #[test] -fn mint_and_verify() -> Result { - let output = Test::new()? - .write("data.txt", "foo")? +fn mint_and_verify() { + let output = Test::new() + .write("data.txt", "foo") .args(&[ "mint", "--ordinal", @@ -15,9 +15,9 @@ fn mint_and_verify() -> Result { "--output-path", "foo.nft", ]) - .output()?; + .output(); - Test::with_state(output.state)? + Test::with_state(output.state) .command("verify foo.nft") .expected_stderr( "NFT is valid! @@ -27,7 +27,5 @@ Data hash: 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae ", ) .expected_stdout("foo") - .run()?; - - Ok(()) + .run(); } diff --git a/tests/range.rs b/tests/range.rs index 317b8b0da8..e249cb0b8a 100644 --- a/tests/range.rs +++ b/tests/range.rs @@ -1,64 +1,64 @@ use super::*; #[test] -fn genesis() -> Result { - Test::new()? +fn genesis() { + Test::new() .args(&["range", "0"]) .expected_stdout("[0,5000000000)\n") .run() } #[test] -fn second_block() -> Result { - Test::new()? +fn second_block() { + Test::new() .args(&["range", "1"]) .expected_stdout("[5000000000,10000000000)\n") .run() } #[test] -fn last_block_with_subsidy() -> Result { - Test::new()? +fn last_block_with_subsidy() { + Test::new() .args(&["range", "6929999"]) .expected_stdout("[2099999997689999,2099999997690000)\n") .run() } #[test] -fn first_block_without_subsidy() -> Result { - Test::new()? +fn first_block_without_subsidy() { + Test::new() .args(&["range", "6930000"]) .expected_stdout("[2099999997690000,2099999997690000)\n") .run() } #[test] -fn genesis_names() -> Result { - Test::new()? +fn genesis_names() { + Test::new() .args(&["range", "--name", "0"]) .expected_stdout("[nvtdijuwxlp,nvtcsezkbth)\n") .run() } #[test] -fn names_before_last() -> Result { - Test::new()? +fn names_before_last() { + Test::new() .args(&["range", "--name", "6929998"]) .expected_stdout("[b,a)\n") .run() } #[test] -fn last_name() -> Result { - Test::new()? +fn last_name() { + Test::new() .args(&["range", "--name", "6929999"]) .expected_stdout("[a,)\n") .run() } #[test] -fn block_with_no_subsidy_range() -> Result { - Test::new()? +fn block_with_no_subsidy_range() { + Test::new() .args(&["range", "--name", "6930000"]) .expected_stdout("[,)\n") .run() diff --git a/tests/server.rs b/tests/server.rs index e62e4e8cf3..7b6ad6df48 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -1,12 +1,12 @@ use super::*; #[test] -fn list() -> Result { +fn list() { let port = free_port(); log::info!("port: {}", port); - Test::new()? + Test::new() .command(&format!("server --address 127.0.0.1 --http-port {port}")) .blocks(1) .request( @@ -18,20 +18,20 @@ fn list() -> Result { } #[test] -fn status() -> Result { +fn status() { let port = free_port(); - Test::new()? + Test::new() .command(&format!("server --address 127.0.0.1 --http-port {port}")) .request("status", 200, "") .run_server(port) } #[test] -fn continuously_index_ranges() -> Result { +fn continuously_index_ranges() { let port = free_port(); - Test::new()? + Test::new() .command(&format!("server --address 127.0.0.1 --http-port {port}")) .request( "list/150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0", @@ -48,8 +48,8 @@ fn continuously_index_ranges() -> Result { } #[test] -fn http_or_https_port_is_required() -> Result { - Test::new()? +fn http_or_https_port_is_required() { + Test::new() .command("server --address 127.0.0.1") .stderr_regex("error: The following required arguments were not provided:\n <--http-port \\|--https-port >\n.*") .expected_status(2) @@ -57,8 +57,8 @@ fn http_or_https_port_is_required() -> Result { } #[test] -fn http_and_https_port_conflict() -> Result { - Test::new()? +fn http_and_https_port_conflict() { + Test::new() .command("server --address 127.0.0.1 --http-port 0 --https-port 0") .stderr_regex("error: The argument '--http-port ' cannot be used with '--https-port '\n.*") .expected_status(2) @@ -66,10 +66,10 @@ fn http_and_https_port_conflict() -> Result { } #[test] -fn http_port_requires_acme_flags() -> Result { +fn http_port_requires_acme_flags() { let port = free_port(); - Test::new()? + Test::new() .command("server --address 127.0.0.1 --https-port 0") .stderr_regex("error: The following required arguments were not provided:\n --acme-cache \n --acme-domain \n --acme-contact \n.*") .expected_status(2) @@ -77,19 +77,19 @@ fn http_port_requires_acme_flags() -> Result { } #[test] -fn acme_contact_accepts_multiple_values() -> Result { +fn acme_contact_accepts_multiple_values() { let port = free_port(); - Test::new()? + Test::new() .command("server --address 127.0.0.1 --http-port 0 --acme-contact foo --acme-contact bar") .run_server(port) } #[test] -fn acme_domain_accepts_multiple_values() -> Result { +fn acme_domain_accepts_multiple_values() { let port = free_port(); - Test::new()? + Test::new() .command("server --address 127.0.0.1 --http-port 0 --acme-domain foo --acme-domain bar") .run_server(port) } @@ -98,7 +98,7 @@ fn acme_domain_accepts_multiple_values() -> Result { fn creates_acme_cache() { let port = free_port(); - let output = Test::new().unwrap() + let output = Test::new() .command("server --address 127.0.0.1 --https-port 0 --acme-domain foo --acme-cache bar --acme-contact mailto:foo@bar.com") .run_server_output(port); diff --git a/tests/supply.rs b/tests/supply.rs index 05b9e68865..6af4303bc1 100644 --- a/tests/supply.rs +++ b/tests/supply.rs @@ -1,8 +1,8 @@ use super::*; #[test] -fn genesis() -> Result { - Test::new()? +fn genesis() { + Test::new() .args(&["supply"]) .expected_stdout( &" @@ -13,5 +13,5 @@ fn genesis() -> Result { " .unindent(), ) - .run() + .run(); } diff --git a/tests/traits.rs b/tests/traits.rs index 54c16175ec..213fb96b2d 100644 --- a/tests/traits.rs +++ b/tests/traits.rs @@ -2,11 +2,9 @@ use super::*; fn case(ordinal: u64, name: &str, value: &str) { let stdout = Test::new() - .unwrap() .args(&["traits", &ordinal.to_string()]) .ignore_stdout() .output() - .unwrap() .stdout; let map = stdout @@ -22,12 +20,12 @@ fn case(ordinal: u64, name: &str, value: &str) { } #[test] -fn invalid_ordinal() -> Result { - Test::new()? +fn invalid_ordinal() { + Test::new() .args(&["traits", "2099999997690000"]) .stderr_regex("error: Invalid value \"2099999997690000\" for '': Invalid ordinal\n.*") .expected_status(2) - .run() + .run(); } #[test] diff --git a/tests/version.rs b/tests/version.rs index e70d16e47b..1603b5509e 100644 --- a/tests/version.rs +++ b/tests/version.rs @@ -1,10 +1,10 @@ use super::*; #[test] -fn flag() -> Result { - Test::new()? +fn flag() { + Test::new() .command("--version") .stdout_regex("ord .*\n") .blocks(1) - .run() + .run(); } diff --git a/tests/wallet.rs b/tests/wallet.rs index cdf721119d..1116223df8 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -9,13 +9,13 @@ fn path(path: &str) -> String { } #[test] -fn init_existing_wallet() -> Result { - let state = Test::new()? +fn init_existing_wallet() { + let state = Test::new() .command("wallet init") .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") - .output()? + .output() .state; assert!(state @@ -26,7 +26,7 @@ fn init_existing_wallet() -> Result { assert!(state.tempdir.path().join(path("ord/entropy")).exists()); - Test::with_state(state)? + Test::with_state(state) .command("wallet init") .set_home_to_tempdir() .expected_status(1) @@ -35,13 +35,13 @@ fn init_existing_wallet() -> Result { } #[test] -fn init_nonexistent_wallet() -> Result { - let output = Test::new()? +fn init_nonexistent_wallet() { + let output = Test::new() .command("wallet init") .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") - .output()?; + .output(); assert!(output .state @@ -56,63 +56,59 @@ fn init_nonexistent_wallet() -> Result { .path() .join(path("ord/entropy")) .exists()); - - Ok(()) } #[test] -fn load_corrupted_entropy() -> Result { - let state = Test::new()? +fn load_corrupted_entropy() { + let state = Test::new() .command("wallet init") .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") - .output()? + .output() .state; let entropy_path = state.tempdir.path().join(path("ord/entropy")); assert!(entropy_path.exists()); - let mut entropy = fs::read(&entropy_path)?; + let mut entropy = fs::read(&entropy_path).unwrap(); entropy[0] ^= 0b0000_1000; - fs::write(&entropy_path, entropy)?; + fs::write(&entropy_path, entropy).unwrap(); - Test::with_state(state)? + Test::with_state(state) .command("wallet fund") .set_home_to_tempdir() .expected_status(1) .expected_stderr("error: ChecksumMismatch\n") - .run()?; - - Ok(()) + .run(); } #[test] -fn fund_existing_wallet() -> Result { - let state = Test::new()? +fn fund_existing_wallet() { + let state = Test::new() .command("wallet init") .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") .set_home_to_tempdir() - .output()? + .output() .state; - Test::with_state(state)? + Test::with_state(state) .command("wallet fund") .set_home_to_tempdir() .stdout_regex("^tb1.*\n") - .run() + .run(); } #[test] -fn fund_nonexistent_wallet() -> Result { - Test::new()? +fn fund_nonexistent_wallet() { + Test::new() .command("wallet fund") .set_home_to_tempdir() .expected_status(1) .expected_stderr("error: Wallet doesn't exist.\n") - .run() + .run(); } From eae8092a9ea8dad1da02a5b0b974b9935e4d039f Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 2 Aug 2022 12:40:57 -0700 Subject: [PATCH 34/61] Move state and test into own files --- tests/lib.rs | 479 +------------------------------------------------ tests/state.rs | 102 +++++++++++ tests/test.rs | 376 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 481 insertions(+), 476 deletions(-) create mode 100644 tests/state.rs create mode 100644 tests/test.rs diff --git a/tests/lib.rs b/tests/lib.rs index 3162d8b55a..22d5180ce7 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,6 +1,7 @@ #![allow(clippy::type_complexity)] use { + self::{state::State, test::Test}, bdk::{ blockchain::{ rpc::{RpcBlockchain, RpcConfig}, @@ -46,7 +47,9 @@ mod name; mod nft; mod range; mod server; +mod state; mod supply; +mod test; mod traits; mod version; mod wallet; @@ -102,479 +105,3 @@ struct TransactionOptions<'a> { output_count: usize, fee: u64, } - -struct Test<'a> { - args: Vec, - envs: Vec<(OsString, OsString)>, - events: Vec>, - expected_status: i32, - expected_stderr: Expected, - expected_stdout: Expected, - state: State, -} - -struct State { - bitcoind: Child, - tempdir: TempDir, - client: Client, - wallet: Wallet, - blockchain: RpcBlockchain, - rpc_port: u16, -} - -impl State { - fn new() -> Self { - let tempdir = TempDir::new().unwrap(); - - fs::create_dir(tempdir.path().join("bitcoin")).unwrap(); - - let rpc_port = free_port(); - - let bitcoind = Command::new("bitcoind") - .stdout(if log::max_level() >= LevelFilter::Info { - Stdio::inherit() - } else { - Stdio::piped() - }) - .args(&[ - "-minrelaytxfee=0", - "-blockmintxfee=0", - "-dustrelayfee=0", - "-maxtxfee=21000000", - "-datadir=bitcoin", - "-regtest", - "-networkactive=0", - "-listen=0", - &format!("-rpcport={rpc_port}"), - ]) - .current_dir(&tempdir.path()) - .spawn() - .unwrap(); - - let cookiefile = tempdir.path().join("bitcoin/regtest/.cookie"); - - while !cookiefile.is_file() {} - - let client = Client::new( - &format!("localhost:{rpc_port}"), - bitcoincore_rpc::Auth::CookieFile(cookiefile.clone()), - ) - .unwrap(); - - for attempt in 0..=300 { - match client.get_blockchain_info() { - Ok(_) => break, - Err(err) => { - if attempt == 300 { - panic!("Failed to connect to bitcoind: {err}"); - } - } - } - sleep(Duration::from_millis(100)); - } - - let wallet = Wallet::new( - Bip84( - ( - Mnemonic::parse("book fit fly ketchup also elevator scout mind edit fatal where rookie") - .unwrap(), - None, - ), - KeychainKind::External, - ), - None, - Network::Regtest, - MemoryDatabase::new(), - ) - .unwrap(); - - let blockchain = RpcBlockchain::from_config(&RpcConfig { - url: format!("localhost:{rpc_port}"), - auth: bdk::blockchain::rpc::Auth::Cookie { file: cookiefile }, - network: Network::Regtest, - wallet_name: "test".to_string(), - skip_blocks: None, - }) - .unwrap(); - - State { - tempdir, - rpc_port, - bitcoind, - client, - wallet, - blockchain, - } - } -} - -impl Drop for State { - fn drop(&mut self) { - self.bitcoind.kill().unwrap(); - } -} - -impl<'a> Test<'a> { - fn new() -> Self { - Self::with_state(State::new()) - } - - fn with_state(state: State) -> Self { - ONCE.call_once(|| { - env_logger::init(); - }); - - let test = Self { - args: Vec::new(), - state, - envs: Vec::new(), - events: Vec::new(), - expected_status: 0, - expected_stderr: Expected::Ignore, - expected_stdout: Expected::String(String::new()), - }; - - test.sync(); - - test - } - - fn command(self, args: &str) -> Self { - Self { - args: args.split_whitespace().map(str::to_owned).collect(), - ..self - } - } - - fn args(self, args: &[&str]) -> Self { - Self { - args: self - .args - .into_iter() - .chain(args.iter().cloned().map(str::to_owned)) - .collect(), - ..self - } - } - - fn expected_stdout(self, expected_stdout: impl AsRef) -> Self { - Self { - expected_stdout: Expected::String(expected_stdout.as_ref().to_owned()), - ..self - } - } - - fn stdout_regex(self, expected_stdout: impl AsRef) -> Self { - Self { - expected_stdout: Expected::regex(expected_stdout.as_ref()), - ..self - } - } - - // TODO: do this always - fn set_home_to_tempdir(mut self) -> Self { - self.envs.push(( - OsString::from("HOME"), - OsString::from(self.state.tempdir.path()), - )); - - self - } - - fn expected_stderr(self, expected_stderr: &str) -> Self { - Self { - expected_stderr: Expected::String(expected_stderr.to_owned()), - ..self - } - } - - fn stderr_regex(self, expected_stderr: impl AsRef) -> Self { - Self { - expected_stderr: Expected::regex(expected_stderr.as_ref()), - ..self - } - } - - fn expected_status(self, expected_status: i32) -> Self { - Self { - expected_status, - ..self - } - } - - fn ignore_stdout(self) -> Self { - Self { - expected_stdout: Expected::Ignore, - ..self - } - } - - fn request(mut self, path: &str, status: u16, response: &str) -> Self { - self.events.push(Event::Request( - path.to_string(), - status, - response.to_string(), - )); - self - } - - fn run(self) { - self.test(None); - } - - fn output(self) -> Output { - self.test(None) - } - - fn run_server(self, port: u16) { - self.test(Some(port)); - } - - fn get_block(&self, height: u64) -> Block { - self - .state - .client - .get_block(&self.state.client.get_block_hash(height).unwrap()) - .unwrap() - } - - fn run_server_output(self, port: u16) -> Output { - self.test(Some(port)) - } - - fn sync(&self) { - self - .state - .wallet - .sync(&self.state.blockchain, SyncOptions::default()) - .unwrap(); - } - - fn test(self, port: Option) -> Output { - let client = reqwest::blocking::Client::new(); - - log::info!("Spawning child process..."); - - let (healthy, child) = if let Some(port) = port { - let child = Command::new(executable_path("ord")) - .envs(self.envs.clone()) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { - Stdio::piped() - } else { - Stdio::inherit() - }) - .current_dir(&self.state.tempdir) - .arg(format!("--rpc-url=localhost:{}", self.state.rpc_port)) - .arg("--cookie-file=bitcoin/regtest/.cookie") - .args(self.args.clone()) - .spawn() - .unwrap(); - - let start = Instant::now(); - let mut healthy = false; - - loop { - if let Ok(response) = client - .get(&format!("http://127.0.0.1:{port}/status")) - .send() - { - if response.status().is_success() { - healthy = true; - break; - } - } - - if Instant::now() - start > Duration::from_secs(1) { - break; - } - - sleep(Duration::from_millis(100)); - } - - (healthy, Some(child)) - } else { - (false, None) - }; - - log::info!( - "Server status: {}", - if healthy { "healthy" } else { "not healthy " } - ); - - let mut successful_requests = 0; - - for event in &self.events { - match event { - Event::Blocks(n) => { - self - .state - .client - .generate_to_address( - *n, - &self - .state - .wallet - .get_address(AddressIndex::Peek(0)) - .unwrap() - .address, - ) - .unwrap(); - } - Event::Request(request, status, expected_response) => { - if healthy { - let response = client - .get(&format!("http://127.0.0.1:{}/{request}", port.unwrap())) - .send() - .unwrap(); - log::info!("{:?}", response); - assert_eq!(response.status().as_u16(), *status); - assert_eq!(response.text().unwrap(), *expected_response); - successful_requests += 1; - } else { - panic!("Tried to make a request when unhealthy"); - } - } - Event::Transaction(options) => { - self.sync(); - - let input_value = options - .slots - .iter() - .map(|slot| self.get_block(slot.0 as u64).txdata[slot.1].output[slot.2].value) - .sum::(); - - let output_value = input_value - options.fee; - - let (mut psbt, _) = { - let mut builder = self.state.wallet.build_tx(); - - builder - .manually_selected_only() - .fee_absolute(options.fee) - .allow_dust(true) - .add_utxos( - &options - .slots - .iter() - .map(|slot| OutPoint { - txid: self.get_block(slot.0 as u64).txdata[slot.1].txid(), - vout: slot.2 as u32, - }) - .collect::>(), - ) - .unwrap() - .set_recipients(vec![ - ( - self - .state - .wallet - .get_address(AddressIndex::Peek(0)) - .unwrap() - .address - .script_pubkey(), - output_value / options.output_count as u64 - ); - options.output_count - ]); - - builder.finish().unwrap() - }; - - if !self - .state - .wallet - .sign(&mut psbt, SignOptions::default()) - .unwrap() - { - panic!("Failed to sign transaction"); - } - - self - .state - .client - .call::( - "sendrawtransaction", - &[psbt.extract_tx().raw_hex().into(), 21000000.into()], - ) - .unwrap(); - } - } - } - - let child = if let Some(child) = child { - signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT).unwrap(); - child - } else { - Command::new(executable_path("ord")) - .envs(self.envs.clone()) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { - Stdio::piped() - } else { - Stdio::inherit() - }) - .current_dir(&self.state.tempdir) - .arg(format!("--rpc-url=localhost:{}", self.state.rpc_port)) - .arg("--cookie-file=bitcoin/regtest/.cookie") - .args(self.args.clone()) - .spawn() - .unwrap() - }; - - let output = child.wait_with_output().unwrap(); - - let stdout = str::from_utf8(&output.stdout).unwrap(); - let stderr = str::from_utf8(&output.stderr).unwrap(); - - if output.status.code() != Some(self.expected_status) { - panic!( - "Test failed: {}\nstdout:\n{}\nstderr:\n{}", - output.status, stdout, stderr - ); - } - - let log_line_re = Regex::new(r"(?m)^\[.*\n").unwrap(); - - for log_line in log_line_re.find_iter(stderr) { - print!("{}", log_line.as_str()) - } - - let stripped_stderr = log_line_re.replace_all(stderr, ""); - - self.expected_stderr.assert_match(&stripped_stderr); - self.expected_stdout.assert_match(stdout); - - assert_eq!( - successful_requests, - self - .events - .iter() - .filter(|event| matches!(event, Event::Request(..))) - .count(), - "Unsuccessful requests" - ); - - Output { - stdout: stdout.to_string(), - state: self.state, - } - } - - fn blocks(mut self, n: u64) -> Self { - self.events.push(Event::Blocks(n)); - self - } - - fn transaction(mut self, options: TransactionOptions<'a>) -> Self { - self.events.push(Event::Transaction(options)); - self - } - - fn write(self, path: &str, contents: &str) -> Self { - fs::write(self.state.tempdir.path().join(path), contents).unwrap(); - self - } -} diff --git a/tests/state.rs b/tests/state.rs new file mode 100644 index 0000000000..a2cc7336f2 --- /dev/null +++ b/tests/state.rs @@ -0,0 +1,102 @@ +use super::*; + +pub(crate) struct State { + bitcoind: Child, + pub(crate) tempdir: TempDir, + pub(crate) client: Client, + pub(crate) wallet: Wallet, + pub(crate) blockchain: RpcBlockchain, + pub(crate) rpc_port: u16, +} + +impl State { + pub(crate) fn new() -> Self { + let tempdir = TempDir::new().unwrap(); + + fs::create_dir(tempdir.path().join("bitcoin")).unwrap(); + + let rpc_port = free_port(); + + let bitcoind = Command::new("bitcoind") + .stdout(if log::max_level() >= LevelFilter::Info { + Stdio::inherit() + } else { + Stdio::piped() + }) + .args(&[ + "-minrelaytxfee=0", + "-blockmintxfee=0", + "-dustrelayfee=0", + "-maxtxfee=21000000", + "-datadir=bitcoin", + "-regtest", + "-networkactive=0", + "-listen=0", + &format!("-rpcport={rpc_port}"), + ]) + .current_dir(&tempdir.path()) + .spawn() + .unwrap(); + + let cookiefile = tempdir.path().join("bitcoin/regtest/.cookie"); + + while !cookiefile.is_file() {} + + let client = Client::new( + &format!("localhost:{rpc_port}"), + bitcoincore_rpc::Auth::CookieFile(cookiefile.clone()), + ) + .unwrap(); + + for attempt in 0..=300 { + match client.get_blockchain_info() { + Ok(_) => break, + Err(err) => { + if attempt == 300 { + panic!("Failed to connect to bitcoind: {err}"); + } + } + } + sleep(Duration::from_millis(100)); + } + + let wallet = Wallet::new( + Bip84( + ( + Mnemonic::parse("book fit fly ketchup also elevator scout mind edit fatal where rookie") + .unwrap(), + None, + ), + KeychainKind::External, + ), + None, + Network::Regtest, + MemoryDatabase::new(), + ) + .unwrap(); + + let blockchain = RpcBlockchain::from_config(&RpcConfig { + url: format!("localhost:{rpc_port}"), + auth: bdk::blockchain::rpc::Auth::Cookie { file: cookiefile }, + network: Network::Regtest, + wallet_name: "test".to_string(), + skip_blocks: None, + }) + .unwrap(); + + State { + tempdir, + rpc_port, + bitcoind, + client, + wallet, + blockchain, + } + } +} + +impl Drop for State { + fn drop(&mut self) { + self.bitcoind.kill().unwrap(); + } +} diff --git a/tests/test.rs b/tests/test.rs new file mode 100644 index 0000000000..d9069a302c --- /dev/null +++ b/tests/test.rs @@ -0,0 +1,376 @@ +use super::*; + +pub(crate) struct Test<'a> { + args: Vec, + envs: Vec<(OsString, OsString)>, + events: Vec>, + expected_status: i32, + expected_stderr: Expected, + expected_stdout: Expected, + state: State, +} + +impl<'a> Test<'a> { + pub(crate) fn new() -> Self { + Self::with_state(State::new()) + } + + pub(crate) fn with_state(state: State) -> Self { + ONCE.call_once(|| { + env_logger::init(); + }); + + let test = Self { + args: Vec::new(), + state, + envs: Vec::new(), + events: Vec::new(), + expected_status: 0, + expected_stderr: Expected::Ignore, + expected_stdout: Expected::String(String::new()), + }; + + test.sync(); + + test + } + + pub(crate) fn command(self, args: &str) -> Self { + Self { + args: args.split_whitespace().map(str::to_owned).collect(), + ..self + } + } + + pub(crate) fn args(self, args: &[&str]) -> Self { + Self { + args: self + .args + .into_iter() + .chain(args.iter().cloned().map(str::to_owned)) + .collect(), + ..self + } + } + + pub(crate) fn expected_stdout(self, expected_stdout: impl AsRef) -> Self { + Self { + expected_stdout: Expected::String(expected_stdout.as_ref().to_owned()), + ..self + } + } + + pub(crate) fn stdout_regex(self, expected_stdout: impl AsRef) -> Self { + Self { + expected_stdout: Expected::regex(expected_stdout.as_ref()), + ..self + } + } + + // TODO: do this always + pub(crate) fn set_home_to_tempdir(mut self) -> Self { + self.envs.push(( + OsString::from("HOME"), + OsString::from(self.state.tempdir.path()), + )); + + self + } + + pub(crate) fn expected_stderr(self, expected_stderr: &str) -> Self { + Self { + expected_stderr: Expected::String(expected_stderr.to_owned()), + ..self + } + } + + pub(crate) fn stderr_regex(self, expected_stderr: impl AsRef) -> Self { + Self { + expected_stderr: Expected::regex(expected_stderr.as_ref()), + ..self + } + } + + pub(crate) fn expected_status(self, expected_status: i32) -> Self { + Self { + expected_status, + ..self + } + } + + pub(crate) fn ignore_stdout(self) -> Self { + Self { + expected_stdout: Expected::Ignore, + ..self + } + } + + pub(crate) fn request(mut self, path: &str, status: u16, response: &str) -> Self { + self.events.push(Event::Request( + path.to_string(), + status, + response.to_string(), + )); + self + } + + pub(crate) fn run(self) { + self.test(None); + } + + pub(crate) fn output(self) -> Output { + self.test(None) + } + + pub(crate) fn run_server(self, port: u16) { + self.test(Some(port)); + } + + fn get_block(&self, height: u64) -> Block { + self + .state + .client + .get_block(&self.state.client.get_block_hash(height).unwrap()) + .unwrap() + } + + pub(crate) fn run_server_output(self, port: u16) -> Output { + self.test(Some(port)) + } + + fn sync(&self) { + self + .state + .wallet + .sync(&self.state.blockchain, SyncOptions::default()) + .unwrap(); + } + + fn test(self, port: Option) -> Output { + let client = reqwest::blocking::Client::new(); + + log::info!("Spawning child process..."); + + let (healthy, child) = if let Some(port) = port { + let child = Command::new(executable_path("ord")) + .envs(self.envs.clone()) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { + Stdio::piped() + } else { + Stdio::inherit() + }) + .current_dir(&self.state.tempdir) + .arg(format!("--rpc-url=localhost:{}", self.state.rpc_port)) + .arg("--cookie-file=bitcoin/regtest/.cookie") + .args(self.args.clone()) + .spawn() + .unwrap(); + + let start = Instant::now(); + let mut healthy = false; + + loop { + if let Ok(response) = client + .get(&format!("http://127.0.0.1:{port}/status")) + .send() + { + if response.status().is_success() { + healthy = true; + break; + } + } + + if Instant::now() - start > Duration::from_secs(1) { + break; + } + + sleep(Duration::from_millis(100)); + } + + (healthy, Some(child)) + } else { + (false, None) + }; + + log::info!( + "Server status: {}", + if healthy { "healthy" } else { "not healthy " } + ); + + let mut successful_requests = 0; + + for event in &self.events { + match event { + Event::Blocks(n) => { + self + .state + .client + .generate_to_address( + *n, + &self + .state + .wallet + .get_address(AddressIndex::Peek(0)) + .unwrap() + .address, + ) + .unwrap(); + } + Event::Request(request, status, expected_response) => { + if healthy { + let response = client + .get(&format!("http://127.0.0.1:{}/{request}", port.unwrap())) + .send() + .unwrap(); + log::info!("{:?}", response); + assert_eq!(response.status().as_u16(), *status); + assert_eq!(response.text().unwrap(), *expected_response); + successful_requests += 1; + } else { + panic!("Tried to make a request when unhealthy"); + } + } + Event::Transaction(options) => { + self.sync(); + + let input_value = options + .slots + .iter() + .map(|slot| self.get_block(slot.0 as u64).txdata[slot.1].output[slot.2].value) + .sum::(); + + let output_value = input_value - options.fee; + + let (mut psbt, _) = { + let mut builder = self.state.wallet.build_tx(); + + builder + .manually_selected_only() + .fee_absolute(options.fee) + .allow_dust(true) + .add_utxos( + &options + .slots + .iter() + .map(|slot| OutPoint { + txid: self.get_block(slot.0 as u64).txdata[slot.1].txid(), + vout: slot.2 as u32, + }) + .collect::>(), + ) + .unwrap() + .set_recipients(vec![ + ( + self + .state + .wallet + .get_address(AddressIndex::Peek(0)) + .unwrap() + .address + .script_pubkey(), + output_value / options.output_count as u64 + ); + options.output_count + ]); + + builder.finish().unwrap() + }; + + if !self + .state + .wallet + .sign(&mut psbt, SignOptions::default()) + .unwrap() + { + panic!("Failed to sign transaction"); + } + + self + .state + .client + .call::( + "sendrawtransaction", + &[psbt.extract_tx().raw_hex().into(), 21000000.into()], + ) + .unwrap(); + } + } + } + + let child = if let Some(child) = child { + signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT).unwrap(); + child + } else { + Command::new(executable_path("ord")) + .envs(self.envs.clone()) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { + Stdio::piped() + } else { + Stdio::inherit() + }) + .current_dir(&self.state.tempdir) + .arg(format!("--rpc-url=localhost:{}", self.state.rpc_port)) + .arg("--cookie-file=bitcoin/regtest/.cookie") + .args(self.args.clone()) + .spawn() + .unwrap() + }; + + let output = child.wait_with_output().unwrap(); + + let stdout = str::from_utf8(&output.stdout).unwrap(); + let stderr = str::from_utf8(&output.stderr).unwrap(); + + if output.status.code() != Some(self.expected_status) { + panic!( + "Test failed: {}\nstdout:\n{}\nstderr:\n{}", + output.status, stdout, stderr + ); + } + + let log_line_re = Regex::new(r"(?m)^\[.*\n").unwrap(); + + for log_line in log_line_re.find_iter(stderr) { + print!("{}", log_line.as_str()) + } + + let stripped_stderr = log_line_re.replace_all(stderr, ""); + + self.expected_stderr.assert_match(&stripped_stderr); + self.expected_stdout.assert_match(stdout); + + assert_eq!( + successful_requests, + self + .events + .iter() + .filter(|event| matches!(event, Event::Request(..))) + .count(), + "Unsuccessful requests" + ); + + Output { + stdout: stdout.to_string(), + state: self.state, + } + } + + pub(crate) fn blocks(mut self, n: u64) -> Self { + self.events.push(Event::Blocks(n)); + self + } + + pub(crate) fn transaction(mut self, options: TransactionOptions<'a>) -> Self { + self.events.push(Event::Transaction(options)); + self + } + + pub(crate) fn write(self, path: &str, contents: &str) -> Self { + fs::write(self.state.tempdir.path().join(path), contents).unwrap(); + self + } +} From bba0e9d8810e6150c9db00a2e0a6811fd080c066 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 2 Aug 2022 12:55:38 -0700 Subject: [PATCH 35/61] More stuff --- tests/lib.rs | 8 -- tests/state.rs | 13 +++ tests/test.rs | 300 +++++++++++++++++-------------------------------- 3 files changed, 113 insertions(+), 208 deletions(-) diff --git a/tests/lib.rs b/tests/lib.rs index 22d5180ce7..3ec303acde 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -54,8 +54,6 @@ mod traits; mod version; mod wallet; -static ONCE: Once = Once::new(); - fn free_port() -> u16 { TcpListener::bind("127.0.0.1:0") .unwrap() @@ -89,12 +87,6 @@ impl Expected { } } -enum Event<'a> { - Blocks(u64), - Request(String, u16, String), - Transaction(TransactionOptions<'a>), -} - struct Output { stdout: String, state: State, diff --git a/tests/state.rs b/tests/state.rs index a2cc7336f2..b722e3f26a 100644 --- a/tests/state.rs +++ b/tests/state.rs @@ -93,6 +93,19 @@ impl State { blockchain, } } + + // pub(crate) fn request(mut self, path: &str, status: u16, expected_response: &str) -> Self { + // let response = self + // .state + // .client + // .get(&format!("http://127.0.0.1:{}/{path}", self.state.rpc_port.unwrap())) + // .send() + // .unwrap(); + // log::info!("{:?}", response); + // assert_eq!(response.status().as_u16(), *status); + // assert_eq!(response.text().unwrap(), *expected_response); + // self + // } } impl Drop for State { diff --git a/tests/test.rs b/tests/test.rs index d9069a302c..cf5ed42c8d 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,21 +1,22 @@ use super::*; -pub(crate) struct Test<'a> { +pub(crate) struct Test { args: Vec, envs: Vec<(OsString, OsString)>, - events: Vec>, expected_status: i32, expected_stderr: Expected, expected_stdout: Expected, state: State, } -impl<'a> Test<'a> { +impl Test { pub(crate) fn new() -> Self { Self::with_state(State::new()) } pub(crate) fn with_state(state: State) -> Self { + static ONCE: Once = Once::new(); + ONCE.call_once(|| { env_logger::init(); }); @@ -24,7 +25,6 @@ impl<'a> Test<'a> { args: Vec::new(), state, envs: Vec::new(), - events: Vec::new(), expected_status: 0, expected_stderr: Expected::Ignore, expected_stdout: Expected::String(String::new()), @@ -105,15 +105,6 @@ impl<'a> Test<'a> { } } - pub(crate) fn request(mut self, path: &str, status: u16, response: &str) -> Self { - self.events.push(Event::Request( - path.to_string(), - status, - response.to_string(), - )); - self - } - pub(crate) fn run(self) { self.test(None); } @@ -147,180 +138,21 @@ impl<'a> Test<'a> { } fn test(self, port: Option) -> Output { - let client = reqwest::blocking::Client::new(); - - log::info!("Spawning child process..."); - - let (healthy, child) = if let Some(port) = port { - let child = Command::new(executable_path("ord")) - .envs(self.envs.clone()) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { - Stdio::piped() - } else { - Stdio::inherit() - }) - .current_dir(&self.state.tempdir) - .arg(format!("--rpc-url=localhost:{}", self.state.rpc_port)) - .arg("--cookie-file=bitcoin/regtest/.cookie") - .args(self.args.clone()) - .spawn() - .unwrap(); - - let start = Instant::now(); - let mut healthy = false; - - loop { - if let Ok(response) = client - .get(&format!("http://127.0.0.1:{port}/status")) - .send() - { - if response.status().is_success() { - healthy = true; - break; - } - } - - if Instant::now() - start > Duration::from_secs(1) { - break; - } - - sleep(Duration::from_millis(100)); - } - - (healthy, Some(child)) - } else { - (false, None) - }; - - log::info!( - "Server status: {}", - if healthy { "healthy" } else { "not healthy " } - ); - - let mut successful_requests = 0; - - for event in &self.events { - match event { - Event::Blocks(n) => { - self - .state - .client - .generate_to_address( - *n, - &self - .state - .wallet - .get_address(AddressIndex::Peek(0)) - .unwrap() - .address, - ) - .unwrap(); - } - Event::Request(request, status, expected_response) => { - if healthy { - let response = client - .get(&format!("http://127.0.0.1:{}/{request}", port.unwrap())) - .send() - .unwrap(); - log::info!("{:?}", response); - assert_eq!(response.status().as_u16(), *status); - assert_eq!(response.text().unwrap(), *expected_response); - successful_requests += 1; - } else { - panic!("Tried to make a request when unhealthy"); - } - } - Event::Transaction(options) => { - self.sync(); - - let input_value = options - .slots - .iter() - .map(|slot| self.get_block(slot.0 as u64).txdata[slot.1].output[slot.2].value) - .sum::(); - - let output_value = input_value - options.fee; - - let (mut psbt, _) = { - let mut builder = self.state.wallet.build_tx(); - - builder - .manually_selected_only() - .fee_absolute(options.fee) - .allow_dust(true) - .add_utxos( - &options - .slots - .iter() - .map(|slot| OutPoint { - txid: self.get_block(slot.0 as u64).txdata[slot.1].txid(), - vout: slot.2 as u32, - }) - .collect::>(), - ) - .unwrap() - .set_recipients(vec![ - ( - self - .state - .wallet - .get_address(AddressIndex::Peek(0)) - .unwrap() - .address - .script_pubkey(), - output_value / options.output_count as u64 - ); - options.output_count - ]); - - builder.finish().unwrap() - }; - - if !self - .state - .wallet - .sign(&mut psbt, SignOptions::default()) - .unwrap() - { - panic!("Failed to sign transaction"); - } - - self - .state - .client - .call::( - "sendrawtransaction", - &[psbt.extract_tx().raw_hex().into(), 21000000.into()], - ) - .unwrap(); - } - } - } - - let child = if let Some(child) = child { - signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT).unwrap(); - child - } else { - Command::new(executable_path("ord")) - .envs(self.envs.clone()) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { - Stdio::piped() - } else { - Stdio::inherit() - }) - .current_dir(&self.state.tempdir) - .arg(format!("--rpc-url=localhost:{}", self.state.rpc_port)) - .arg("--cookie-file=bitcoin/regtest/.cookie") - .args(self.args.clone()) - .spawn() - .unwrap() - }; - - let output = child.wait_with_output().unwrap(); + let output = Command::new(executable_path("ord")) + .envs(self.envs.clone()) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { + Stdio::piped() + } else { + Stdio::inherit() + }) + .current_dir(&self.state.tempdir) + .arg(format!("--rpc-url=localhost:{}", self.state.rpc_port)) + .arg("--cookie-file=bitcoin/regtest/.cookie") + .args(self.args.clone()) + .output() + .unwrap(); let stdout = str::from_utf8(&output.stdout).unwrap(); let stderr = str::from_utf8(&output.stderr).unwrap(); @@ -343,16 +175,6 @@ impl<'a> Test<'a> { self.expected_stderr.assert_match(&stripped_stderr); self.expected_stdout.assert_match(stdout); - assert_eq!( - successful_requests, - self - .events - .iter() - .filter(|event| matches!(event, Event::Request(..))) - .count(), - "Unsuccessful requests" - ); - Output { stdout: stdout.to_string(), state: self.state, @@ -360,12 +182,86 @@ impl<'a> Test<'a> { } pub(crate) fn blocks(mut self, n: u64) -> Self { - self.events.push(Event::Blocks(n)); + self + .state + .client + .generate_to_address( + n, + &self + .state + .wallet + .get_address(AddressIndex::Peek(0)) + .unwrap() + .address, + ) + .unwrap(); + self } - pub(crate) fn transaction(mut self, options: TransactionOptions<'a>) -> Self { - self.events.push(Event::Transaction(options)); + pub(crate) fn transaction(mut self, options: TransactionOptions) -> Self { + self.sync(); + + let input_value = options + .slots + .iter() + .map(|slot| self.get_block(slot.0 as u64).txdata[slot.1].output[slot.2].value) + .sum::(); + + let output_value = input_value - options.fee; + + let (mut psbt, _) = { + let mut builder = self.state.wallet.build_tx(); + + builder + .manually_selected_only() + .fee_absolute(options.fee) + .allow_dust(true) + .add_utxos( + &options + .slots + .iter() + .map(|slot| OutPoint { + txid: self.get_block(slot.0 as u64).txdata[slot.1].txid(), + vout: slot.2 as u32, + }) + .collect::>(), + ) + .unwrap() + .set_recipients(vec![ + ( + self + .state + .wallet + .get_address(AddressIndex::Peek(0)) + .unwrap() + .address + .script_pubkey(), + output_value / options.output_count as u64 + ); + options.output_count + ]); + + builder.finish().unwrap() + }; + + if !self + .state + .wallet + .sign(&mut psbt, SignOptions::default()) + .unwrap() + { + panic!("Failed to sign transaction"); + } + + self + .state + .client + .call::( + "sendrawtransaction", + &[psbt.extract_tx().raw_hex().into(), 21000000.into()], + ) + .unwrap(); self } @@ -373,4 +269,8 @@ impl<'a> Test<'a> { fs::write(self.state.tempdir.path().join(path), contents).unwrap(); self } + + pub(crate) fn request(mut self, path: &str, status: u16, expected_response: &str) -> Self { + panic!() + } } From 28f033b775d75beb4fe83ab1e381a06b7ab48a9e Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 2 Aug 2022 13:10:13 -0700 Subject: [PATCH 36/61] Fix --- tests/server.rs | 32 ++++++++++++++++---------------- tests/state.rs | 22 ++++++++++++++-------- tests/test.rs | 4 ---- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/tests/server.rs b/tests/server.rs index 7b6ad6df48..5046489d9b 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -9,11 +9,11 @@ fn list() { Test::new() .command(&format!("server --address 127.0.0.1 --http-port {port}")) .blocks(1) - .request( - "list/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0", - 200, - "[[0,5000000000]]", - ) + // .request( + // "list/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0", + // 200, + // "[[0,5000000000]]", + // ) .run_server(port) } @@ -23,7 +23,7 @@ fn status() { Test::new() .command(&format!("server --address 127.0.0.1 --http-port {port}")) - .request("status", 200, "") + // .request("status", 200, "") .run_server(port) } @@ -33,17 +33,17 @@ fn continuously_index_ranges() { Test::new() .command(&format!("server --address 127.0.0.1 --http-port {port}")) - .request( - "list/150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0", - 404, - "null", - ) + // .request( + // "list/150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0", + // 404, + // "null", + // ) .blocks(1) - .request( - "list/150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0", - 200, - "[[5000000000,10000000000]]", - ) + // .request( + // "list/150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0", + // 200, + // "[[5000000000,10000000000]]", + // ) .run_server(port) } diff --git a/tests/state.rs b/tests/state.rs index b722e3f26a..3f719507b2 100644 --- a/tests/state.rs +++ b/tests/state.rs @@ -7,6 +7,7 @@ pub(crate) struct State { pub(crate) wallet: Wallet, pub(crate) blockchain: RpcBlockchain, pub(crate) rpc_port: u16, + // server: Child, } impl State { @@ -60,6 +61,15 @@ impl State { sleep(Duration::from_millis(100)); } + // let server = Command::new(executable_path("ord")) + // .envs(self.envs.clone()) + // .current_dir(&tempdir) + // .arg(format!("--rpc-url=localhost:{}", rpc_port)) + // .arg("--cookie-file=bitcoin/regtest/.cookie") + // .args(["ord", "server", "--address", "127.0.0.1", "--http-port"]) + // .spawn() + // .unwrap(); + let wallet = Wallet::new( Bip84( ( @@ -95,15 +105,11 @@ impl State { } // pub(crate) fn request(mut self, path: &str, status: u16, expected_response: &str) -> Self { - // let response = self - // .state - // .client - // .get(&format!("http://127.0.0.1:{}/{path}", self.state.rpc_port.unwrap())) - // .send() - // .unwrap(); + // let response = + // reqwest::blocking::get(&format!("http://127.0.0.1:{}/{path}", self.rpc_port)).unwrap(); // log::info!("{:?}", response); - // assert_eq!(response.status().as_u16(), *status); - // assert_eq!(response.text().unwrap(), *expected_response); + // assert_eq!(response.status().as_u16(), status); + // assert_eq!(response.text().unwrap(), expected_response); // self // } } diff --git a/tests/test.rs b/tests/test.rs index cf5ed42c8d..d438622ecf 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -269,8 +269,4 @@ impl Test { fs::write(self.state.tempdir.path().join(path), contents).unwrap(); self } - - pub(crate) fn request(mut self, path: &str, status: u16, expected_response: &str) -> Self { - panic!() - } } From 4590aa6434182263303e23331733106c8cf04156 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 2 Aug 2022 13:12:00 -0700 Subject: [PATCH 37/61] Stuff --- tests/server.rs | 18 +++++++----------- tests/state.rs | 18 +++++++++--------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/tests/server.rs b/tests/server.rs index 5046489d9b..99902f4751 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -2,19 +2,15 @@ use super::*; #[test] fn list() { - let port = free_port(); + let state = State::new(); - log::info!("port: {}", port); + state.blocks(1); - Test::new() - .command(&format!("server --address 127.0.0.1 --http-port {port}")) - .blocks(1) - // .request( - // "list/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0", - // 200, - // "[[0,5000000000]]", - // ) - .run_server(port) + state.request( + "list/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0", + 200, + "[[0,5000000000]]", + ); } #[test] diff --git a/tests/state.rs b/tests/state.rs index 3f719507b2..64f8515c82 100644 --- a/tests/state.rs +++ b/tests/state.rs @@ -6,7 +6,7 @@ pub(crate) struct State { pub(crate) client: Client, pub(crate) wallet: Wallet, pub(crate) blockchain: RpcBlockchain, - pub(crate) rpc_port: u16, + pub(crate) bitcoind_rpc_port: u16, // server: Child, } @@ -104,14 +104,14 @@ impl State { } } - // pub(crate) fn request(mut self, path: &str, status: u16, expected_response: &str) -> Self { - // let response = - // reqwest::blocking::get(&format!("http://127.0.0.1:{}/{path}", self.rpc_port)).unwrap(); - // log::info!("{:?}", response); - // assert_eq!(response.status().as_u16(), status); - // assert_eq!(response.text().unwrap(), expected_response); - // self - // } + pub(crate) fn request(mut self, path: &str, status: u16, expected_response: &str) -> Self { + let response = + reqwest::blocking::get(&format!("http://127.0.0.1:{}/{path}", self.ord_http_port)).unwrap(); + log::info!("{:?}", response); + assert_eq!(response.status().as_u16(), status); + assert_eq!(response.text().unwrap(), expected_response); + self + } } impl Drop for State { From 6c21615acdaad1db37cccf5cce7e0bc34bbd9ece Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 2 Aug 2022 13:41:19 -0700 Subject: [PATCH 38/61] Get first server test working --- tests/lib.rs | 6 +--- tests/server.rs | 75 +++++++++++++++++++++---------------------------- tests/state.rs | 69 ++++++++++++++++++++++++++++++++++----------- tests/test.rs | 40 ++++++-------------------- 4 files changed, 95 insertions(+), 95 deletions(-) diff --git a/tests/lib.rs b/tests/lib.rs index 3ec303acde..c7a23daf12 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -18,10 +18,6 @@ use { bitcoincore_rpc::{Client, RawTx, RpcApi}, executable_path::executable_path, log::LevelFilter, - nix::{ - sys::signal::{self, Signal}, - unistd::Pid, - }, regex::Regex, std::{ collections::BTreeMap, @@ -32,7 +28,7 @@ use { str, sync::Once, thread::sleep, - time::{Duration, Instant}, + time::Duration, }, tempfile::TempDir, unindent::Unindent, diff --git a/tests/server.rs b/tests/server.rs index 99902f4751..fde6d9971c 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -4,8 +4,6 @@ use super::*; fn list() { let state = State::new(); - state.blocks(1); - state.request( "list/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0", 200, @@ -13,35 +11,34 @@ fn list() { ); } -#[test] -fn status() { - let port = free_port(); - - Test::new() - .command(&format!("server --address 127.0.0.1 --http-port {port}")) - // .request("status", 200, "") - .run_server(port) -} - -#[test] -fn continuously_index_ranges() { - let port = free_port(); - - Test::new() - .command(&format!("server --address 127.0.0.1 --http-port {port}")) - // .request( - // "list/150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0", - // 404, - // "null", - // ) - .blocks(1) - // .request( - // "list/150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0", - // 200, - // "[[5000000000,10000000000]]", - // ) - .run_server(port) -} +// #[test] +// fn status() { +// let port = free_port(); + +// Test::new() +// .command(&format!("server --address 127.0.0.1 --http-port {port}")) +// // .request("status", 200, "") +// .run_server(port) +// } + +// #[test] +// let port = free_port(); + +// Test::new() +// .command(&format!("server --address 127.0.0.1 --http-port {port}")) +// // .request( +// // "list/150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0", +// // 404, +// // "null", +// // ) +// .blocks(1) +// // .request( +// // "list/150ba822b458a19615e70a604d8dd9d3482fc165fa4e9cc150d74e11916ce8ae:0", +// // 200, +// // "[[5000000000,10000000000]]", +// // ) +// .run(port) +// } #[test] fn http_or_https_port_is_required() { @@ -63,40 +60,32 @@ fn http_and_https_port_conflict() { #[test] fn http_port_requires_acme_flags() { - let port = free_port(); - Test::new() .command("server --address 127.0.0.1 --https-port 0") .stderr_regex("error: The following required arguments were not provided:\n --acme-cache \n --acme-domain \n --acme-contact \n.*") .expected_status(2) - .run_server(port) + .run() } #[test] fn acme_contact_accepts_multiple_values() { - let port = free_port(); - Test::new() .command("server --address 127.0.0.1 --http-port 0 --acme-contact foo --acme-contact bar") - .run_server(port) + .run() } #[test] fn acme_domain_accepts_multiple_values() { - let port = free_port(); - Test::new() .command("server --address 127.0.0.1 --http-port 0 --acme-domain foo --acme-domain bar") - .run_server(port) + .run() } #[test] fn creates_acme_cache() { - let port = free_port(); - let output = Test::new() .command("server --address 127.0.0.1 --https-port 0 --acme-domain foo --acme-cache bar --acme-contact mailto:foo@bar.com") - .run_server_output(port); + .output(); assert!(output.state.tempdir.path().join("bar").is_dir()); } diff --git a/tests/state.rs b/tests/state.rs index 64f8515c82..1bf33a5527 100644 --- a/tests/state.rs +++ b/tests/state.rs @@ -7,7 +7,8 @@ pub(crate) struct State { pub(crate) wallet: Wallet, pub(crate) blockchain: RpcBlockchain, pub(crate) bitcoind_rpc_port: u16, - // server: Child, + ord_http_port: u16, + ord: Child, } impl State { @@ -16,7 +17,7 @@ impl State { fs::create_dir(tempdir.path().join("bitcoin")).unwrap(); - let rpc_port = free_port(); + let bitcoind_rpc_port = free_port(); let bitcoind = Command::new("bitcoind") .stdout(if log::max_level() >= LevelFilter::Info { @@ -33,7 +34,7 @@ impl State { "-regtest", "-networkactive=0", "-listen=0", - &format!("-rpcport={rpc_port}"), + &format!("-rpcport={bitcoind_rpc_port}"), ]) .current_dir(&tempdir.path()) .spawn() @@ -44,7 +45,7 @@ impl State { while !cookiefile.is_file() {} let client = Client::new( - &format!("localhost:{rpc_port}"), + &format!("localhost:{bitcoind_rpc_port}"), bitcoincore_rpc::Auth::CookieFile(cookiefile.clone()), ) .unwrap(); @@ -61,14 +62,33 @@ impl State { sleep(Duration::from_millis(100)); } - // let server = Command::new(executable_path("ord")) - // .envs(self.envs.clone()) - // .current_dir(&tempdir) - // .arg(format!("--rpc-url=localhost:{}", rpc_port)) - // .arg("--cookie-file=bitcoin/regtest/.cookie") - // .args(["ord", "server", "--address", "127.0.0.1", "--http-port"]) - // .spawn() - // .unwrap(); + let ord_http_port = free_port(); + + let ord = Command::new(executable_path("ord")) + .current_dir(&tempdir) + .arg(format!("--rpc-url=localhost:{}", bitcoind_rpc_port)) + .arg("--cookie-file=bitcoin/regtest/.cookie") + .args([ + "server", + "--address", + "127.0.0.1", + "--http-port", + &ord_http_port.to_string(), + ]) + .spawn() + .unwrap(); + + for attempt in 0..=300 { + match reqwest::blocking::get(&format!("http://127.0.0.1:{ord_http_port}/status")) { + Ok(response) if response.status().is_success() => break, + result => { + if attempt == 300 { + panic!("Failed to connect to ord server: {result:?}"); + } + } + } + sleep(Duration::from_millis(100)); + } let wallet = Wallet::new( Bip84( @@ -86,7 +106,7 @@ impl State { .unwrap(); let blockchain = RpcBlockchain::from_config(&RpcConfig { - url: format!("localhost:{rpc_port}"), + url: format!("localhost:{bitcoind_rpc_port}"), auth: bdk::blockchain::rpc::Auth::Cookie { file: cookiefile }, network: Network::Regtest, wallet_name: "test".to_string(), @@ -96,17 +116,33 @@ impl State { State { tempdir, - rpc_port, + bitcoind_rpc_port, + ord_http_port, bitcoind, client, wallet, + ord, blockchain, } } - pub(crate) fn request(mut self, path: &str, status: u16, expected_response: &str) -> Self { + pub(crate) fn blocks(&self, n: u64) { + self + .client + .generate_to_address( + n, + &self + .wallet + .get_address(AddressIndex::Peek(0)) + .unwrap() + .address, + ) + .unwrap(); + } + + pub(crate) fn request(self, path: &str, status: u16, expected_response: &str) -> Self { let response = - reqwest::blocking::get(&format!("http://127.0.0.1:{}/{path}", self.ord_http_port)).unwrap(); + reqwest::blocking::get(&format!("http://127.0.0.1:{}/{}", self.ord_http_port, path)).unwrap(); log::info!("{:?}", response); assert_eq!(response.status().as_u16(), status); assert_eq!(response.text().unwrap(), expected_response); @@ -116,6 +152,7 @@ impl State { impl Drop for State { fn drop(&mut self) { + self.ord.kill().unwrap(); self.bitcoind.kill().unwrap(); } } diff --git a/tests/test.rs b/tests/test.rs index d438622ecf..0a5480c633 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -106,15 +106,7 @@ impl Test { } pub(crate) fn run(self) { - self.test(None); - } - - pub(crate) fn output(self) -> Output { - self.test(None) - } - - pub(crate) fn run_server(self, port: u16) { - self.test(Some(port)); + self.output(); } fn get_block(&self, height: u64) -> Block { @@ -125,10 +117,6 @@ impl Test { .unwrap() } - pub(crate) fn run_server_output(self, port: u16) -> Output { - self.test(Some(port)) - } - fn sync(&self) { self .state @@ -137,7 +125,7 @@ impl Test { .unwrap(); } - fn test(self, port: Option) -> Output { + pub(crate) fn output(self) -> Output { let output = Command::new(executable_path("ord")) .envs(self.envs.clone()) .stdin(Stdio::null()) @@ -148,7 +136,10 @@ impl Test { Stdio::inherit() }) .current_dir(&self.state.tempdir) - .arg(format!("--rpc-url=localhost:{}", self.state.rpc_port)) + .arg(format!( + "--rpc-url=localhost:{}", + self.state.bitcoind_rpc_port + )) .arg("--cookie-file=bitcoin/regtest/.cookie") .args(self.args.clone()) .output() @@ -181,25 +172,12 @@ impl Test { } } - pub(crate) fn blocks(mut self, n: u64) -> Self { - self - .state - .client - .generate_to_address( - n, - &self - .state - .wallet - .get_address(AddressIndex::Peek(0)) - .unwrap() - .address, - ) - .unwrap(); - + pub(crate) fn blocks(self, n: u64) -> Self { + self.state.blocks(n); self } - pub(crate) fn transaction(mut self, options: TransactionOptions) -> Self { + pub(crate) fn transaction(self, options: TransactionOptions) -> Self { self.sync(); let input_value = options From 16246431876985f741c1fc5516ca57ee184b8fef Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 2 Aug 2022 17:40:24 -0400 Subject: [PATCH 39/61] Get tests to pass --- tests/lib.rs | 94 +++++++++++++++++++++++++++++++++++++---- tests/wallet.rs | 110 +++++++++++++++++++++--------------------------- 2 files changed, 133 insertions(+), 71 deletions(-) diff --git a/tests/lib.rs b/tests/lib.rs index dfd39069b8..4c890878de 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -92,6 +92,9 @@ enum Event<'a> { } struct Output { + bitcoind: Bitcoind, + client: Client, + rpc_port: u16, stdout: String, tempdir: TempDir, } @@ -104,15 +107,15 @@ struct TransactionOptions<'a> { struct Test<'a> { args: Vec, - _bitcoind: Bitcoind, + bitcoind: Bitcoind, blockchain: RpcBlockchain, client: Client, - rpc_port: u16, envs: Vec<(OsString, OsString)>, events: Vec>, expected_status: i32, expected_stderr: Expected, expected_stdout: Expected, + rpc_port: u16, tempdir: TempDir, wallet: Wallet, } @@ -154,7 +157,6 @@ impl<'a> Test<'a> { "-maxtxfee=21000000", "-datadir=bitcoin", "-regtest", - "-networkactive=0", &format!("-rpcport={rpc_port}"), ]) .current_dir(&tempdir.path()) @@ -208,7 +210,7 @@ impl<'a> Test<'a> { args: Vec::new(), client, blockchain, - _bitcoind: Bitcoind(bitcoind), + bitcoind: Bitcoind(bitcoind), envs: Vec::new(), events: Vec::new(), expected_status: 0, @@ -224,6 +226,75 @@ impl<'a> Test<'a> { Ok(test) } + fn connect(output: Output) -> Result { + ONCE.call_once(|| { + env_logger::init(); + }); + + let cookiefile = output.tempdir.path().join("bitcoin/regtest/.cookie"); + + let client = Client::new( + &format!("127.0.0.1:{}", output.rpc_port), + bitcoincore_rpc::Auth::CookieFile(cookiefile.clone()), + )?; + + log::info!("Connecting to client..."); + + loop { + let mut attempts = 0; + match client.get_blockchain_info() { + Ok(_) => break, + Err(error) => { + attempts += 1; + if attempts > 300 { + panic!("Failed to connect to bitcoind: {error}"); + } + sleep(Duration::from_millis(100)); + } + } + } + + let wallet = Wallet::new( + Bip84( + ( + Mnemonic::parse("book fit fly ketchup also elevator scout mind edit fatal where rookie")?, + None, + ), + KeychainKind::External, + ), + None, + Network::Regtest, + MemoryDatabase::new(), + )?; + + let blockchain = RpcBlockchain::from_config(&RpcConfig { + url: format!("127.0.0.1:{}", output.rpc_port), + auth: bdk::blockchain::rpc::Auth::Cookie { file: cookiefile }, + network: Network::Regtest, + wallet_name: "test".to_string(), + skip_blocks: None, + })?; + + let test = Self { + args: Vec::new(), + client, + blockchain, + bitcoind: output.bitcoind, + envs: Vec::new(), + events: Vec::new(), + expected_status: 0, + expected_stderr: Expected::Ignore, + expected_stdout: Expected::String(String::new()), + rpc_port: output.rpc_port, + tempdir: output.tempdir, + wallet, + }; + + test.sync()?; + + Ok(test) + } + fn command(self, args: &str) -> Self { Self { args: args.split_whitespace().map(str::to_owned).collect(), @@ -333,9 +404,9 @@ impl<'a> Test<'a> { fn test(self, port: Option) -> Result { let client = reqwest::blocking::Client::new(); - log::info!("Spawning child process..."); - let (healthy, child) = if let Some(port) = port { + log::info!("Spawning ord server child process..."); + let child = Command::new(executable_path("ord")) .envs(self.envs.clone()) .stdin(Stdio::null()) @@ -346,7 +417,7 @@ impl<'a> Test<'a> { Stdio::inherit() }) .current_dir(&self.tempdir) - .arg(format!("--rpc-url=localhost:{}", self.rpc_port)) + .arg(format!("--rpc-url=127.0.0.1:{}", self.rpc_port)) .arg("--cookie-file=bitcoin/regtest/.cookie") .args(self.args.clone()) .spawn()?; @@ -379,7 +450,7 @@ impl<'a> Test<'a> { log::info!( "Server status: {}", - if healthy { "healthy" } else { "not healthy " } + if healthy { "healthy" } else { "unhealthy" } ); let mut successful_requests = 0; @@ -460,9 +531,11 @@ impl<'a> Test<'a> { } let child = if let Some(child) = child { + log::info!("Killing server child process..."); signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT)?; child } else { + log::info!("Spawning ord child process..."); Command::new(executable_path("ord")) .envs(self.envs.clone()) .stdin(Stdio::null()) @@ -473,7 +546,7 @@ impl<'a> Test<'a> { Stdio::inherit() }) .current_dir(&self.tempdir) - .arg(format!("--rpc-url=localhost:{}", self.rpc_port)) + .arg(format!("--rpc-url=127.0.0.1:{}", self.rpc_port)) .arg("--cookie-file=bitcoin/regtest/.cookie") .args(self.args.clone()) .spawn()? @@ -513,6 +586,9 @@ impl<'a> Test<'a> { ); Ok(Output { + bitcoind: self.bitcoind, + client: self.client, + rpc_port: self.rpc_port, stdout: stdout.to_string(), tempdir: self.tempdir, }) diff --git a/tests/wallet.rs b/tests/wallet.rs index 908c2967cb..9d5f91603e 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -1,4 +1,4 @@ -use super::*; +use {super::*, bitcoin::util::address::Address, std::str::FromStr}; fn path(path: &str) -> String { if cfg!(target_os = "macos") { @@ -10,19 +10,22 @@ fn path(path: &str) -> String { #[test] fn init_existing_wallet() -> Result { - let tempdir = Test::new()? + let output = Test::new()? .command("wallet init") .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") - .output()? - .tempdir; + .output()?; - assert!(tempdir.path().join(path("ord/wallet.sqlite")).exists()); + assert!(output + .tempdir + .path() + .join(path("ord/wallet.sqlite")) + .exists()); - assert!(tempdir.path().join(path("ord/entropy")).exists()); + assert!(output.tempdir.path().join(path("ord/entropy")).exists()); - Test::with_tempdir(tempdir)? + Test::connect(output)? .command("wallet init") .set_home_to_tempdir() .expected_status(1) @@ -49,15 +52,14 @@ fn init_nonexistent_wallet() -> Result { #[test] fn load_corrupted_entropy() -> Result { - let tempdir = Test::new()? + let output = Test::new()? .command("wallet init") .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") - .output()? - .tempdir; + .output()?; - let entropy_path = tempdir.path().join(path("ord/entropy")); + let entropy_path = output.tempdir.path().join(path("ord/entropy")); assert!(entropy_path.exists()); @@ -66,31 +68,28 @@ fn load_corrupted_entropy() -> Result { fs::write(&entropy_path, entropy)?; - Test::with_tempdir(tempdir)? + Test::connect(output)? .command("wallet fund") .set_home_to_tempdir() .expected_status(1) .expected_stderr("error: ChecksumMismatch\n") - .run()?; - - Ok(()) + .run() } #[test] fn fund_existing_wallet() -> Result { - let tempdir = Test::new()? + let output = Test::new()? .command("wallet init") .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") .set_home_to_tempdir() - .output()? - .tempdir; + .output()?; - Test::with_tempdir(tempdir)? + Test::connect(output)? .command("wallet fund") .set_home_to_tempdir() - .stdout_regex("^tb1.*\n") + .stdout_regex("^bcrt1.*\n") .run() } @@ -106,47 +105,34 @@ fn fund_nonexistent_wallet() -> Result { #[test] fn utxos() -> Result { - // let output = Test::new()? - // .command("wallet init") - // .set_home_to_tempdir() - // .expected_status(0) - // .expected_stderr("Wallet initialized.\n") - // .set_home_to_tempdir() - // .output()?; - - // let output = Test::with_tempdir(output.tempdir)? - // .command("wallet fund") - // .set_home_to_tempdir() - // .stdout_regex("^bcrt1.*\n") - // .output()?; - - // let core_address = output.bitcoind.client.get_new_address(None, None)?; - - // output - // .bitcoind - // .client - // .generate_to_address(101, &core_address)?; - - // output.bitcoind.client.send_to_address( - // &Address::from_str(&output.stdout.strip_suffix('\n').unwrap())?, - // Amount::from_btc(10.0)?, - // None, - // None, - // None, - // None, - // None, - // None, - // )?; - - // output - // .bitcoind - // .client - // .generate_to_address(1, &core_address)?; - - // Test::with_tempdir(output.tempdir)? - // .command("wallet utxos") - // .set_home_to_tempdir() - // .run() + let output = Test::new()? + .command("wallet init") + .set_home_to_tempdir() + .expected_status(0) + .expected_stderr("Wallet initialized.\n") + .set_home_to_tempdir() + .output()?; - Ok(()) + let output = Test::connect(output)? + .command("wallet fund") + .set_home_to_tempdir() + .stdout_regex("^bcrt1.*\n") + .output()?; + + output.client.generate_to_address( + 1, + &Address::from_str( + &output + .stdout + .strip_suffix('\n') + .ok_or("Failed to convert string to Address")?, + )?, + )?; + + Test::connect(output)? + .command("wallet utxos") + .set_home_to_tempdir() + .expected_status(0) + .expected_stdout("[]\n") + .run() } From f16a0033f9919a656413008f8f998d2ce6dd5dfd Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 2 Aug 2022 17:41:35 -0400 Subject: [PATCH 40/61] Strip suffix error --- tests/wallet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/wallet.rs b/tests/wallet.rs index 9d5f91603e..26cd2790fe 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -125,7 +125,7 @@ fn utxos() -> Result { &output .stdout .strip_suffix('\n') - .ok_or("Failed to convert string to Address")?, + .ok_or("Failed to strip suffix")?, )?, )?; From 30b5dfdbe033a2bfd70c43d0e76872c7a3901ec3 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Aug 2022 11:27:15 -0400 Subject: [PATCH 41/61] Generate 101 blocks, output txid:vout --- src/subcommand/wallet/utxos.rs | 10 +++++++++- tests/wallet.rs | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/subcommand/wallet/utxos.rs b/src/subcommand/wallet/utxos.rs index c37101cad3..ccacca8e61 100644 --- a/src/subcommand/wallet/utxos.rs +++ b/src/subcommand/wallet/utxos.rs @@ -1,5 +1,13 @@ use super::*; pub(crate) fn run(options: Options) -> Result { - Ok(println!("{:?}", get_wallet(options)?.list_unspent()?)) + Ok(println!( + "{}", + get_wallet(options)? + .list_unspent()? + .iter() + .map(|utxo| format!("{}:{}", utxo.outpoint.txid, utxo.outpoint.vout)) + .collect::>() + .join("\n") + )) } diff --git a/tests/wallet.rs b/tests/wallet.rs index 26cd2790fe..3094c57ae3 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -120,7 +120,7 @@ fn utxos() -> Result { .output()?; output.client.generate_to_address( - 1, + 101, &Address::from_str( &output .stdout @@ -133,6 +133,6 @@ fn utxos() -> Result { .command("wallet utxos") .set_home_to_tempdir() .expected_status(0) - .expected_stdout("[]\n") + .stdout_regex("^[a-z0-9]{64}:[0-9]*\n") .run() } From 14f13ed7e4698d4d70eb81ca39ee4bd3663a794f Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Thu, 4 Aug 2022 10:42:26 -0700 Subject: [PATCH 42/61] Try not to leak write transactions --- src/index.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/index.rs b/src/index.rs index 65e426c246..035d88ff8e 100644 --- a/src/index.rs +++ b/src/index.rs @@ -105,12 +105,17 @@ impl Index { loop { let mut wtx = self.database.begin_write()?; - let done = self.index_block(&mut wtx)?; - - wtx.commit()?; - - if done || INTERRUPTS.load(atomic::Ordering::Relaxed) > 0 { - break; + match self.index_block(&mut wtx) { + Ok(done) => { + wtx.commit()?; + if done || INTERRUPTS.load(atomic::Ordering::Relaxed) > 0 { + break; + } + } + Err(err) => { + wtx.abort()?; + return Err(err); + } } } From e2a620b7370483ff712ff093687fa3f9427c2c12 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Thu, 4 Aug 2022 10:56:48 -0700 Subject: [PATCH 43/61] Try updating dependencies --- Cargo.lock | 69 +++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d40a82cf08..c6b17b15b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -626,14 +626,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "6127248204b9aba09a362f6c930ef6a78f2c1b2215f8a7b398c06e1083f17af0" dependencies = [ - "libc", + "js-sys", "num-integer", "num-traits", "time 0.1.44", + "wasm-bindgen", "winapi", ] @@ -1174,9 +1175,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", @@ -1473,9 +1474,9 @@ checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" [[package]] name = "js-sys" @@ -1515,9 +1516,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b" [[package]] name = "libsqlite3-sys" @@ -1982,9 +1983,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.42" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] @@ -2001,9 +2002,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] @@ -2374,7 +2375,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.12", + "semver 1.0.13", ] [[package]] @@ -2441,9 +2442,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "schannel" @@ -2535,9 +2536,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" +checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711" [[package]] name = "semver-parser" @@ -2547,9 +2548,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.141" +version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7af873f2c95b99fcb0bd0fe622a43e29514658873c8ceba88c4cb88833a22500" +checksum = "e590c437916fb6b221e1d00df6e3294f3fccd70ca7e92541c475d6ed6ef5fee2" dependencies = [ "serde_derive", ] @@ -2566,9 +2567,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.141" +version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75743a150d003dd863b51dc809bcad0d73f2102c53632f1e954e738192a3413f" +checksum = "34b5b8d809babe02f538c2cfec6f2c1ed10804c0e5a6a041a049a4f5588ccc2e" dependencies = [ "proc-macro2", "quote", @@ -2577,9 +2578,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" dependencies = [ "itoa", "ryu", @@ -2822,9 +2823,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", @@ -2886,18 +2887,18 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" dependencies = [ "proc-macro2", "quote", @@ -3126,9 +3127,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" [[package]] name = "unicode-normalization" @@ -3147,9 +3148,9 @@ checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "unindent" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52fee519a3e570f7df377a06a1a7775cdbfb7aa460be7e08de2b1f0e69973a44" +checksum = "58ee9362deb4a96cef4d437d1ad49cffc9b9e92d202b6995674e928ce684f112" [[package]] name = "universal-hash" From ef09f26b7da4cc6deeb508af697118a08709e86d Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Thu, 4 Aug 2022 11:03:05 -0700 Subject: [PATCH 44/61] Initialize logger in state --- tests/state.rs | 4 ++++ tests/test.rs | 6 ------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/state.rs b/tests/state.rs index 1bf33a5527..80ba643340 100644 --- a/tests/state.rs +++ b/tests/state.rs @@ -11,8 +11,12 @@ pub(crate) struct State { ord: Child, } +static ONCE: Once = Once::new(); + impl State { pub(crate) fn new() -> Self { + ONCE.call_once(|| env_logger::init()); + let tempdir = TempDir::new().unwrap(); fs::create_dir(tempdir.path().join("bitcoin")).unwrap(); diff --git a/tests/test.rs b/tests/test.rs index 0a5480c633..10b583e9ae 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -15,12 +15,6 @@ impl Test { } pub(crate) fn with_state(state: State) -> Self { - static ONCE: Once = Once::new(); - - ONCE.call_once(|| { - env_logger::init(); - }); - let test = Self { args: Vec::new(), state, From 0a88ec153af45c41e91b848194df16ea6507db86 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Thu, 4 Aug 2022 11:24:57 -0700 Subject: [PATCH 45/61] Increase redb database size --- src/options.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/options.rs b/src/options.rs index 99b1e75028..3ffff3d67c 100644 --- a/src/options.rs +++ b/src/options.rs @@ -2,7 +2,7 @@ use super::*; #[derive(Parser)] pub(crate) struct Options { - #[clap(long, default_value = "1MiB")] + #[clap(long, default_value = "10MiB")] pub(crate) max_index_size: Bytes, #[clap(long)] pub(crate) cookie_file: Option, From 5d0b30caef89a6c779f08f96270a71bdcf383398 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 8 Aug 2022 18:25:29 -0400 Subject: [PATCH 46/61] Fix more tests --- src/arguments.rs | 75 ++++++++++++++- src/index.rs | 7 ++ src/options.rs | 2 +- src/subcommand.rs | 2 +- src/subcommand/find.rs | 2 +- src/subcommand/list.rs | 2 +- src/subcommand/mint.rs | 2 +- src/subcommand/name.rs | 2 +- src/subcommand/range.rs | 2 +- src/subcommand/server.rs | 2 +- src/subcommand/traits.rs | 2 +- src/subcommand/verify.rs | 2 +- src/subcommand/wallet.rs | 2 +- tests/index.rs | 21 ---- tests/info.rs | 8 +- tests/server.rs | 200 ++++++++++++++------------------------- tests/state.rs | 89 ++++++++++++++++- tests/test.rs | 81 +--------------- 18 files changed, 254 insertions(+), 249 deletions(-) diff --git a/src/arguments.rs b/src/arguments.rs index 05cf9f6c16..9938780f36 100644 --- a/src/arguments.rs +++ b/src/arguments.rs @@ -1,6 +1,6 @@ use super::*; -#[derive(Parser)] +#[derive(Debug, Parser)] #[clap(version)] pub(crate) struct Arguments { #[clap(flatten)] @@ -110,4 +110,77 @@ mod tests { assert!(cookie_file.ends_with("/Bitcoin/signet/.cookie")); } } + + #[test] + fn http_or_https_port_is_required() { + let err = Arguments::try_parse_from(&["ord", "server", "--address", "127.0.0.1"]) + .unwrap_err() + .to_string(); + + assert!( + err.starts_with("error: The following required arguments were not provided:\n <--http-port |--https-port >\n"), + "{}", + err + ); + } + + #[test] + fn http_and_https_port_conflict() { + let err = Arguments::try_parse_from(&["ord", "server", "--http-port=0", "--https-port=0"]) + .unwrap_err() + .to_string(); + + assert!( + err.starts_with("error: The argument '--http-port ' cannot be used with '--https-port '\n"), + "{}", + err + ); + } + + #[test] + fn http_port_requires_acme_flags() { + let err = Arguments::try_parse_from(&["ord", "server", "--https-port=0"]) + .unwrap_err() + .to_string(); + + assert!( + err.starts_with("error: The following required arguments were not provided:\n --acme-cache \n --acme-domain \n --acme-contact \n"), + "{}", + err + ); + } + + #[test] + fn acme_contact_accepts_multiple_values() { + assert!(Arguments::try_parse_from(&[ + "ord", + "server", + "--address", + "127.0.0.1", + "--http-port", + "0", + "--acme-contact", + "foo", + "--acme-contact", + "bar" + ]) + .is_ok()); + } + + #[test] + fn acme_domain_accepts_multiple_values() { + assert!(Arguments::try_parse_from(&[ + "ord", + "server", + "--address", + "127.0.0.1", + "--http-port", + "0", + "--acme-domain", + "foo", + "--acme-domain", + "bar" + ]) + .is_ok()); + } } diff --git a/src/index.rs b/src/index.rs index a3972096f9..b804639004 100644 --- a/src/index.rs +++ b/src/index.rs @@ -308,6 +308,13 @@ impl Index { Err(bitcoincore_rpc::Error::JsonRpc(bitcoincore_rpc::jsonrpc::error::Error::Rpc( bitcoincore_rpc::jsonrpc::error::RpcError { code: -8, .. }, ))) => Ok(None), + Err(bitcoincore_rpc::Error::JsonRpc(bitcoincore_rpc::jsonrpc::error::Error::Rpc( + bitcoincore_rpc::jsonrpc::error::RpcError { message, .. }, + ))) + if message == "Block not found" => + { + Ok(None) + } Err(err) => Err(err.into()), } } diff --git a/src/options.rs b/src/options.rs index 332a0e48fc..33c27481df 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1,6 +1,6 @@ use super::*; -#[derive(Parser)] +#[derive(Debug, Parser)] pub(crate) struct Options { #[clap(long, default_value = "10MiB")] pub(crate) max_index_size: Bytes, diff --git a/src/subcommand.rs b/src/subcommand.rs index 559e783e48..1e8deb40dd 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -14,7 +14,7 @@ mod traits; mod verify; mod wallet; -#[derive(Parser)] +#[derive(Debug, Parser)] pub(crate) enum Subcommand { Epochs, Find(find::Find), diff --git a/src/subcommand/find.rs b/src/subcommand/find.rs index 9275f3912d..75158de49c 100644 --- a/src/subcommand/find.rs +++ b/src/subcommand/find.rs @@ -1,6 +1,6 @@ use super::*; -#[derive(Parser)] +#[derive(Debug, Parser)] pub(crate) struct Find { ordinal: Ordinal, } diff --git a/src/subcommand/list.rs b/src/subcommand/list.rs index 181600b4c5..f34f6525f2 100644 --- a/src/subcommand/list.rs +++ b/src/subcommand/list.rs @@ -1,6 +1,6 @@ use super::*; -#[derive(Parser)] +#[derive(Debug, Parser)] pub(crate) struct List { outpoint: OutPoint, } diff --git a/src/subcommand/mint.rs b/src/subcommand/mint.rs index 5500cf2f68..1c4cc99f19 100644 --- a/src/subcommand/mint.rs +++ b/src/subcommand/mint.rs @@ -1,6 +1,6 @@ use super::*; -#[derive(Parser)] +#[derive(Debug, Parser)] pub(crate) struct Mint { #[clap(long, help = "Read NFT contents from ")] data_path: PathBuf, diff --git a/src/subcommand/name.rs b/src/subcommand/name.rs index c9d9198dd3..ba2ce7f8a9 100644 --- a/src/subcommand/name.rs +++ b/src/subcommand/name.rs @@ -1,6 +1,6 @@ use super::*; -#[derive(Parser)] +#[derive(Debug, Parser)] pub(crate) struct Name { name: String, } diff --git a/src/subcommand/range.rs b/src/subcommand/range.rs index c798feb3b4..07c3c75389 100644 --- a/src/subcommand/range.rs +++ b/src/subcommand/range.rs @@ -1,6 +1,6 @@ use super::*; -#[derive(Parser)] +#[derive(Debug, Parser)] pub(crate) struct Range { #[clap(long)] name: bool, diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 4464f70173..d37f4e2762 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -15,7 +15,7 @@ use { mod deserialize_ordinal_from_str; mod tls_acceptor; -#[derive(Parser)] +#[derive(Debug, Parser)] #[clap(group = ArgGroup::new("port").multiple(false).required(true))] pub(crate) struct Server { #[clap( diff --git a/src/subcommand/traits.rs b/src/subcommand/traits.rs index e2447d6ffc..a6e4691a2b 100644 --- a/src/subcommand/traits.rs +++ b/src/subcommand/traits.rs @@ -1,6 +1,6 @@ use super::*; -#[derive(Parser)] +#[derive(Debug, Parser)] pub(crate) struct Traits { ordinal: Ordinal, } diff --git a/src/subcommand/verify.rs b/src/subcommand/verify.rs index 12eb9a8164..899899cbee 100644 --- a/src/subcommand/verify.rs +++ b/src/subcommand/verify.rs @@ -1,6 +1,6 @@ use super::*; -#[derive(Parser)] +#[derive(Debug, Parser)] pub(crate) struct Verify { #[clap(help = "Read bech32-formatted NFT from ")] input_path: PathBuf, diff --git a/src/subcommand/wallet.rs b/src/subcommand/wallet.rs index da16cc4762..bc058b1e78 100644 --- a/src/subcommand/wallet.rs +++ b/src/subcommand/wallet.rs @@ -3,7 +3,7 @@ use super::*; mod fund; mod init; -#[derive(Parser)] +#[derive(Debug, Parser)] pub(crate) enum Wallet { Init, Fund, diff --git a/tests/index.rs b/tests/index.rs index 6807b465d7..83c5a27623 100644 --- a/tests/index.rs +++ b/tests/index.rs @@ -1,26 +1,5 @@ use super::*; -#[test] -fn default_index_size() { - let state = Test::new() - .command("find 0") - .expected_stdout("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0:0\n") - .blocks(1) - .output() - .state; - - assert_eq!( - state - .tempdir - .path() - .join("index.redb") - .metadata() - .unwrap() - .len(), - 1 << 20 - ); -} - #[test] fn custom_index_size() { let state = Test::new() diff --git a/tests/info.rs b/tests/info.rs index f9003de7a9..7c886ca95b 100644 --- a/tests/info.rs +++ b/tests/info.rs @@ -12,10 +12,10 @@ fn basic() { outputs indexed: 1 tree height: \d+ free pages: \d+ - stored: .* bytes - overhead: .* bytes - fragmented: .* KiB - index size: 1 MiB + stored: .* + overhead: .* + fragmented: .* + index size: .* " .unindent(), ) diff --git a/tests/server.rs b/tests/server.rs index 3205206720..99748d6e9f 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -2,37 +2,24 @@ use super::*; #[test] fn list() { - State::new().request( - "list/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0", - 200, - "[[0,5000000000]]", - ); -} - -#[test] -fn status() { - State::new().request("status", 200, ""); -} - -#[test] -fn continuously_index_ranges() { let state = State::new(); - state.request( - "api/list/0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0", - 404, - "null", - ); - state.blocks(1); + sleep(Duration::from_secs(1)); + state.request( - "api/list/0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0", + "api/list/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0", 200, "[[0,5000000000]]", ); } +#[test] +fn status() { + State::new().request("status", 200, ""); +} + #[test] fn range_end_before_range_start_returns_400() { State::new().request("range/1/0", 400, "Range Start Greater Than Range End"); @@ -101,10 +88,16 @@ fn invalid_outpoint_hash_returns_400() { #[test] fn outpoint_returns_ordinal_ranges() { - State::new().request( - "output/0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9:0", + let state = State::new(); + + state.blocks(1); + + sleep(Duration::from_secs(1)); + + state.request( + "output/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0", 200, - "", + "", ); } @@ -125,134 +118,85 @@ fn invalid_vout_returns_404() { fn root() { let state = State::new(); - state.request("/", 200, "
    \n
"); + state.blocks(1); - state.blocks(2); + sleep(Duration::from_secs(1)); state.request( "/", 200, " ", ); } -// #[test] -// fn transactions() -> Result { -// let state = State::new(); - -// state.blocks(1) - -// .transaction(TransactionOptions { -// slots: &[(0, 0, 0)], -// output_count: 1, -// fee: 0, -// }) -// .request( -// "block/14508459b221041eab257d2baaa7459775ba748246c8403609eb708f0e57e74b", -// 200, -// " -// -// ", -// ) -// .run_server(port) -// } +#[test] +fn transactions() { + let state = State::new(); + + state.blocks(1); + + state.transaction(TransactionOptions { + slots: &[(0, 0, 0)], + output_count: 1, + fee: 0, + }); + + state.request( + "block/14508459b221041eab257d2baaa7459775ba748246c8403609eb708f0e57e74b", + 200, + " + + ", + ); +} #[test] fn block_not_found() { State::new().request( - "block/14508459b221041eab257d2baaa7459775ba748246c8403609eb708f0e57e74b", + "block/467a86f0642b1d284376d13a98ef58310caa49502b0f9a560ee222e0a122fe16", 404, "Not Found", ); } -// #[test] -// fn outputs() -> Result { -// let port = free_port()?; - -// Test::new()? -// .command(&format!("server --address 127.0.0.1 --http-port {port}")) -// .block() -// .transaction(TransactionOptions { -// slots: &[(0, 0, 0)], -// output_count: 1, -// fee: 0, -// }) -// .request( -// "block/14508459b221041eab257d2baaa7459775ba748246c8403609eb708f0e57e74b", -// 200, -// " -// -// ", -// ) -// .request( -// "tx/0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9", -// 200, -// " -// -// ") -// .run_server(port) -// } - #[test] -fn http_or_https_port_is_required() { - Test::new() - .command("server --address 127.0.0.1") - .stderr_regex("error: The following required arguments were not provided:\n <--http-port \\|--https-port >\n.*") - .expected_status(2) - .run(); -} - -#[test] -fn http_and_https_port_conflict() { - Test::new() - .command("server --address 127.0.0.1 --http-port 0 --https-port 0") - .stderr_regex("error: The argument '--http-port ' cannot be used with '--https-port '\n.*") - .expected_status(2) - .run() -} - -#[test] -fn http_port_requires_acme_flags() { - Test::new() - .command("server --address 127.0.0.1 --https-port 0") - .stderr_regex("error: The following required arguments were not provided:\n --acme-cache \n --acme-domain \n --acme-contact \n.*") - .expected_status(2) - .run() -} +fn outputs() { + let state = State::new(); -#[test] -fn acme_contact_accepts_multiple_values() { - Test::new() - .command("server --address 127.0.0.1 --http-port 0 --acme-contact foo --acme-contact bar") - .run() -} + state.blocks(1); -#[test] -fn acme_domain_accepts_multiple_values() { - Test::new() - .command("server --address 127.0.0.1 --http-port 0 --acme-domain foo --acme-domain bar") - .run() -} + state.transaction(TransactionOptions { + slots: &[(0, 0, 0)], + output_count: 1, + fee: 0, + }); -#[test] -fn creates_acme_cache() { - let output = Test::new() - .command("server --address 127.0.0.1 --https-port 0 --acme-domain foo --acme-cache bar --acme-contact mailto:foo@bar.com") - .output(); + state.request( + "block/14508459b221041eab257d2baaa7459775ba748246c8403609eb708f0e57e74b", + 200, + " + + ", + ); - assert!(output.state.tempdir.path().join("bar").is_dir()); + state.request( + "tx/0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9", + 200, + " + + " + ); } diff --git a/tests/state.rs b/tests/state.rs index 4cda0ba226..955c0dfe0a 100644 --- a/tests/state.rs +++ b/tests/state.rs @@ -68,10 +68,12 @@ impl State { let ord_http_port = free_port(); + fs::create_dir(tempdir.path().join("server")).unwrap(); + let ord = Command::new(executable_path("ord")) - .current_dir(&tempdir) + .current_dir(tempdir.path().join("server")) .arg(format!("--rpc-url=localhost:{}", bitcoind_rpc_port)) - .arg("--cookie-file=bitcoin/regtest/.cookie") + .arg("--cookie-file=../bitcoin/regtest/.cookie") .args([ "server", "--address", @@ -130,6 +132,20 @@ impl State { } } + pub(crate) fn get_block(&self, height: u64) -> Block { + self + .client + .get_block(&self.client.get_block_hash(height).unwrap()) + .unwrap() + } + + pub(crate) fn sync(&self) { + self + .wallet + .sync(&self.blockchain, SyncOptions::default()) + .unwrap(); + } + pub(crate) fn blocks(&self, n: u64) { self .client @@ -144,6 +160,64 @@ impl State { .unwrap(); } + pub(crate) fn transaction(&self, options: TransactionOptions) { + self.sync(); + + let input_value = options + .slots + .iter() + .map(|slot| self.get_block(slot.0 as u64).txdata[slot.1].output[slot.2].value) + .sum::(); + + let output_value = input_value - options.fee; + + let (mut psbt, _) = { + let mut builder = self.wallet.build_tx(); + + builder + .manually_selected_only() + .fee_absolute(options.fee) + .allow_dust(true) + .add_utxos( + &options + .slots + .iter() + .map(|slot| OutPoint { + txid: self.get_block(slot.0 as u64).txdata[slot.1].txid(), + vout: slot.2 as u32, + }) + .collect::>(), + ) + .unwrap() + .set_recipients(vec![ + ( + self + .wallet + .get_address(AddressIndex::Peek(0)) + .unwrap() + .address + .script_pubkey(), + output_value / options.output_count as u64 + ); + options.output_count + ]); + + builder.finish().unwrap() + }; + + if !self.wallet.sign(&mut psbt, SignOptions::default()).unwrap() { + panic!("Failed to sign transaction"); + } + + self + .client + .call::( + "sendrawtransaction", + &[psbt.extract_tx().raw_hex().into(), 21000000.into()], + ) + .unwrap(); + } + pub(crate) fn request(&self, path: &str, status: u16, expected_response: &str) { let response = reqwest::blocking::get(&format!("http://127.0.0.1:{}/{}", self.ord_http_port, path)).unwrap(); @@ -152,9 +226,14 @@ impl State { assert_eq!(response.status().as_u16(), status); - assert_eq!( - response.text().unwrap(), - expected_response.unindent().trim_end() + let response_text = response.text().unwrap(); + + assert!( + Regex::new(expected_response.unindent().trim_end()) + .unwrap() + .is_match(&response_text), + "Response text did not match regex: {:?}", + &response_text ); } } diff --git a/tests/test.rs b/tests/test.rs index 10b583e9ae..97438a95b4 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -24,7 +24,7 @@ impl Test { expected_stdout: Expected::String(String::new()), }; - test.sync(); + test.state.sync(); test } @@ -103,22 +103,6 @@ impl Test { self.output(); } - fn get_block(&self, height: u64) -> Block { - self - .state - .client - .get_block(&self.state.client.get_block_hash(height).unwrap()) - .unwrap() - } - - fn sync(&self) { - self - .state - .wallet - .sync(&self.state.blockchain, SyncOptions::default()) - .unwrap(); - } - pub(crate) fn output(self) -> Output { let output = Command::new(executable_path("ord")) .envs(self.envs.clone()) @@ -172,68 +156,7 @@ impl Test { } pub(crate) fn transaction(self, options: TransactionOptions) -> Self { - self.sync(); - - let input_value = options - .slots - .iter() - .map(|slot| self.get_block(slot.0 as u64).txdata[slot.1].output[slot.2].value) - .sum::(); - - let output_value = input_value - options.fee; - - let (mut psbt, _) = { - let mut builder = self.state.wallet.build_tx(); - - builder - .manually_selected_only() - .fee_absolute(options.fee) - .allow_dust(true) - .add_utxos( - &options - .slots - .iter() - .map(|slot| OutPoint { - txid: self.get_block(slot.0 as u64).txdata[slot.1].txid(), - vout: slot.2 as u32, - }) - .collect::>(), - ) - .unwrap() - .set_recipients(vec![ - ( - self - .state - .wallet - .get_address(AddressIndex::Peek(0)) - .unwrap() - .address - .script_pubkey(), - output_value / options.output_count as u64 - ); - options.output_count - ]); - - builder.finish().unwrap() - }; - - if !self - .state - .wallet - .sign(&mut psbt, SignOptions::default()) - .unwrap() - { - panic!("Failed to sign transaction"); - } - - self - .state - .client - .call::( - "sendrawtransaction", - &[psbt.extract_tx().raw_hex().into(), 21000000.into()], - ) - .unwrap(); + self.state.transaction(options); self } From 6c563eaf6fd0fffd55484e314b8fd23b4ee1032c Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 8 Aug 2022 19:01:10 -0400 Subject: [PATCH 47/61] Fix outputs --- tests/server.rs | 21 ++++++--------------- tests/state.rs | 6 +++++- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/tests/server.rs b/tests/server.rs index 99748d6e9f..79dfd519fb 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -171,31 +171,22 @@ fn block_not_found() { fn outputs() { let state = State::new(); - state.blocks(1); + state.blocks(101); + + sleep(Duration::from_secs(1)); state.transaction(TransactionOptions { - slots: &[(0, 0, 0)], + slots: &[(1, 0, 0)], output_count: 1, fee: 0, }); state.request( - "block/14508459b221041eab257d2baaa7459775ba748246c8403609eb708f0e57e74b", - 200, - " - - ", - ); - - state.request( - "tx/0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9", + "tx/30b037a346d31902f146a53d9ac8fa90541f43ca4a5e321914e86acdbf28394c", 200, " " ); diff --git a/tests/state.rs b/tests/state.rs index 955c0dfe0a..ad3028fe33 100644 --- a/tests/state.rs +++ b/tests/state.rs @@ -209,11 +209,15 @@ impl State { panic!("Failed to sign transaction"); } + let tx = psbt.extract_tx(); + + eprintln!("{}", tx.txid()); + self .client .call::( "sendrawtransaction", - &[psbt.extract_tx().raw_hex().into(), 21000000.into()], + &[tx.raw_hex().into(), 21000000.into()], ) .unwrap(); } From f9fbb79a72595d960c36d80541ad895c10832604 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 8 Aug 2022 19:07:22 -0400 Subject: [PATCH 48/61] Transactions still broken --- tests/server.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/server.rs b/tests/server.rs index 79dfd519fb..d0bbde1324 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -138,10 +138,12 @@ fn root() { fn transactions() { let state = State::new(); - state.blocks(1); + state.blocks(101); + + sleep(Duration::from_secs(1)); state.transaction(TransactionOptions { - slots: &[(0, 0, 0)], + slots: &[(1, 0, 0)], output_count: 1, fee: 0, }); From 557d5bdb2f7f97dfad9656d8807362625989b3e2 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 8 Aug 2022 19:20:39 -0400 Subject: [PATCH 49/61] All server tests pass --- src/index.rs | 8 ++++++++ tests/server.rs | 10 ++++++---- tests/state.rs | 6 +++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/index.rs b/src/index.rs index b804639004..6675a03d69 100644 --- a/src/index.rs +++ b/src/index.rs @@ -325,6 +325,13 @@ impl Index { Err(bitcoincore_rpc::Error::JsonRpc(bitcoincore_rpc::jsonrpc::error::Error::Rpc( bitcoincore_rpc::jsonrpc::error::RpcError { code: -8, .. }, ))) => Ok(None), + Err(bitcoincore_rpc::Error::JsonRpc(bitcoincore_rpc::jsonrpc::error::Error::Rpc( + bitcoincore_rpc::jsonrpc::error::RpcError { message, .. }, + ))) + if message == "Block not found" => + { + Ok(None) + } Err(err) => Err(err.into()), } } @@ -335,6 +342,7 @@ impl Index { Err(bitcoincore_rpc::Error::JsonRpc(bitcoincore_rpc::jsonrpc::error::Error::Rpc( bitcoincore_rpc::jsonrpc::error::RpcError { code: -8, .. }, ))) => Ok(None), + Err(err) => Err(err.into()), } } diff --git a/tests/server.rs b/tests/server.rs index d0bbde1324..6da11765c2 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -148,15 +148,17 @@ fn transactions() { fee: 0, }); + let blocks = state.blocks(1); + state.request( - "block/14508459b221041eab257d2baaa7459775ba748246c8403609eb708f0e57e74b", + &format!("block/{}", blocks[0]), 200, " - ", + " ); } diff --git a/tests/state.rs b/tests/state.rs index ad3028fe33..3da058b5f0 100644 --- a/tests/state.rs +++ b/tests/state.rs @@ -146,7 +146,7 @@ impl State { .unwrap(); } - pub(crate) fn blocks(&self, n: u64) { + pub(crate) fn blocks(&self, n: u64) -> Vec { self .client .generate_to_address( @@ -157,7 +157,7 @@ impl State { .unwrap() .address, ) - .unwrap(); + .unwrap() } pub(crate) fn transaction(&self, options: TransactionOptions) { @@ -211,7 +211,7 @@ impl State { let tx = psbt.extract_tx(); - eprintln!("{}", tx.txid()); + eprintln!("YOLO: {}", tx.txid()); self .client From 09895ba5097d577878f166f40f31bc54437f4deb Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 8 Aug 2022 19:25:30 -0400 Subject: [PATCH 50/61] Fix ci breakage --- tests/find.rs | 1 - tests/lib.rs | 1 - tests/server.rs | 2 +- tests/state.rs | 2 +- tests/test.rs | 14 +------------- tests/wallet.rs | 9 --------- 6 files changed, 3 insertions(+), 26 deletions(-) diff --git a/tests/find.rs b/tests/find.rs index 58b233c617..2c7ef95520 100644 --- a/tests/find.rs +++ b/tests/find.rs @@ -26,7 +26,6 @@ fn second_satoshi() { .run(); } -// TODO: fix ignore tests #[test] #[ignore] fn second_satoshi_slot() { diff --git a/tests/lib.rs b/tests/lib.rs index c7a23daf12..3b82831bec 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -21,7 +21,6 @@ use { regex::Regex, std::{ collections::BTreeMap, - ffi::OsString, fs, net::TcpListener, process::{Child, Command, Stdio}, diff --git a/tests/server.rs b/tests/server.rs index 6da11765c2..c373fcaaf1 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -158,7 +158,7 @@ fn transactions() {
  • 0 - [[:xdigit:]]{64}
  • 1 - [[:xdigit:]]{64}
  • - " + ", ); } diff --git a/tests/state.rs b/tests/state.rs index 3da058b5f0..fac7b12f59 100644 --- a/tests/state.rs +++ b/tests/state.rs @@ -15,7 +15,7 @@ static ONCE: Once = Once::new(); impl State { pub(crate) fn new() -> Self { - ONCE.call_once(|| env_logger::init()); + ONCE.call_once(env_logger::init); let tempdir = TempDir::new().unwrap(); diff --git a/tests/test.rs b/tests/test.rs index 97438a95b4..836c79bd94 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -2,7 +2,6 @@ use super::*; pub(crate) struct Test { args: Vec, - envs: Vec<(OsString, OsString)>, expected_status: i32, expected_stderr: Expected, expected_stdout: Expected, @@ -18,7 +17,6 @@ impl Test { let test = Self { args: Vec::new(), state, - envs: Vec::new(), expected_status: 0, expected_stderr: Expected::Ignore, expected_stdout: Expected::String(String::new()), @@ -61,16 +59,6 @@ impl Test { } } - // TODO: do this always - pub(crate) fn set_home_to_tempdir(mut self) -> Self { - self.envs.push(( - OsString::from("HOME"), - OsString::from(self.state.tempdir.path()), - )); - - self - } - pub(crate) fn expected_stderr(self, expected_stderr: &str) -> Self { Self { expected_stderr: Expected::String(expected_stderr.to_owned()), @@ -105,7 +93,7 @@ impl Test { pub(crate) fn output(self) -> Output { let output = Command::new(executable_path("ord")) - .envs(self.envs.clone()) + .env("HOME", self.state.tempdir.path()) .stdin(Stdio::null()) .stdout(Stdio::piped()) .stderr(if !matches!(self.expected_stderr, Expected::Ignore) { diff --git a/tests/wallet.rs b/tests/wallet.rs index 1116223df8..cabd89fbdf 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -12,7 +12,6 @@ fn path(path: &str) -> String { fn init_existing_wallet() { let state = Test::new() .command("wallet init") - .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") .output() @@ -28,7 +27,6 @@ fn init_existing_wallet() { Test::with_state(state) .command("wallet init") - .set_home_to_tempdir() .expected_status(1) .expected_stderr("error: Wallet already exists.\n") .run() @@ -38,7 +36,6 @@ fn init_existing_wallet() { fn init_nonexistent_wallet() { let output = Test::new() .command("wallet init") - .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") .output(); @@ -62,7 +59,6 @@ fn init_nonexistent_wallet() { fn load_corrupted_entropy() { let state = Test::new() .command("wallet init") - .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") .output() @@ -79,7 +75,6 @@ fn load_corrupted_entropy() { Test::with_state(state) .command("wallet fund") - .set_home_to_tempdir() .expected_status(1) .expected_stderr("error: ChecksumMismatch\n") .run(); @@ -89,16 +84,13 @@ fn load_corrupted_entropy() { fn fund_existing_wallet() { let state = Test::new() .command("wallet init") - .set_home_to_tempdir() .expected_status(0) .expected_stderr("Wallet initialized.\n") - .set_home_to_tempdir() .output() .state; Test::with_state(state) .command("wallet fund") - .set_home_to_tempdir() .stdout_regex("^tb1.*\n") .run(); } @@ -107,7 +99,6 @@ fn fund_existing_wallet() { fn fund_nonexistent_wallet() { Test::new() .command("wallet fund") - .set_home_to_tempdir() .expected_status(1) .expected_stderr("error: Wallet doesn't exist.\n") .run(); From 2e31c188c93183a96c992442a66795e9aad492b2 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 8 Aug 2022 19:27:18 -0400 Subject: [PATCH 51/61] Run with a single test thread --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 85ea05852f..d69fe2632e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -44,7 +44,7 @@ jobs: cargo update --locked --package ord - name: Test - run: cargo test --all + run: cargo test --all -- --test-threads=1 - name: Clippy run: cargo clippy --all --all-targets From c37b945270ff2e38b74caca8266e64070386403a Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 8 Aug 2022 19:31:34 -0400 Subject: [PATCH 52/61] Install bitcoind --- .github/workflows/ci.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d69fe2632e..fe9e9d037f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -37,11 +37,13 @@ jobs: override: true toolchain: stable + - name: Install bitcoind + run: brew install bitcoind + - uses: Swatinem/rust-cache@v1 - name: Check Lockfile - run: | - cargo update --locked --package ord + run: cargo update --locked --package ord - name: Test run: cargo test --all -- --test-threads=1 From f8b84bfb617f4d9b4bda8e3b4bb22a845c296d1a Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 8 Aug 2022 19:33:05 -0400 Subject: [PATCH 53/61] Bitcoin -> Bitcoind --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index fe9e9d037f..905b3643e5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -38,7 +38,7 @@ jobs: toolchain: stable - name: Install bitcoind - run: brew install bitcoind + run: brew install bitcoin - uses: Swatinem/rust-cache@v1 From 0da8ce7af634365eb7968471a59dae7618d5ca6c Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 8 Aug 2022 19:40:48 -0400 Subject: [PATCH 54/61] Install sqlite --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 905b3643e5..b49bfc7c12 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -37,8 +37,8 @@ jobs: override: true toolchain: stable - - name: Install bitcoind - run: brew install bitcoin + - name: Install dependencies + run: brew install bitcoin sqlite - uses: Swatinem/rust-cache@v1 From e3fd7e3c3dba57d9ec8093620b32684544574960 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 9 Aug 2022 12:53:39 -0400 Subject: [PATCH 55/61] Load server on first request --- tests/server.rs | 12 +++--- tests/state.rs | 106 ++++++++++++++++++++++++++---------------------- 2 files changed, 64 insertions(+), 54 deletions(-) diff --git a/tests/server.rs b/tests/server.rs index c373fcaaf1..c7d4f25532 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -2,7 +2,7 @@ use super::*; #[test] fn list() { - let state = State::new(); + let mut state = State::new(); state.blocks(1); @@ -88,7 +88,7 @@ fn invalid_outpoint_hash_returns_400() { #[test] fn outpoint_returns_ordinal_ranges() { - let state = State::new(); + let mut state = State::new(); state.blocks(1); @@ -103,7 +103,7 @@ fn outpoint_returns_ordinal_ranges() { #[test] fn invalid_vout_returns_404() { - let state = State::new(); + let mut state = State::new(); state.blocks(1); @@ -116,7 +116,7 @@ fn invalid_vout_returns_404() { #[test] fn root() { - let state = State::new(); + let mut state = State::new(); state.blocks(1); @@ -136,7 +136,7 @@ fn root() { #[test] fn transactions() { - let state = State::new(); + let mut state = State::new(); state.blocks(101); @@ -173,7 +173,7 @@ fn block_not_found() { #[test] fn outputs() { - let state = State::new(); + let mut state = State::new(); state.blocks(101); diff --git a/tests/state.rs b/tests/state.rs index fac7b12f59..e664b46a7a 100644 --- a/tests/state.rs +++ b/tests/state.rs @@ -7,8 +7,8 @@ pub(crate) struct State { pub(crate) wallet: Wallet, pub(crate) blockchain: RpcBlockchain, pub(crate) bitcoind_rpc_port: u16, - ord_http_port: u16, - ord: Child, + ord_http_port: Option, + ord: Option, } static ONCE: Once = Once::new(); @@ -66,36 +66,6 @@ impl State { sleep(Duration::from_millis(100)); } - let ord_http_port = free_port(); - - fs::create_dir(tempdir.path().join("server")).unwrap(); - - let ord = Command::new(executable_path("ord")) - .current_dir(tempdir.path().join("server")) - .arg(format!("--rpc-url=localhost:{}", bitcoind_rpc_port)) - .arg("--cookie-file=../bitcoin/regtest/.cookie") - .args([ - "server", - "--address", - "127.0.0.1", - "--http-port", - &ord_http_port.to_string(), - ]) - .spawn() - .unwrap(); - - for attempt in 0..=300 { - match reqwest::blocking::get(&format!("http://127.0.0.1:{ord_http_port}/status")) { - Ok(response) if response.status().is_success() => break, - result => { - if attempt == 300 { - panic!("Failed to connect to ord server: {result:?}"); - } - } - } - sleep(Duration::from_millis(100)); - } - let wallet = Wallet::new( Bip84( ( @@ -123,11 +93,11 @@ impl State { State { tempdir, bitcoind_rpc_port, - ord_http_port, + ord_http_port: None, bitcoind, client, wallet, - ord, + ord: None, blockchain, } } @@ -222,29 +192,69 @@ impl State { .unwrap(); } - pub(crate) fn request(&self, path: &str, status: u16, expected_response: &str) { - let response = - reqwest::blocking::get(&format!("http://127.0.0.1:{}/{}", self.ord_http_port, path)).unwrap(); + pub(crate) fn request(&mut self, path: &str, status: u16, expected_response: &str) { + if let Some(ord_http_port) = self.ord_http_port { + let response = + reqwest::blocking::get(&format!("http://127.0.0.1:{}/{}", ord_http_port, path)).unwrap(); - log::info!("{:?}", response); + log::info!("{:?}", response); - assert_eq!(response.status().as_u16(), status); + assert_eq!(response.status().as_u16(), status); - let response_text = response.text().unwrap(); + let response_text = response.text().unwrap(); - assert!( - Regex::new(expected_response.unindent().trim_end()) - .unwrap() - .is_match(&response_text), - "Response text did not match regex: {:?}", - &response_text - ); + assert!( + Regex::new(expected_response.unindent().trim_end()) + .unwrap() + .is_match(&response_text), + "Response text did not match regex: {:?}", + &response_text + ); + } else { + let ord_http_port = free_port(); + + fs::create_dir(self.tempdir.path().join("server")).unwrap(); + + let ord = Command::new(executable_path("ord")) + .current_dir(self.tempdir.path().join("server")) + .arg(format!("--rpc-url=localhost:{}", self.bitcoind_rpc_port)) + .arg("--cookie-file=../bitcoin/regtest/.cookie") + .args([ + "server", + "--address", + "127.0.0.1", + "--http-port", + &ord_http_port.to_string(), + ]) + .spawn() + .unwrap(); + + for attempt in 0..=300 { + match reqwest::blocking::get(&format!("http://127.0.0.1:{ord_http_port}/status")) { + Ok(response) if response.status().is_success() => break, + result => { + if attempt == 300 { + panic!("Failed to connect to ord server: {result:?}"); + } + } + } + sleep(Duration::from_millis(100)); + } + + self.ord = Some(ord); + self.ord_http_port = Some(ord_http_port); + + self.request(path, status, expected_response); + } } } impl Drop for State { fn drop(&mut self) { - self.ord.kill().unwrap(); + if let Some(ord) = &mut self.ord { + ord.kill().unwrap(); + } + self.bitcoind.kill().unwrap(); } } From ee58902425ee47e0d2661468a0008329df3a066e Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 9 Aug 2022 14:04:38 -0400 Subject: [PATCH 56/61] Fix import errors --- src/index.rs | 2 +- src/main.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/index.rs b/src/index.rs index 6675a03d69..4836702447 100644 --- a/src/index.rs +++ b/src/index.rs @@ -1,6 +1,6 @@ use { super::*, - bitcoincore_rpc::{Client, RpcApi}, + bitcoincore_rpc::{Auth, Client, RpcApi}, rayon::iter::{IntoParallelRefIterator, ParallelIterator}, }; diff --git a/src/main.rs b/src/main.rs index a4bc7d804d..0432638e37 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,7 +34,6 @@ use { util::key::PrivateKey, Block, Network, OutPoint, Transaction, Txid, }, - bitcoincore_rpc::Auth, chrono::{DateTime, NaiveDateTime, Utc}, clap::Parser, derive_more::{Display, FromStr}, From 77aa8c5344ed0871e3ed3bd768d599b2e2620ac7 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 9 Aug 2022 14:09:03 -0400 Subject: [PATCH 57/61] Fix regex --- tests/wallet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/wallet.rs b/tests/wallet.rs index 62f66f7118..6ff4b95cac 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -91,7 +91,7 @@ fn fund_existing_wallet() { Test::with_state(state) .command("wallet fund") - .stdout_regex("^tb1.*\n") + .stdout_regex("^bcrt1.*\n") .run(); } From 8b6322e4c094fb5489114d8bd11b34645e4b0e93 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 9 Aug 2022 14:24:56 -0400 Subject: [PATCH 58/61] Clippy --- justfile | 2 +- src/subcommand/wallet/fund.rs | 6 ++---- src/subcommand/wallet/utxos.rs | 5 +++-- tests/wallet.rs | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/justfile b/justfile index 7a49673525..72b5e4a6b3 100644 --- a/justfile +++ b/justfile @@ -1,6 +1,6 @@ ci: clippy forbid cargo fmt -- --check - cargo test + cargo test -- --test-threads=1 forbid: ./bin/forbid diff --git a/src/subcommand/wallet/fund.rs b/src/subcommand/wallet/fund.rs index 22299a54d1..597f256060 100644 --- a/src/subcommand/wallet/fund.rs +++ b/src/subcommand/wallet/fund.rs @@ -1,8 +1,6 @@ use super::*; pub(crate) fn run(options: Options) -> Result { - Ok(println!( - "{}", - get_wallet(options)?.get_address(LastUnused)?.address - )) + println!("{}", get_wallet(options)?.get_address(LastUnused)?.address); + Ok(()) } diff --git a/src/subcommand/wallet/utxos.rs b/src/subcommand/wallet/utxos.rs index ccacca8e61..fffad991d7 100644 --- a/src/subcommand/wallet/utxos.rs +++ b/src/subcommand/wallet/utxos.rs @@ -1,7 +1,7 @@ use super::*; pub(crate) fn run(options: Options) -> Result { - Ok(println!( + println!( "{}", get_wallet(options)? .list_unspent()? @@ -9,5 +9,6 @@ pub(crate) fn run(options: Options) -> Result { .map(|utxo| format!("{}:{}", utxo.outpoint.txid, utxo.outpoint.vout)) .collect::>() .join("\n") - )) + ); + Ok(()) } diff --git a/tests/wallet.rs b/tests/wallet.rs index 6ff4b95cac..7e819325ac 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -124,7 +124,7 @@ fn utxos() { .generate_to_address( 101, &Address::from_str( - &output + output .stdout .strip_suffix('\n') .ok_or("Failed to strip suffix") From c8a21a608c56bd15499a5a364fb280e449a9fb55 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 9 Aug 2022 13:27:18 -0700 Subject: [PATCH 59/61] Install bitcoin from release on linux --- .github/workflows/ci.yaml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b49bfc7c12..0567837353 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -37,8 +37,16 @@ jobs: override: true toolchain: stable - - name: Install dependencies - run: brew install bitcoin sqlite + - name: Install Bitcoin from Homebrew + if: ${{ matrix.os == 'macos-latest' }} + run: brew install bitcoin + + - name: Install from bitcoincore.org + if: ${{ matrix.os == 'ubuntu-latest' }} + run: | + curl -O https://bitcoincore.org/bin/bitcoin-core-23.0/bitcoin-23.0-x86_64-linux-gnu.tar.gz + tar xvf bitcoin-23.0-x86_64-linux-gnu.tar.gz + cp bitcoin-23.0/bin/bitcoind /usr/local/bin/ - uses: Swatinem/rust-cache@v1 From 64c86ebff977518af149505a1d592803b94ab707 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 9 Aug 2022 17:43:55 -0400 Subject: [PATCH 60/61] Fix mergies --- src/index.rs | 20 ++++++-------------- tests/lib.rs | 5 ++--- tests/wallet.rs | 4 ++-- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/index.rs b/src/index.rs index 4836702447..12abfc0205 100644 --- a/src/index.rs +++ b/src/index.rs @@ -95,17 +95,12 @@ impl Index { loop { let mut wtx = self.database.begin_write()?; - match self.index_block(&mut wtx) { - Ok(done) => { - wtx.commit()?; - if done || INTERRUPTS.load(atomic::Ordering::Relaxed) > 0 { - break; - } - } - Err(err) => { - wtx.abort()?; - return Err(err); - } + let done = self.index_block(&mut wtx)?; + + wtx.commit()?; + + if done || INTERRUPTS.load(atomic::Ordering::Relaxed) > 0 { + break; } } @@ -257,8 +252,6 @@ impl Index { input_ordinal_ranges: &mut VecDeque<(u64, u64)>, ordinal_ranges_written: &mut u64, ) -> Result { - log::trace!("{txid}: {:?}", tx); - for (vout, output) in tx.output.iter().enumerate() { let outpoint = OutPoint { vout: vout as u32, @@ -342,7 +335,6 @@ impl Index { Err(bitcoincore_rpc::Error::JsonRpc(bitcoincore_rpc::jsonrpc::error::Error::Rpc( bitcoincore_rpc::jsonrpc::error::RpcError { code: -8, .. }, ))) => Ok(None), - Err(err) => Err(err.into()), } } diff --git a/tests/lib.rs b/tests/lib.rs index 6ec61e882b..34cbba69a9 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -13,8 +13,7 @@ use { wallet::{signer::SignOptions, AddressIndex, SyncOptions, Wallet}, KeychainKind, }, - bitcoin::hash_types::Txid, - bitcoin::{network::constants::Network, Block, OutPoint}, + bitcoin::{hash_types::Txid, network::constants::Network, Address, Block, OutPoint}, bitcoincore_rpc::{Client, RawTx, RpcApi}, executable_path::executable_path, log::LevelFilter, @@ -24,7 +23,7 @@ use { fs, net::TcpListener, process::{Child, Command, Stdio}, - str, + str::{self, FromStr}, sync::Once, thread::sleep, time::Duration, diff --git a/tests/wallet.rs b/tests/wallet.rs index 7e819325ac..e4b6fd7e5f 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -1,4 +1,4 @@ -use {super::*, bitcoin::Address, std::str::FromStr}; +use super::*; fn path(path: &str) -> String { if cfg!(target_os = "macos") { @@ -137,6 +137,6 @@ fn utxos() { Test::with_state(output.state) .command("wallet utxos") .expected_status(0) - .stdout_regex("^[a-z0-9]{64}:[0-9]*\n") + .stdout_regex("^[[:xdigit:]]{64}:[[:digit:]]*\n") .run() } From a81be370a1cda150e01e8b15eb09b3a4c4f0ebff Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 9 Aug 2022 18:05:14 -0400 Subject: [PATCH 61/61] Address review comments --- src/options.rs | 4 ++-- src/subcommand/wallet.rs | 17 +++++++---------- src/subcommand/wallet/init.rs | 17 +++++++---------- src/subcommand/wallet/utxos.rs | 15 ++++++--------- tests/wallet.rs | 24 ++++++++++++------------ 5 files changed, 34 insertions(+), 43 deletions(-) diff --git a/src/options.rs b/src/options.rs index 33c27481df..b1ec1254f8 100644 --- a/src/options.rs +++ b/src/options.rs @@ -5,9 +5,9 @@ pub(crate) struct Options { #[clap(long, default_value = "10MiB")] pub(crate) max_index_size: Bytes, #[clap(long)] - pub(crate) cookie_file: Option, + cookie_file: Option, #[clap(long)] - pub(crate) rpc_url: Option, + rpc_url: Option, #[clap(long, default_value = "bitcoin")] pub(crate) network: Network, } diff --git a/src/subcommand/wallet.rs b/src/subcommand/wallet.rs index a9551c5776..86d5fd3b2d 100644 --- a/src/subcommand/wallet.rs +++ b/src/subcommand/wallet.rs @@ -21,7 +21,7 @@ fn get_wallet(options: Options) -> Result> { let wallet = bdk::wallet::Wallet::new( Bip84(key.clone(), KeychainKind::External), None, - Network::Regtest, + options.network, SqliteDatabase::new( path .join("wallet.sqlite") @@ -33,18 +33,15 @@ fn get_wallet(options: Options) -> Result> { wallet.sync( &RpcBlockchain::from_config(&RpcConfig { - url: options - .rpc_url - .ok_or_else(|| anyhow!("This command requires `--rpc-url`"))?, - auth: options - .cookie_file - .map(|path| Auth::Cookie { file: path }) - .unwrap_or(Auth::None), - network: Network::Regtest, + url: options.rpc_url(), + auth: Auth::Cookie { + file: options.cookie_file()?, + }, + network: options.network, wallet_name: wallet_name_from_descriptor( Bip84(key, KeychainKind::External), None, - Network::Regtest, + options.network, &Secp256k1::new(), )?, skip_blocks: None, diff --git a/src/subcommand/wallet/init.rs b/src/subcommand/wallet/init.rs index 75740a89ef..7f05d6f5b6 100644 --- a/src/subcommand/wallet/init.rs +++ b/src/subcommand/wallet/init.rs @@ -18,7 +18,7 @@ pub(crate) fn run(options: Options) -> Result { let wallet = bdk::wallet::Wallet::new( Bip84((seed.clone(), None), KeychainKind::External), None, - Network::Regtest, + options.network, SqliteDatabase::new( path .join("wallet.sqlite") @@ -30,18 +30,15 @@ pub(crate) fn run(options: Options) -> Result { wallet.sync( &RpcBlockchain::from_config(&RpcConfig { - url: options - .rpc_url - .ok_or_else(|| anyhow!("This command requires `--rpc-url`"))?, - auth: options - .cookie_file - .map(|path| Auth::Cookie { file: path }) - .unwrap_or(Auth::None), - network: Network::Regtest, + url: options.rpc_url(), + auth: Auth::Cookie { + file: options.cookie_file()?, + }, + network: options.network, wallet_name: wallet_name_from_descriptor( Bip84((seed, None), KeychainKind::External), None, - Network::Regtest, + options.network, &Secp256k1::new(), )?, skip_blocks: None, diff --git a/src/subcommand/wallet/utxos.rs b/src/subcommand/wallet/utxos.rs index fffad991d7..badbe6eec6 100644 --- a/src/subcommand/wallet/utxos.rs +++ b/src/subcommand/wallet/utxos.rs @@ -1,14 +1,11 @@ use super::*; pub(crate) fn run(options: Options) -> Result { - println!( - "{}", - get_wallet(options)? - .list_unspent()? - .iter() - .map(|utxo| format!("{}:{}", utxo.outpoint.txid, utxo.outpoint.vout)) - .collect::>() - .join("\n") - ); + for utxo in get_wallet(options)?.list_unspent()? { + println!( + "{}:{} {}", + utxo.outpoint.txid, utxo.outpoint.vout, utxo.txout.value + ); + } Ok(()) } diff --git a/tests/wallet.rs b/tests/wallet.rs index e4b6fd7e5f..864a0c3394 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -11,7 +11,7 @@ fn path(path: &str) -> String { #[test] fn init_existing_wallet() { let state = Test::new() - .command("wallet init") + .command("--network regtest wallet init") .expected_status(0) .expected_stderr("Wallet initialized.\n") .output() @@ -26,7 +26,7 @@ fn init_existing_wallet() { assert!(state.tempdir.path().join(path("ord/entropy")).exists()); Test::with_state(state) - .command("wallet init") + .command("--network regtest wallet init") .expected_status(1) .expected_stderr("error: Wallet already exists.\n") .run() @@ -35,7 +35,7 @@ fn init_existing_wallet() { #[test] fn init_nonexistent_wallet() { let output = Test::new() - .command("wallet init") + .command("--network regtest wallet init") .expected_status(0) .expected_stderr("Wallet initialized.\n") .output(); @@ -58,7 +58,7 @@ fn init_nonexistent_wallet() { #[test] fn load_corrupted_entropy() { let state = Test::new() - .command("wallet init") + .command("--network regtest wallet init") .expected_status(0) .expected_stderr("Wallet initialized.\n") .output() @@ -74,7 +74,7 @@ fn load_corrupted_entropy() { fs::write(&entropy_path, entropy).unwrap(); Test::with_state(state) - .command("wallet fund") + .command("--network regtest wallet fund") .expected_status(1) .expected_stderr("error: ChecksumMismatch\n") .run(); @@ -83,14 +83,14 @@ fn load_corrupted_entropy() { #[test] fn fund_existing_wallet() { let state = Test::new() - .command("wallet init") + .command("--network regtest wallet init") .expected_status(0) .expected_stderr("Wallet initialized.\n") .output() .state; Test::with_state(state) - .command("wallet fund") + .command("--network regtest wallet fund") .stdout_regex("^bcrt1.*\n") .run(); } @@ -98,7 +98,7 @@ fn fund_existing_wallet() { #[test] fn fund_nonexistent_wallet() { Test::new() - .command("wallet fund") + .command("--network regtest wallet fund") .expected_status(1) .expected_stderr("error: Wallet doesn't exist.\n") .run(); @@ -107,14 +107,14 @@ fn fund_nonexistent_wallet() { #[test] fn utxos() { let state = Test::new() - .command("wallet init") + .command("--network regtest wallet init") .expected_status(0) .expected_stderr("Wallet initialized.\n") .output() .state; let output = Test::with_state(state) - .command("wallet fund") + .command("--network regtest wallet fund") .stdout_regex("^bcrt1.*\n") .output(); @@ -135,8 +135,8 @@ fn utxos() { .unwrap(); Test::with_state(output.state) - .command("wallet utxos") + .command("--network regtest wallet utxos") .expected_status(0) - .stdout_regex("^[[:xdigit:]]{64}:[[:digit:]]*\n") + .stdout_regex("^[[:xdigit:]]{64}:0 5000000000\n") .run() }