diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..0b3779e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,5 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1d90a4f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +name: ci + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + run-tests: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + + - name: Cache cargo registry + uses: actions/cache@v3 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-registry- + + - name: Run tests + run: cargo test diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..1bad2a0 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,139 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in library 'spaced'", + "cargo": { + "args": [ + "test", + "--no-run", + "--lib", + "--package=spaced" + ], + "filter": { + "name": "spaced", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'space-cli'", + "cargo": { + "args": [ + "build", + "--bin=space-cli", + "--package=spaced" + ], + "filter": { + "name": "space-cli", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'space-cli'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=space-cli", + "--package=spaced" + ], + "filter": { + "name": "space-cli", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'spaced'", + "cargo": { + "args": [ + "build", + "--bin=spaced", + "--package=spaced" + ], + "filter": { + "name": "spaced", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'spaced'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=spaced", + "--package=spaced" + ], + "filter": { + "name": "spaced", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in library 'protocol'", + "cargo": { + "args": [ + "test", + "--no-run", + "--lib", + "--package=protocol" + ], + "filter": { + "name": "protocol", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in library 'wallet'", + "cargo": { + "args": [ + "test", + "--no-run", + "--lib", + "--package=wallet" + ], + "filter": { + "name": "wallet", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7ea5d0f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "cSpell.words": [ + "bitcoind", + "regtest", + "tempdir", + "tempfile" + ] +} diff --git a/Cargo.lock b/Cargo.lock index 031c314..366d9a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,23 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -87,6 +104,22 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "assert_cmd" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d" +dependencies = [ + "anstyle", + "bstr", + "doc-comment", + "libc", + "predicates", + "predicates-core", + "predicates-tree", + "wait-timeout", +] + [[package]] name = "async-trait" version = "0.1.77" @@ -120,7 +153,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.2", "object", "rustc-demangle", ] @@ -153,6 +186,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bdk_chain" version = "0.16.0" @@ -307,6 +346,48 @@ dependencies = [ "serde", ] +[[package]] +name = "bitcoincore-rpc" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedd23ae0fd321affb4bbbc36126c6f49a32818dc6b979395d24da8c9d4e80ee" +dependencies = [ + "bitcoincore-rpc-json", + "jsonrpc", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "bitcoincore-rpc-json" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8909583c5fab98508e80ef73e5592a651c954993dc6b7739963257d19f0e71a" +dependencies = [ + "bitcoin", + "serde", + "serde_json", +] + +[[package]] +name = "bitcoind" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ee5cf6a9903ff9cc808494c1232b0e9f6eef6600913d0d69fe1cb5c428f25b9" +dependencies = [ + "anyhow", + "bitcoin_hashes 0.14.0", + "bitcoincore-rpc", + "flate2", + "log", + "minreq", + "tar", + "tempfile", + "which", + "zip", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -337,23 +418,65 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bstr" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + [[package]] name = "bumpalo" version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +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.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +dependencies = [ + "jobserver", + "libc", +] [[package]] name = "cfg-if" @@ -367,6 +490,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.5.6" @@ -413,6 +546,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "core-foundation" version = "0.9.4" @@ -438,6 +577,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "crypto-common" version = "0.1.6" @@ -458,6 +612,21 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "digest" version = "0.9.0" @@ -475,6 +644,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", "crypto-common", + "subtle", ] [[package]] @@ -498,6 +668,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "encoding_rs" version = "0.8.34" @@ -552,6 +734,37 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", +] + +[[package]] +name = "flate2" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +dependencies = [ + "crc32fast", + "miniz_oxide 0.8.0", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "fnv" version = "1.0.7" @@ -787,6 +1000,24 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "http" version = "0.2.12" @@ -994,6 +1225,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -1012,6 +1252,15 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.69" @@ -1028,6 +1277,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3662a38d341d77efecb73caf01420cfa5aa63c0253fd7bc05289ef9f6616e1bf" dependencies = [ "base64 0.13.1", + "minreq", "serde", "serde_json", ] @@ -1248,6 +1498,30 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "minreq" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763d142cdff44aaadd9268bebddb156ef6c65a0e13486bb81673cf2d8739f9b0" +dependencies = [ + "log", + "once_cell", + "rustls 0.21.10", + "rustls-webpki 0.101.7", + "serde", + "serde_json", + "webpki-roots", +] + [[package]] name = "mio" version = "0.8.11" @@ -1288,6 +1562,27 @@ dependencies = [ "libc", ] +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -1387,11 +1682,34 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.1", "smallvec", "windows-targets 0.52.4", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", + "hmac", + "password-hash", + "sha2 0.10.8", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1436,12 +1754,48 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "predicates" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" +dependencies = [ + "anstyle", + "difflib", + "float-cmp", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" + +[[package]] +name = "predicates-tree" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "proc-macro-crate" version = "3.1.0" @@ -1510,6 +1864,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.1" @@ -1899,6 +2262,17 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sha2" version = "0.10.6" @@ -1909,6 +2283,17 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -1964,8 +2349,10 @@ name = "spaced" version = "0.0.2" dependencies = [ "anyhow", + "assert_cmd", "base64 0.22.1", "bincode 2.0.0-rc.3", + "bitcoind", "clap", "ctrlc", "directories", @@ -1974,6 +2361,7 @@ dependencies = [ "hex", "jsonrpsee", "log", + "predicates", "protocol", "reqwest", "serde", @@ -1993,7 +2381,7 @@ dependencies = [ "bincode 2.0.0-rc.3", "hex", "libc", - "sha2", + "sha2 0.10.6", ] [[package]] @@ -2052,6 +2440,17 @@ dependencies = [ "libc", ] +[[package]] +name = "tar" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tempfile" version = "3.10.1" @@ -2064,20 +2463,26 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + [[package]] name = "thiserror" -version = "1.0.60" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.60" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", @@ -2093,6 +2498,25 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "tinyvec" version = "1.6.0" @@ -2385,6 +2809,15 @@ version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314" +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "wallet" version = "0.0.2" @@ -2496,6 +2929,24 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -2656,8 +3107,68 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + [[package]] name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/README.md b/README.md index 50dfd1b..c76494f 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,18 @@ # Spaced - Bitcoin Spaces daemon -Spaces is a naming protocol that leverages the existing infrastructure and security of Bitcoin without requiring a new blockchain or any modifications to Bitcoin itself [learn more](https://spacesprotocol.org). +Spaces is a naming protocol that leverages the existing infrastructure and security of Bitcoin without requiring a new blockchain or any modifications to Bitcoin itself [learn more](https://spacesprotocol.org). ## Project Structure -| Package | Requires std | | -|----------|------------------|-------------------------------------------------| -| node | Yes | Daemon and wallet service | | -| wallet | Yes (no-std WIP) | wallet library for building spaces transactions | -| protocol | No | Protocol consensus library | - +| Package | Requires std | Description | +|----------|------------------|------------------------------------------------| +| node | Yes | Daemon and wallet service | +| wallet | Yes (no-std WIP) | wallet library for building spaces transactions| +| protocol | No | Protocol consensus library | ## Setup -First, download Bitcoin Core and set it up to connect to `regtest` +First, download Bitcoin Core and set it up to connect to `regtest` using these steps: ```bash @@ -34,5 +33,3 @@ Connect `spaced` to Bitcoin core ```bash spaced --chain regtest --bitcoin-rpc-user test --bitcoin-rpc-password test ``` - - diff --git a/node/Cargo.toml b/node/Cargo.toml index 08627f6..3b324a4 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -35,4 +35,9 @@ spacedb = { git = "https://github.com/spacesprotocol/spacedb", tag = "0.0.2" } base64 = "0.22.1" futures = "0.3.30" reqwest = { version = "0.12.5", features = ["json", "blocking"] } -threadpool = "1.8.1" \ No newline at end of file +threadpool = "1.8.1" + +[dev-dependencies] +assert_cmd = "2.0.16" +bitcoind = { version = "0.36.0", features = ["26_0"] } +predicates = "3.1.2" diff --git a/node/src/rpc.rs b/node/src/rpc.rs index 37a7d16..d58efb8 100644 --- a/node/src/rpc.rs +++ b/node/src/rpc.rs @@ -51,7 +51,7 @@ pub(crate) type Responder = oneshot::Sender; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ServerInfo { - chain: ExtendedNetwork, + pub chain: ExtendedNetwork, tip: ChainAnchor, } diff --git a/node/src/source.rs b/node/src/source.rs index 4a1f8d6..d52659e 100644 --- a/node/src/source.rs +++ b/node/src/source.rs @@ -732,52 +732,3 @@ impl BlockSource for BitcoinBlockSource { .send_json_blocking(&self.client, &self.rpc.get_block_count())?) } } - -#[cfg(test)] -mod test { - use protocol::{bitcoin::BlockHash, constants::ChainAnchor}; - - use crate::source::{BitcoinRpc, BitcoinRpcAuth, BlockEvent, BlockFetcher}; - - #[test] - fn test_fetcher() -> anyhow::Result<()> { - let rpc = BitcoinRpc::new( - "http://127.0.0.1:18332", - BitcoinRpcAuth::UserPass("test".to_string(), "test".to_string()), - ); - - let client = reqwest::blocking::Client::new(); - let count: u32 = rpc.send_json_blocking(&client, &rpc.get_block_count())?; - - let checkpoint = count - 10; - let start_block_hash: BlockHash = - rpc.send_json_blocking(&client, &rpc.get_block_hash(checkpoint))?; - - let (fetcher, receiver) = BlockFetcher::new(rpc, client, 8); - - println!("fetcher checkpoint block {}", checkpoint); - - fetcher.start(ChainAnchor { - hash: start_block_hash, - height: checkpoint, - }); - - println!("fetcher receiving blocks"); - while let Ok(event) = receiver.recv() { - match event { - BlockEvent::Block(id, _) => { - println!("got block {}", id.height); - if id.height >= count { - break; - } - } - BlockEvent::Error(e) => { - println!("error: {}", e.to_string()); - break; - } - } - } - - Ok(()) - } -} diff --git a/node/tests/fetcher_tests.rs b/node/tests/fetcher_tests.rs new file mode 100644 index 0000000..8952877 --- /dev/null +++ b/node/tests/fetcher_tests.rs @@ -0,0 +1,71 @@ +pub mod utils; + +#[cfg(test)] +mod tests { + use std::{ + sync::mpsc::TryRecvError, + time::{Duration, Instant}, + }; + + use crate::utils::SpaceD; + use anyhow::Result; + use bitcoind::bitcoincore_rpc::RpcApi; + use protocol::constants::ChainAnchor; + use reqwest::blocking::Client; + use spaced::source::{BitcoinRpc, BitcoinRpcAuth, BlockEvent, BlockFetcher}; + use wallet::bitcoin::Network; + + #[test] + fn test_block_fetching_from_bitcoin_rpc() -> Result<()> { + let spaced = SpaceD::new()?; + let fetcher_rpc = BitcoinRpc::new( + &spaced.bitcoind.rpc_url(), + BitcoinRpcAuth::UserPass("user".to_string(), "password".to_string()), + ); + let miner_addr = spaced + .bitcoind + .client + .get_new_address(None, None)? + .require_network(Network::Regtest)?; + const GENERATED_BLOCKS: u32 = 10; + spaced + .bitcoind + .client + .generate_to_address(GENERATED_BLOCKS as u64, &miner_addr)?; + + let client = Client::new(); + let (fetcher, receiver) = BlockFetcher::new(fetcher_rpc.clone(), client.clone(), 8); + fetcher.start(ChainAnchor { + hash: fetcher_rpc.send_json_blocking(&client, &fetcher_rpc.get_block_hash(0))?, + height: 0, + }); + + let mut start_block = 0; + let timeout = Duration::from_secs(5); + let start_time = Instant::now(); + + loop { + if start_time.elapsed() > timeout { + panic!("Test timed out after {:?}", timeout); + } + match receiver.try_recv() { + Ok(BlockEvent::Block(id, _)) => { + start_block += 1; + if id.height == GENERATED_BLOCKS { + break; + } + } + Ok(BlockEvent::Error(e)) => panic!("Unexpected error: {}", e), + Err(TryRecvError::Empty) => { + std::thread::sleep(Duration::from_millis(10)); + } + Err(TryRecvError::Disconnected) => panic!("Disconnected unexpectedly"), + } + } + assert_eq!( + start_block, GENERATED_BLOCKS, + "Not all blocks were received" + ); + Ok(()) + } +} diff --git a/node/tests/space_cli_tests.rs b/node/tests/space_cli_tests.rs new file mode 100644 index 0000000..aeb8d3f --- /dev/null +++ b/node/tests/space_cli_tests.rs @@ -0,0 +1,34 @@ +pub mod utils; + +#[cfg(test)] +mod tests { + use crate::utils::SpaceD; + use anyhow::Result; + use assert_cmd::prelude::*; + use predicates::prelude::*; + use serde_json::from_str; + use spaced::config::ExtendedNetwork; + use spaced::rpc::ServerInfo; + use std::process::Command; + + #[tokio::test] + async fn test_get_server_info() -> Result<()> { + env_logger::init(); + let spaced = SpaceD::new()?; + + Command::cargo_bin("space-cli")? + .arg("--chain") + .arg("regtest") + .arg("--spaced-rpc-url") + .arg(spaced.spaced_rpc_url()) + .arg("getserverinfo") + .assert() + .success() + .stdout(predicate::function(|x: &str| { + let info: ServerInfo = from_str(x).unwrap(); + return info.chain == ExtendedNetwork::Regtest; + })); + + Ok(()) + } +} diff --git a/node/tests/utils.rs b/node/tests/utils.rs new file mode 100644 index 0000000..183e5a6 --- /dev/null +++ b/node/tests/utils.rs @@ -0,0 +1,70 @@ +use anyhow::{anyhow, Result}; +use assert_cmd::cargo::CommandCargoExt; +use bitcoind::{get_available_port, tempfile::tempdir, BitcoinD, Conf}; +use log::{debug, error}; +use std::{ + net::Ipv4Addr, + process::{Child, Command}, + thread, + time::Duration, +}; + +#[derive(Debug)] +pub struct SpaceD { + pub bitcoind: BitcoinD, + process: Child, + rpc_port: u16, +} + +const LOCAL_IP: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); + +impl SpaceD { + pub fn new() -> Result { + let mut conf: Conf = Conf::default(); + // The RPC auth uses username "user" and password "password". If we + // don't set this, bitcoind's RPC API becomes inaccessible to spaced due + // to auth issues. + conf.args = vec!["-regtest", "-fallbackfee=0.0001", "-rpcauth=user:70dbb4f60ccc95e154da97a43b7a9d06$00c10a3849edf2f10173e80d0bdadbde793ad9a80e6e6f9f71f978fb5c797343"]; + let bitcoind = BitcoinD::from_downloaded_with_conf(&conf).unwrap(); + debug!("bitcoind running on port {}", bitcoind.rpc_url()); + let rpc_port = get_available_port()?; + let mut process = Command::cargo_bin("spaced")? + .arg("--chain") + .arg("regtest") + .arg("--bitcoin-rpc-url") + .arg(bitcoind.rpc_url()) + .arg("--bitcoin-rpc-user") + .arg("user") + .arg("--bitcoin-rpc-password") + .arg("password") + .arg("--block-index") + .arg("--data-dir") + .arg(tempdir()?.path()) + .arg("--rpc-port") + .arg(rpc_port.to_string()) + .spawn()?; + if let Some(_) = process.try_wait()? { + error!("spaced failed to obtain port {}", rpc_port); + return Err(anyhow!("port unavailable")); + } + thread::sleep(Duration::from_millis(100)); + assert!(process.stderr.is_none()); + debug!("spaced running on port {}", rpc_port); + Ok(Self { + bitcoind, + process, + rpc_port, + }) + } + + pub fn spaced_rpc_url(&self) -> String { + format!("http://{}:{}", LOCAL_IP, self.rpc_port) + } +} + +impl Drop for SpaceD { + fn drop(&mut self) { + debug!("killing spaced process"); + let _ = self.process.kill(); + } +}