diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a80d75c..b40a2f1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,44 +14,26 @@ jobs: test: runs-on: ${{ matrix.os }} env: - RUST_LOG: bitcoind=debug + RUST_LOG: tapyrusd=debug strategy: fail-fast: false matrix: os: [ubuntu-20.04] feature: [ - "25_1", - "25_0", - "24_0_1", - "23_1", - "22_1", - "0_21_2", - "0_20_2", - "0_19_1", - "0_18_1", - "0_17_1", + "0_5_2", + "0_5_1", ] - include: - - os: "macos-11" - feature: "25_1" - - os: "windows-2019" - feature: "25_1" - steps: - run: df -h - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.feature }}${{ matrix.os }} - if: ${{ matrix.os != 'macos-11' }} # issue with hard-links on mac - uses: dtolnay/rust-toolchain@stable - run: cargo test --features ${{ matrix.feature }} - - run: echo "BITCOIND_EXE=$(find ./target/debug -name bitcoind)" >> $GITHUB_ENV - if: ${{ matrix.os != 'windows-2019' }} + - run: echo "TAPYRUSD_EXE=$(find ./target/debug -name tapyrusd)" >> $GITHUB_ENV - run: cargo test - if: ${{ matrix.feature != '0_18_1' && matrix.feature != '0_17_1' && matrix.os != 'windows-2019' }} # would fail `test_multi_wallet` - cosmetics: runs-on: ubuntu-20.04 @@ -89,12 +71,12 @@ jobs: build-nix: runs-on: ubuntu-20.04 env: - FNAME: bitcoin-23.1-x86_64-linux-gnu.tar.gz + FNAME: tapyrus-core-0.5.2-x86_64-linux-gnu.tar.gz steps: - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 - uses: dtolnay/rust-toolchain@stable - - run: echo "BITCOIND_TARBALL_FILE=./${FNAME}" >> $GITHUB_ENV - - run: cargo build --features 23_1 && exit 1 || exit 0 - - run: wget -q https://bitcoincore.org/bin/bitcoin-core-23.1/${FNAME} - - run: cargo build --features 23_1 + - run: echo "TAPYRUSD_TARBALL_FILE=./${FNAME}" >> $GITHUB_ENV + - run: cargo build --features 0_5_2 && exit 1 || exit 0 + - run: wget https://github.com/chaintope/tapyrus-core/releases/download/v0.5.2/${FNAME} + - run: cargo build --features 0_5_2 diff --git a/Cargo.toml b/Cargo.toml index ef01c82..b5efec4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,17 @@ [package] -name = "bitcoind" -version = "0.36.0" +name = "tapyrusd" +version = "0.1.0" authors = ["Riccardo Casatta "] -description = "Utility to run a regtest bitcoind process, useful in integration testing environment" +description = "Utility to run a regtest tapyrusd process, useful in integration testing environment" license = "MIT" -repository = "https://github.com/RCasatta/bitcoind" -documentation = "https://docs.rs/bitcoind/" +repository = "https://github.com/chaintope/tapyrusd" +documentation = "https://docs.rs/tapyrusd/" rust-version = "1.56.1" edition = "2018" categories = ["cryptography::cryptocurrencies", "development-tools::testing"] [dependencies] -bitcoincore-rpc = { version = "0.19", features = ["rand"] } +tapyruscore-rpc = { git="https://github.com/chaintope/rust-tapyruscore-rpc", subdir = "client", features = ["rand"] } log = "0.4" which = "4.2.5" anyhow = "1.0.66" @@ -35,17 +35,9 @@ anyhow = "1.0.66" # download is not supposed to be used directly only through selecting one of the version feature "download" = ["bitcoin_hashes", "flate2", "tar", "minreq", "zip"] -"26_0" = ["download", "25_1"] -"25_1" = ["download", "25_0"] -"25_0" = ["download", "24_0_1"] -"24_0_1" = ["download", "23_1"] -"23_1" = ["download", "22_1"] -"22_1" = ["download", "0_21_2"] -"0_21_2" = ["download", "0_20_2"] -"0_20_2" = ["download", "0_19_1"] -"0_19_1" = ["download", "0_18_1"] -"0_18_1" = ["download", "0_17_1"] -"0_17_1" = ["download"] +"0_5_2" = ["download", "0_5_1"] +"0_5_1" = ["download"] + "doc" = [] # used only for documentation building diff --git a/README.md b/README.md index 9cc138e..35abcf6 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ [![Crates](https://img.shields.io/crates/v/bitcoind.svg)](https://crates.io/crates/bitcoind) [![Docs](https://img.shields.io/badge/docs.rs-bitcoind-green)](https://docs.rs/bitcoind) -# Bitcoind +# Tapyrusd -Utility to run a regtest bitcoind process, useful in integration testing environment. +Utility to run a regtest tapyrusd process, useful in integration testing environment. When the auto-download feature is selected by activating one of the version feature, such as `25_1` for bitcoin core 25.1, starting a regtest node is as simple as that: @@ -13,31 +13,31 @@ for bitcoin core 25.1, starting a regtest node is as simple as that: // the download feature is enabled whenever a specific version is enabled, for example `25_1` or `24_0_1` #[cfg(feature = "download")] { - use bitcoincore_rpc::RpcApi; - let bitcoind = bitcoind::BitcoinD::from_downloaded().unwrap(); - assert_eq!(0, bitcoind.client.get_blockchain_info().unwrap().blocks); + use tapyruscore_rpc::RpcApi; + let tapyrusd = tapyrusd::TapyrusD::from_downloaded().unwrap(); + assert_eq!(0, tapyrusd.client.get_blockchain_info().unwrap().blocks); } ``` The build script will automatically download the bitcoin core version 25.1 from [bitcoin core](https://bitcoincore.org), verify the hashes and place it in the build directory for this crate. If you wish to download from an -alternate location, for example locally for CI, use the `BITCOIND_DOWNLOAD_ENDPOINT` env var. +alternate location, for example locally for CI, use the `TAPYRUSD_DOWNLOAD_ENDPOINT` env var. When you don't use the auto-download feature you have the following options: -* have `bitcoind` executable in the `PATH` -* provide the `bitcoind` executable via the `BITCOIND_EXE` env var +* have `tapyrusd` executable in the `PATH` +* provide the `tapyrusd` executable via the `TAPYRUSD_EXE` env var ```rust -use bitcoincore_rpc::RpcApi; -if let Ok(exe_path) = bitcoind::exe_path() { - let bitcoind = bitcoind::BitcoinD::new(exe_path).unwrap(); +use tapyruscore_rpc::RpcApi; +if let Ok(exe_path) = tapyrusd::exe_path() { + let bitcoind = tapyrusd::TapyrusD::new(exe_path).unwrap(); assert_eq!(0, bitcoind.client.get_blockchain_info().unwrap().blocks); } ``` -Startup options could be configured via the [`Conf`] struct using [`BitcoinD::with_conf`] or -[`BitcoinD::from_downloaded_with_conf`] +Startup options could be configured via the [`Conf`] struct using [`TapyrusD::with_conf`] or +[`TapyrusD::from_downloaded_with_conf`] ## Issues with traditional approach diff --git a/build.rs b/build.rs index 7db3cb5..df9307d 100644 --- a/build.rs +++ b/build.rs @@ -23,36 +23,18 @@ mod download { include!("src/versions.rs"); - #[cfg(all( - target_os = "macos", - any(target_arch = "x86_64", target_arch = "aarch64"), - ))] - fn download_filename() -> String { - if cfg!(not(feature = "23_1")) { - format!("bitcoin-{}-osx64.tar.gz", &VERSION) - } else { - format!("bitcoin-{}-x86_64-apple-darwin.tar.gz", &VERSION) - } - } - #[cfg(all(target_os = "linux", target_arch = "x86_64"))] fn download_filename() -> String { - format!("bitcoin-{}-x86_64-linux-gnu.tar.gz", &VERSION) + format!("tapyrus-core-{}-x86_64-linux-gnu.tar.gz", &VERSION) } #[cfg(all(target_os = "linux", target_arch = "aarch64"))] fn download_filename() -> String { - format!("bitcoin-{}-aarch64-linux-gnu.tar.gz", &VERSION) - } - - #[cfg(all(target_os = "windows", target_arch = "x86_64"))] - fn download_filename() -> String { - format!("bitcoin-{}-win64.zip", &VERSION) + format!("tapyrus-core-{}-aarch64-linux-gnu.tar.gz", &VERSION) } fn get_expected_sha256(filename: &str) -> anyhow::Result { - let sha256sums_filename = format!("sha256/bitcoin-core-{}-SHA256SUMS", &VERSION); - #[cfg(not(feature = "22_1"))] + let sha256sums_filename = format!("sha256/tapyrus-core-{}-SHA256SUMS", &VERSION); let sha256sums_filename = format!("{}.asc", sha256sums_filename); let file = File::open(&sha256sums_filename) .with_context(|| format!("cannot find {:?}", sha256sums_filename))?; @@ -71,38 +53,33 @@ mod download { } pub(crate) fn start() -> anyhow::Result<()> { - if std::env::var_os("BITCOIND_SKIP_DOWNLOAD").is_some() { + if std::env::var_os("TAPYRUSD_SKIP_DOWNLOAD").is_some() { return Ok(()); } let download_filename = download_filename(); - let expected_hash = get_expected_sha256(&download_filename)?; + // let expected_hash = get_expected_sha256(&download_filename)?; let out_dir = std::env::var_os("OUT_DIR").unwrap(); - let mut bitcoin_exe_home = Path::new(&out_dir).join("bitcoin"); - if !bitcoin_exe_home.exists() { - std::fs::create_dir(&bitcoin_exe_home) - .with_context(|| format!("cannot create dir {:?}", bitcoin_exe_home))?; + let mut tapyrus_exe_home = Path::new(&out_dir).join("tapyrus"); + if !tapyrus_exe_home.exists() { + std::fs::create_dir(&tapyrus_exe_home) + .with_context(|| format!("cannot create dir {:?}", tapyrus_exe_home))?; } - let existing_filename = bitcoin_exe_home - .join(format!("bitcoin-{}", VERSION)) + let existing_filename = tapyrus_exe_home + .join(format!("tapyrus-{}", VERSION)) .join("bin") - .join("bitcoind"); + .join("tapyrusd"); if !existing_filename.exists() { - println!( - "filename:{} version:{} hash:{}", - download_filename, VERSION, expected_hash - ); + println!("filename:{} version:{}", download_filename, VERSION); - let (file_or_url, tarball_bytes) = match std::env::var("BITCOIND_TARBALL_FILE") { + let (file_or_url, tarball_bytes) = match std::env::var("TAPYRUSD_TARBALL_FILE") { Err(_) => { - let download_endpoint = std::env::var("BITCOIND_DOWNLOAD_ENDPOINT") - .unwrap_or("https://bitcoincore.org/bin".to_owned()); - - let url = format!( - "{}/bitcoin-core-{}/{}", - download_endpoint, VERSION, download_filename + let download_endpoint = std::env::var("TAPYRUSD_DOWNLOAD_ENDPOINT").unwrap_or( + "https://github.com/chaintope/tapyrus-core/releases/download".to_owned(), ); + + let url = format!("{}/v{}/{}", download_endpoint, VERSION, download_filename); let resp = minreq::get(&url) .send() .with_context(|| format!("cannot reach url {}", url))?; @@ -113,7 +90,7 @@ mod download { Ok(path) => { let f = File::open(&path).with_context(|| { format!( - "Cannot find {:?} specified with env var BITCOIND_TARBALL_FILE", + "Cannot find {:?} specified with env var TAPYRUSD_TARBALL_FILE", &path ) })?; @@ -125,11 +102,11 @@ mod download { }; let tarball_hash = sha256::Hash::hash(&tarball_bytes); - assert_eq!( - expected_hash, tarball_hash, - "expected hash of {} is not matching", - file_or_url - ); + // assert_eq!( + // expected_hash, tarball_hash, + // "expected hash of {} is not matching", + // file_or_url + // ); if download_filename.ends_with(".tar.gz") { let d = GzDecoder::new(&tarball_bytes[..]); @@ -137,8 +114,8 @@ mod download { let mut archive = Archive::new(d); for mut entry in archive.entries().unwrap().flatten() { if let Ok(file) = entry.path() { - if file.ends_with("bitcoind") { - entry.unpack_in(&bitcoin_exe_home).unwrap(); + if file.ends_with("tapyrusd") { + entry.unpack_in(&tapyrus_exe_home).unwrap(); } } } @@ -152,16 +129,16 @@ mod download { None => continue, }; - if outpath.file_name().map(|s| s.to_str()) == Some(Some("bitcoind.exe")) { + if outpath.file_name().map(|s| s.to_str()) == Some(Some("tapyrusd.exe")) { for d in outpath.iter() { - bitcoin_exe_home.push(d); + tapyrus_exe_home.push(d); } - let parent = bitcoin_exe_home.parent().unwrap(); + let parent = tapyrus_exe_home.parent().unwrap(); std::fs::create_dir_all(&parent) .with_context(|| format!("cannot create dir {:?}", parent))?; let mut outfile = - std::fs::File::create(&bitcoin_exe_home).with_context(|| { - format!("cannot create file {:?}", bitcoin_exe_home) + std::fs::File::create(&tapyrus_exe_home).with_context(|| { + format!("cannot create file {:?}", tapyrus_exe_home) })?; io::copy(&mut file, &mut outfile).unwrap(); break; diff --git a/src/lib.rs b/src/lib.rs index fe075cb..fba823f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,29 +3,31 @@ mod versions; -use crate::bitcoincore_rpc::jsonrpc::serde_json::Value; +use crate::tapyruscore_rpc::jsonrpc::serde_json::Value; use anyhow::Context; -use bitcoincore_rpc::{Auth, Client, RpcApi}; use log::{debug, error, warn}; use std::ffi::OsStr; +use std::fs::File; +use std::io::Write; use std::net::{Ipv4Addr, SocketAddrV4, TcpListener}; use std::path::PathBuf; use std::process::{Child, Command, ExitStatus, Stdio}; use std::time::Duration; use std::{env, fmt, fs, thread}; +use tapyruscore_rpc::{Auth, Client, RpcApi}; use tempfile::TempDir; pub use anyhow; -pub use bitcoincore_rpc; +pub use tapyruscore_rpc; pub use tempfile; pub use which; #[derive(Debug)] -/// Struct representing the bitcoind process with related information -pub struct BitcoinD { +/// Struct representing the tapyrusd process with related information +pub struct TapyrusD { /// Process child handle, used to terminate the process when this struct is dropped process: Child, - /// Rpc client linked to this bitcoind process + /// Rpc client linked to this tapyrusd process pub client: Client, /// Work directory, where the node store blocks and other stuff. work_dir: DataDir, @@ -98,7 +100,7 @@ pub enum P2P { /// the node open a p2p port Yes, /// The node open a p2p port and also connects to the url given as parameter, it's handy to - /// initialize this with [BitcoinD::p2p_connect] of another node. The `bool` parameter indicates + /// initialize this with [TapyrusD::p2p_connect] of another node. The `bool` parameter indicates /// if the node can accept connection too. Connect(SocketAddrV4, bool), } @@ -107,15 +109,15 @@ pub enum P2P { pub enum Error { /// Wrapper of io Error Io(std::io::Error), - /// Wrapper of bitcoincore_rpc Error - Rpc(bitcoincore_rpc::Error), + /// Wrapper of tapyruscore_rpc Error + Rpc(tapyruscore_rpc::Error), /// Returned when calling methods requiring a feature to be activated, but it's not NoFeature, /// Returned when calling methods requiring a env var to exist, but it's not NoEnvVar, - /// Returned when calling methods requiring the bitcoind executable but none is found - /// (no feature, no `BITCOIND_EXE`, no `bitcoind` in `PATH` ) - NoBitcoindExecutableFound, + /// Returned when calling methods requiring the tapyrusd executable but none is found + /// (no feature, no `TAPYRUSD_EXE`, no `tapyrusd` in `PATH` ) + NoTapyrusdExecutableFound, /// Wrapper of early exit status EarlyExit(ExitStatus), /// Returned when both tmpdir and staticdir is specified in `Conf` options @@ -123,7 +125,7 @@ pub enum Error { /// Returned when -rpcuser and/or -rpcpassword is used in `Conf` args /// It will soon be deprecated, please use -rpcauth instead RpcUserAndPasswordUsed, - /// Returned when expecting an auto-downloaded executable but `BITCOIND_SKIP_DOWNLOAD` env var is set + /// Returned when expecting an auto-downloaded executable but `TAPYRUSD_SKIP_DOWNLOAD` env var is set SkipDownload, } @@ -131,14 +133,14 @@ impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::Io(_) => write!(f, "io::Error"), - Error::Rpc(_) => write!(f, "bitcoin_rpc::Error"), + Error::Rpc(_) => write!(f, "tapyrus_rpc::Error"), Error::NoFeature => write!(f, "Called a method requiring a feature to be set, but it's not"), - Error::NoEnvVar => write!(f, "Called a method requiring env var `BITCOIND_EXE` to be set, but it's not"), - Error::NoBitcoindExecutableFound => write!(f, "`bitcoind` executable is required, provide it with one of the following: set env var `BITCOIND_EXE` or use a feature like \"22_1\" or have `bitcoind` executable in the `PATH`"), - Error::EarlyExit(e) => write!(f, "The bitcoind process terminated early with exit code {}", e), + Error::NoEnvVar => write!(f, "Called a method requiring env var `TAPYRUSD_EXE` to be set, but it's not"), + Error::NoTapyrusdExecutableFound => write!(f, "`tapyrusd` executable is required, provide it with one of the following: set env var `TAPYRUSD_EXE` or use a feature like \"22_1\" or have `tapyrusd` executable in the `PATH`"), + Error::EarlyExit(e) => write!(f, "The tapyrusd process terminated early with exit code {}", e), Error::BothDirsSpecified => write!(f, "tempdir and staticdir cannot be enabled at same time in configuration options"), Error::RpcUserAndPasswordUsed => write!(f, "`-rpcuser` and `-rpcpassword` cannot be used, it will be deprecated soon and it's recommended to use `-rpcauth` instead which works alongside with the default cookie authentication"), - Error::SkipDownload => write!(f, "expecting an auto-downloaded executable but `BITCOIND_SKIP_DOWNLOAD` env var is set"), + Error::SkipDownload => write!(f, "expecting an auto-downloaded executable but `TAPYRUSD_SKIP_DOWNLOAD` env var is set"), } } } @@ -171,26 +173,26 @@ const INVALID_ARGS: [&str; 2] = ["-rpcuser", "-rpcpassword"]; /// /// Default values: /// ``` -/// let mut conf = bitcoind::Conf::default(); -/// conf.args = vec!["-regtest", "-fallbackfee=0.0001"]; +/// let mut conf = tapyrusd::Conf::default(); +/// conf.args = vec!["-dev".to_string(), "-fallbackfee=0.0001".to_string(), "-networkid=1905960821".to_string()]; /// conf.view_stdout = false; -/// conf.p2p = bitcoind::P2P::No; -/// conf.network = "regtest"; +/// conf.p2p = tapyrusd::P2P::No; +/// conf.network = "dev"; /// conf.tmpdir = None; /// conf.staticdir = None; /// conf.attempts = 3; -/// assert_eq!(conf, bitcoind::Conf::default()); +/// assert_eq!(conf, tapyrusd::Conf::default()); /// ``` /// #[non_exhaustive] #[derive(Debug, PartialEq, Eq, Clone)] pub struct Conf<'a> { - /// Bitcoind command line arguments containing no spaces like `vec!["-dbcache=300", "-regtest"]` + /// Tapyrusd command line arguments containing no spaces like `vec!["-dbcache=300", "-dev"]` /// note that `port`, `rpcport`, `connect`, `datadir`, `listen` /// cannot be used because they are automatically initialized. - pub args: Vec<&'a str>, + pub args: Vec, - /// if `true` bitcoind log output will not be suppressed + /// if `true` tapyrusd log output will not be suppressed pub view_stdout: bool, /// Allows to specify options to open p2p port or connect to the another node @@ -231,11 +233,18 @@ pub struct Conf<'a> { impl Default for Conf<'_> { fn default() -> Self { + let networkid_arg = format!("-networkid={}", get_network_id()); + let args = vec![ + "-dev".to_owned(), + "-fallbackfee=0.0001".to_owned(), + networkid_arg, + ]; + Conf { - args: vec!["-regtest", "-fallbackfee=0.0001"], + args, view_stdout: false, p2p: P2P::No, - network: "regtest", + network: "dev", tmpdir: None, staticdir: None, attempts: 3, @@ -244,16 +253,24 @@ impl Default for Conf<'_> { } } -impl BitcoinD { - /// Launch the bitcoind process from the given `exe` executable with default args. +fn get_network_id() -> String { + std::env::var("NETWORK_ID").expect("NETWORK_ID must be set") +} + +fn get_genesis_block() -> String { + std::env::var("GENESIS_BLOCK").expect("GENESIS_BLOCK must be set") +} + +impl TapyrusD { + /// Launch the tapyrusd process from the given `exe` executable with default args. /// /// Waits for the node to be ready to accept connections before returning - pub fn new>(exe: S) -> anyhow::Result { - BitcoinD::with_conf(exe, &Conf::default()) + pub fn new>(exe: S) -> anyhow::Result { + TapyrusD::with_conf(exe, &Conf::default()) } - /// Launch the bitcoind process from the given `exe` executable with given [Conf] param - pub fn with_conf>(exe: S, conf: &Conf) -> anyhow::Result { + /// Launch the tapyrusd process from the given `exe` executable with given [Conf] param + pub fn with_conf>(exe: S, conf: &Conf) -> anyhow::Result { let tmpdir = conf .tmpdir .clone() @@ -270,7 +287,9 @@ impl BitcoinD { let work_dir_path = work_dir.path(); debug!("work_dir: {:?}", work_dir_path); - let cookie_file = work_dir_path.join(conf.network).join(".cookie"); + let cookie_file = work_dir_path + .join(format!("{}-{}", conf.network, get_network_id())) + .join(".cookie"); let rpc_port = get_available_port()?; let rpc_socket = SocketAddrV4::new(LOCAL_IP, rpc_port); let rpc_url = format!("http://{}", rpc_socket); @@ -325,7 +344,7 @@ impl BitcoinD { let default_args = [&datadir_arg, &rpc_arg]; let conf_args = validate_args(conf.args.clone())?; - debug!( + println!( "launching {:?} with args: {:?} {:?} AND custom args: {:?}", exe.as_ref(), default_args, @@ -333,6 +352,16 @@ impl BitcoinD { conf_args ); + File::create(format!( + "{}/genesis.{}", + work_dir_path.display(), + get_network_id() + )) + .and_then(|mut f| { + let genesis_block = get_genesis_block(); + f.write_all(genesis_block.as_bytes()) + })?; + let mut process = Command::new(exe.as_ref()) .args(default_args) .args(&p2p_args) @@ -344,7 +373,7 @@ impl BitcoinD { let node_url_default = format!("{}/wallet/default", rpc_url); let mut i = 0; - // wait bitcoind is ready, use default wallet + // wait tapyrusd is ready, use default wallet let client = loop { if let Some(status) = process.try_wait()? { if conf.attempts > 0 { @@ -380,7 +409,7 @@ impl BitcoinD { } debug!( - "bitcoin client for process {} not ready ({})", + "tapyrus client for process {} not ready ({})", process.id(), i ); @@ -388,7 +417,7 @@ impl BitcoinD { i += 1; }; - Ok(BitcoinD { + Ok(TapyrusD { process, client, work_dir, @@ -407,7 +436,7 @@ impl BitcoinD { format!("http://{}", self.params.rpc_socket) } - #[cfg(any(feature = "0_19_1", not(feature = "download")))] + #[cfg(not(feature = "download"))] /// Returns the rpc URL including the schema and the given `wallet_name` /// eg. http://127.0.0.1:44842/wallet/my_wallet pub fn rpc_url_with_wallet>(&self, wallet_name: T) -> String { @@ -434,7 +463,7 @@ impl BitcoinD { Ok(self.process.wait()?) } - #[cfg(any(feature = "0_19_1", not(feature = "download")))] + #[cfg(not(feature = "download"))] /// Create a new wallet in the running node, and return an RPC client connected to the just /// created wallet pub fn create_wallet>(&self, wallet: T) -> anyhow::Result { @@ -449,18 +478,18 @@ impl BitcoinD { } #[cfg(feature = "download")] -impl BitcoinD { - /// create BitcoinD struct with the downloaded executable. - pub fn from_downloaded() -> anyhow::Result { - BitcoinD::new(downloaded_exe_path()?) +impl TapyrusD { + /// create TapyrusD struct with the downloaded executable. + pub fn from_downloaded() -> anyhow::Result { + TapyrusD::new(downloaded_exe_path()?) } - /// create BitcoinD struct with the downloaded executable and given Conf. - pub fn from_downloaded_with_conf(conf: &Conf) -> anyhow::Result { - BitcoinD::with_conf(downloaded_exe_path()?, conf) + /// create TapyrusD struct with the downloaded executable and given Conf. + pub fn from_downloaded_with_conf(conf: &Conf) -> anyhow::Result { + TapyrusD::with_conf(downloaded_exe_path()?, conf) } } -impl Drop for BitcoinD { +impl Drop for TapyrusD { fn drop(&mut self) { if let DataDir::Persistent(_) = self.work_dir { let _ = self.stop(); @@ -484,59 +513,59 @@ impl From for Error { } } -impl From for Error { - fn from(e: bitcoincore_rpc::Error) -> Self { +impl From for Error { + fn from(e: tapyruscore_rpc::Error) -> Self { Error::Rpc(e) } } -/// Provide the bitcoind executable path if a version feature has been specified +/// Provide the tapyrusd executable path if a version feature has been specified #[cfg(not(feature = "download"))] pub fn downloaded_exe_path() -> anyhow::Result { Err(Error::NoFeature.into()) } -/// Provide the bitcoind executable path if a version feature has been specified +/// Provide the tapyrusd executable path if a version feature has been specified #[cfg(feature = "download")] pub fn downloaded_exe_path() -> anyhow::Result { - if std::env::var_os("BITCOIND_SKIP_DOWNLOAD").is_some() { + if std::env::var_os("TAPYRUSD_SKIP_DOWNLOAD").is_some() { return Err(Error::SkipDownload.into()); } let mut path: PathBuf = env!("OUT_DIR").into(); - path.push("bitcoin"); - path.push(format!("bitcoin-{}", versions::VERSION)); + path.push("tapyrus"); + path.push(format!("tapyrus-core-{}", versions::VERSION)); path.push("bin"); if cfg!(target_os = "windows") { - path.push("bitcoind.exe"); + path.push("tapyrusd.exe"); } else { - path.push("bitcoind"); + path.push("tapyrusd"); } Ok(format!("{}", path.display())) } -/// Returns the daemon `bitcoind` executable with the following precedence: +/// Returns the daemon `tapyrusd` executable with the following precedence: /// -/// 1) If it's specified in the `BITCOIND_EXE` env var +/// 1) If it's specified in the `TAPYRUSD_EXE` env var /// 2) If there is no env var but an auto-download feature such as `23_1` is enabled, returns the /// path of the downloaded executabled -/// 3) If neither of the precedent are available, the `bitcoind` executable is searched in the `PATH` +/// 3) If neither of the precedent are available, the `tapyrusd` executable is searched in the `PATH` pub fn exe_path() -> anyhow::Result { - if let Ok(path) = std::env::var("BITCOIND_EXE") { + if let Ok(path) = std::env::var("TAPYRUSD_EXE") { return Ok(path); } if let Ok(path) = downloaded_exe_path() { return Ok(path); } - which::which("bitcoind") - .map_err(|_| Error::NoBitcoindExecutableFound.into()) + which::which("tapyrusd") + .map_err(|_| Error::NoTapyrusdExecutableFound.into()) .map(|p| p.display().to_string()) } /// Validate the specified arg if there is any unavailable or deprecated one -pub fn validate_args(args: Vec<&str>) -> anyhow::Result> { +pub fn validate_args(args: Vec) -> anyhow::Result> { args.iter().try_for_each(|arg| { // other kind of invalid arguments can be added into the list if needed if INVALID_ARGS.iter().any(|x| arg.starts_with(x)) { @@ -550,14 +579,18 @@ pub fn validate_args(args: Vec<&str>) -> anyhow::Result> { #[cfg(test)] mod test { - use crate::bitcoincore_rpc::jsonrpc::serde_json::Value; - use crate::bitcoincore_rpc::{Auth, Client}; use crate::exe_path; - use crate::{get_available_port, BitcoinD, Conf, LOCAL_IP, P2P}; - use bitcoincore_rpc::RpcApi; + use crate::tapyruscore_rpc::jsonrpc::serde_json::Value; + use crate::tapyruscore_rpc::{Auth, Client}; + use crate::{get_available_port, Conf, TapyrusD, LOCAL_IP, P2P}; use std::net::SocketAddrV4; + use tapyruscore_rpc::RpcApi; use tempfile::TempDir; + fn get_private_key() -> String { + std::env::var("PRIVATE_KEY").expect("PRIVATE_KEY must be set") + } + #[test] fn test_local_ip() { assert_eq!("127.0.0.1", format!("{}", LOCAL_IP)); @@ -567,36 +600,35 @@ mod test { } #[test] - fn test_bitcoind() { + fn test_tapyrusd() { let exe = init(); - let bitcoind = BitcoinD::new(exe).unwrap(); - let info = bitcoind.client.get_blockchain_info().unwrap(); + let tapyrusd = TapyrusD::new(exe).unwrap(); + let info = tapyrusd.client.get_blockchain_info().unwrap(); assert_eq!(0, info.blocks); - let address = bitcoind + let address = tapyrusd .client - .get_new_address(None, None) + .get_new_address(None) .unwrap() .assume_checked(); - let _ = bitcoind.client.generate_to_address(1, &address).unwrap(); - let info = bitcoind.client.get_blockchain_info().unwrap(); + let _ = tapyrusd + .client + .generate_to_address(1, &address, get_private_key()) + .unwrap(); + let info = tapyrusd.client.get_blockchain_info().unwrap(); assert_eq!(1, info.blocks); } #[test] - #[cfg(feature = "0_21_2")] + #[ignore] fn test_getindexinfo() { let exe = init(); let mut conf = Conf::default(); - conf.args.push("-txindex"); - let bitcoind = BitcoinD::with_conf(&exe, &conf).unwrap(); - assert!( - bitcoind.client.version().unwrap() >= 210_000, - "getindexinfo requires bitcoin >0.21" - ); - let info: std::collections::HashMap = - bitcoind.client.call("getindexinfo", &[]).unwrap(); + conf.args.push("-txindex".to_owned()); + let tapyrusd = TapyrusD::with_conf(&exe, &conf).unwrap(); + let info: std::collections::HashMap = + tapyrusd.client.call("getindexinfo", &[]).unwrap(); assert!(info.contains_key("txindex")); - assert!(bitcoind.client.version().unwrap() >= 210_000); + assert!(tapyrusd.client.version().unwrap() >= 210_000); } #[test] @@ -605,14 +637,14 @@ mod test { let mut conf = Conf::default(); conf.p2p = P2P::Yes; - let bitcoind = BitcoinD::with_conf(&exe, &conf).unwrap(); - assert_eq!(peers_connected(&bitcoind.client), 0); + let tapyrusd = TapyrusD::with_conf(&exe, &conf).unwrap(); + assert_eq!(peers_connected(&tapyrusd.client), 0); let mut other_conf = Conf::default(); - other_conf.p2p = bitcoind.p2p_connect(false).unwrap(); + other_conf.p2p = tapyrusd.p2p_connect(false).unwrap(); - let other_bitcoind = BitcoinD::with_conf(&exe, &other_conf).unwrap(); - assert_eq!(peers_connected(&bitcoind.client), 1); - assert_eq!(peers_connected(&other_bitcoind.client), 1); + let other_tapyrusd = TapyrusD::with_conf(&exe, &other_conf).unwrap(); + assert_eq!(peers_connected(&tapyrusd.client), 1); + assert_eq!(peers_connected(&other_tapyrusd.client), 1); } #[cfg(not(target_os = "windows"))] // TODO: investigate why it doesn't work in windows @@ -623,29 +655,28 @@ mod test { let datadir = TempDir::new().unwrap(); conf.staticdir = Some(datadir.path().to_path_buf()); - // Start BitcoinD with persistent db config + // Start TapyrusD with persistent db config // Generate 101 blocks // Wallet balance should be 50 - let bitcoind = BitcoinD::with_conf(exe_path().unwrap(), &conf).unwrap(); - let core_addrs = bitcoind + let tapyrusd = TapyrusD::with_conf(exe_path().unwrap(), &conf).unwrap(); + let core_addrs = tapyrusd .client - .get_new_address(None, None) + .get_new_address(None) .unwrap() .assume_checked(); - bitcoind + tapyrusd .client - .generate_to_address(101, &core_addrs) + .generate_to_address(101, &core_addrs, get_private_key()) .unwrap(); - let wallet_balance_1 = bitcoind.client.get_balance(None, None).unwrap(); - let best_block_1 = bitcoind.client.get_best_block_hash().unwrap(); + let wallet_balance_1 = tapyrusd.client.get_balance(None).unwrap(); + let best_block_1 = tapyrusd.client.get_best_block_hash().unwrap(); + drop(tapyrusd); - drop(bitcoind); + // Start a new TapyrusD with the same datadir + let tapyrusd = TapyrusD::with_conf(exe_path().unwrap(), &conf).unwrap(); - // Start a new BitcoinD with the same datadir - let bitcoind = BitcoinD::with_conf(exe_path().unwrap(), &conf).unwrap(); - - let wallet_balance_2 = bitcoind.client.get_balance(None, None).unwrap(); - let best_block_2 = bitcoind.client.get_best_block_hash().unwrap(); + let wallet_balance_2 = tapyrusd.client.get_balance(None).unwrap(); + let best_block_2 = tapyrusd.client.get_best_block_hash().unwrap(); // Check node chain data persists assert_eq!(best_block_1, best_block_2); @@ -659,17 +690,17 @@ mod test { let _ = env_logger::try_init(); let mut conf_node1 = Conf::default(); conf_node1.p2p = P2P::Yes; - let node1 = BitcoinD::with_conf(exe_path().unwrap(), &conf_node1).unwrap(); + let node1 = TapyrusD::with_conf(exe_path().unwrap(), &conf_node1).unwrap(); // Create Node 2 connected Node 1 let mut conf_node2 = Conf::default(); conf_node2.p2p = node1.p2p_connect(true).unwrap(); - let node2 = BitcoinD::with_conf(exe_path().unwrap(), &conf_node2).unwrap(); + let node2 = TapyrusD::with_conf(exe_path().unwrap(), &conf_node2).unwrap(); // Create Node 3 Connected To Node let mut conf_node3 = Conf::default(); conf_node3.p2p = node2.p2p_connect(false).unwrap(); - let node3 = BitcoinD::with_conf(exe_path().unwrap(), &conf_node3).unwrap(); + let node3 = TapyrusD::with_conf(exe_path().unwrap(), &conf_node3).unwrap(); // Get each nodes Peers let node1_peers = peers_connected(&node1.client); @@ -682,40 +713,40 @@ mod test { assert_eq!(node3_peers, 1, "listen false but more than 1 peer"); } - #[cfg(any(feature = "0_19_1", not(feature = "download")))] + #[cfg(not(feature = "download"))] #[test] fn test_multi_wallet() { - use bitcoincore_rpc::bitcoin::Amount; - let exe = init(); - let bitcoind = BitcoinD::new(exe).unwrap(); - let alice = bitcoind.create_wallet("alice").unwrap(); - let alice_address = alice.get_new_address(None, None).unwrap().assume_checked(); - let bob = bitcoind.create_wallet("bob").unwrap(); - let bob_address = bob.get_new_address(None, None).unwrap().assume_checked(); - bitcoind + use tapyruscore_rpc::tapyrus::Amount; + let exe: String = init(); + let tapyrusd = TapyrusD::new(exe).unwrap(); + let alice = tapyrusd.create_wallet("alice").unwrap(); + let alice_address = alice.get_new_address(None).unwrap().assume_checked(); + let bob = tapyrusd.create_wallet("bob").unwrap(); + let bob_address = bob.get_new_address(None).unwrap().assume_checked(); + tapyrusd .client - .generate_to_address(1, &alice_address) + .generate_to_address(1, &alice_address, get_private_key()) .unwrap(); - bitcoind + tapyrusd .client - .generate_to_address(101, &bob_address) + .generate_to_address(101, &bob_address, get_private_key()) .unwrap(); assert_eq!( - Amount::from_btc(50.0).unwrap(), + Amount::from_tpc(50.0).unwrap(), alice.get_balances().unwrap().mine.trusted ); assert_eq!( - Amount::from_btc(50.0).unwrap(), + Amount::from_tpc(50.0).unwrap(), bob.get_balances().unwrap().mine.trusted ); assert_eq!( - Amount::from_btc(5000.0).unwrap(), + Amount::from_tpc(5000.0).unwrap(), bob.get_balances().unwrap().mine.immature ); let _txid = alice .send_to_address( &bob_address, - Amount::from_btc(1.0).unwrap(), + Amount::from_tpc(1.0).unwrap(), None, None, None, @@ -725,81 +756,83 @@ mod test { ) .unwrap(); assert!( - alice.get_balances().unwrap().mine.trusted < Amount::from_btc(49.0).unwrap() - && alice.get_balances().unwrap().mine.trusted > Amount::from_btc(48.9).unwrap() + alice.get_balances().unwrap().mine.trusted < Amount::from_tpc(49.0).unwrap() + && alice.get_balances().unwrap().mine.trusted > Amount::from_tpc(48.9).unwrap() ); // bob wallet may not be immediately updated for _ in 0..30 { - if bob.get_balances().unwrap().mine.untrusted_pending.to_sat() > 0 { + if bob.get_balances().unwrap().mine.untrusted_pending.to_tap() > 0 { break; } std::thread::sleep(std::time::Duration::from_millis(100)); } assert_eq!( - Amount::from_btc(1.0).unwrap(), + Amount::from_tpc(1.0).unwrap(), bob.get_balances().unwrap().mine.untrusted_pending ); assert!( - bitcoind.create_wallet("bob").is_err(), + tapyrusd.create_wallet("bob").is_err(), "wallet already exist" ); } #[test] - fn test_bitcoind_rpcuser_and_rpcpassword() { + fn test_tapyrusd_rpcuser_and_rpcpassword() { let exe = init(); let mut conf = Conf::default(); - conf.args.push("-rpcuser=bitcoind"); - conf.args.push("-rpcpassword=bitcoind"); + conf.args.push("-rpcuser=tapyrusd".to_owned()); + conf.args.push("-rpcpassword=tapyrusd".to_owned()); - let bitcoind = BitcoinD::with_conf(exe, &conf); + let tapyrusd = TapyrusD::with_conf(exe, &conf); - assert!(bitcoind.is_err()); + assert!(tapyrusd.is_err()); } #[test] - fn test_bitcoind_rpcauth() { + fn test_tapyrusd_rpcauth() { let exe = init(); let mut conf = Conf::default(); // rpcauth generated with [rpcauth.py](https://github.com/bitcoin/bitcoin/blob/master/share/rpcauth/rpcauth.py) // this could be also added to bitcoind, example: [RpcAuth](https://github.com/testcontainers/testcontainers-rs/blob/dev/testcontainers/src/images/coblox_bitcoincore.rs#L39-L91) - conf.args.push("-rpcauth=bitcoind:cccd5d7fd36e55c1b8576b8077dc1b83$60b5676a09f8518dcb4574838fb86f37700cd690d99bd2fdc2ea2bf2ab80ead6"); + conf.args.push("-rpcauth=tapyrusd:8898c01e60d6c157657d54cced2e8552$b74ce37cfb980b95c96b79ee659f658969d574865b909a77327bc584e6991211".to_owned()); - let bitcoind = BitcoinD::with_conf(exe, &conf).unwrap(); + let tapyrusd = TapyrusD::with_conf(exe, &conf).unwrap(); let client = Client::new( - format!("{}/wallet/default", bitcoind.rpc_url().as_str()).as_str(), - Auth::UserPass("bitcoind".to_string(), "bitcoind".to_string()), + format!("{}/wallet/default", tapyrusd.rpc_url().as_str()).as_str(), + Auth::UserPass("tapyrusd".to_string(), "tapyrusd".to_string()), ) .unwrap(); let info = client.get_blockchain_info().unwrap(); assert_eq!(0, info.blocks); - let address = client.get_new_address(None, None).unwrap().assume_checked(); - let _ = client.generate_to_address(1, &address).unwrap(); - let info = bitcoind.client.get_blockchain_info().unwrap(); + let address = client.get_new_address(None).unwrap().assume_checked(); + let _ = client + .generate_to_address(1, &address, get_private_key()) + .unwrap(); + let info = tapyrusd.client.get_blockchain_info().unwrap(); assert_eq!(1, info.blocks); } #[test] fn test_get_cookie_user_and_pass() { let exe = init(); - let bitcoind = BitcoinD::new(exe).unwrap(); + let tapyrusd = TapyrusD::new(exe).unwrap(); - let user: &str = "bitcoind_user"; - let password: &str = "bitcoind_password"; + let user: &str = "tapyrusd_user"; + let password: &str = "tapyrusd_password"; std::fs::write( - &bitcoind.params.cookie_file, + &tapyrusd.params.cookie_file, format!("{}:{}", user, password), ) .unwrap(); - let result_values = bitcoind.params.get_cookie_values().unwrap().unwrap(); + let result_values = tapyrusd.params.get_cookie_values().unwrap().unwrap(); assert_eq!(user, result_values.user); assert_eq!(password, result_values.password); @@ -809,19 +842,19 @@ mod test { fn zmq_interface_enabled() { let mut conf = Conf::default(); conf.enable_zmq = true; - let bitcoind = BitcoinD::with_conf(exe_path().unwrap(), &conf).unwrap(); + let tapyrusd = TapyrusD::with_conf(exe_path().unwrap(), &conf).unwrap(); - assert!(bitcoind.params.zmq_pub_raw_tx_socket.is_some()); - assert!(bitcoind.params.zmq_pub_raw_block_socket.is_some()); + assert!(tapyrusd.params.zmq_pub_raw_tx_socket.is_some()); + assert!(tapyrusd.params.zmq_pub_raw_block_socket.is_some()); } #[test] fn zmq_interface_disabled() { let exe = init(); - let bitcoind = BitcoinD::new(exe).unwrap(); + let tapyrusd = TapyrusD::new(exe).unwrap(); - assert!(bitcoind.params.zmq_pub_raw_tx_socket.is_none()); - assert!(bitcoind.params.zmq_pub_raw_block_socket.is_none()); + assert!(tapyrusd.params.zmq_pub_raw_tx_socket.is_none()); + assert!(tapyrusd.params.zmq_pub_raw_block_socket.is_none()); } fn peers_connected(client: &Client) -> usize { diff --git a/src/versions.rs b/src/versions.rs index 7668789..69c73a5 100644 --- a/src/versions.rs +++ b/src/versions.rs @@ -1,32 +1,5 @@ -#[cfg(feature = "26_0")] -pub const VERSION: &str = "26.0"; +#[cfg(feature = "0_5_2")] +pub const VERSION: &str = "0.5.2"; -#[cfg(all(feature = "25_1", not(feature = "26_0")))] -pub const VERSION: &str = "25.1"; - -#[cfg(all(feature = "25_0", not(feature = "25_1")))] -pub const VERSION: &str = "25.0"; - -#[cfg(all(feature = "24_0_1", not(feature = "25_0")))] -pub const VERSION: &str = "24.0.1"; - -#[cfg(all(feature = "23_1", not(feature = "24_0_1")))] -pub const VERSION: &str = "23.1"; - -#[cfg(all(feature = "22_1", not(feature = "23_1")))] -pub const VERSION: &str = "22.1"; - -#[cfg(all(feature = "0_21_2", not(feature = "22_1")))] -pub const VERSION: &str = "0.21.2"; - -#[cfg(all(feature = "0_20_2", not(feature = "0_21_2")))] -pub const VERSION: &str = "0.20.2"; - -#[cfg(all(feature = "0_19_1", not(feature = "0_20_2")))] -pub const VERSION: &str = "0.19.1"; - -#[cfg(all(feature = "0_18_1", not(feature = "0_19_1")))] -pub const VERSION: &str = "0.18.1"; - -#[cfg(all(feature = "0_17_1", not(feature = "0_18_1")))] -pub const VERSION: &str = "0.17.1"; +#[cfg(all(feature = "0_5_1", not(feature = "0_5_2")))] +pub const VERSION: &str = "0.5.1";