diff --git a/rpc-integration-test/run.sh b/rpc-integration-test/run.sh index a442ae47..dab05ce9 100755 --- a/rpc-integration-test/run.sh +++ b/rpc-integration-test/run.sh @@ -1,51 +1,46 @@ #!/bin/sh -TESTDIR=/tmp/rust_bitcoincore_rpc_test +set -e -rm -rf ${TESTDIR} -mkdir -p ${TESTDIR}/1 ${TESTDIR}/2 +TESTDIR=/tmp/rust_dashcore_rpc_test -# To kill any remaining open bitcoind. -killall -9 bitcoind +rm -rf "${TESTDIR}" +mkdir -p "${TESTDIR}/dash" -bitcoind -regtest \ - -datadir=${TESTDIR}/1 \ - -port=12348 \ - -server=0 \ - -printtoconsole=0 & -PID1=$! +# Kill any remaining dashd to avoid port conflicts +if command -v killall >/dev/null 2>&1; then + killall -9 dashd 2>/dev/null || true +fi -# Make sure it's listening on its p2p port. -sleep 3 +# Start Dash Core on regtest using standard Dash RPC port 19898 +dashd -regtest \ + -datadir="${TESTDIR}/dash" \ + -rpcport=19898 \ + -server=1 \ + -txindex=1 \ + -printtoconsole=0 & +PID=$! -BLOCKFILTERARG="" -if bitcoind -version | grep -q "v0\.\(19\|2\)"; then - BLOCKFILTERARG="-blockfilterindex=1" -fi +# Allow time for startup +sleep 5 -FALLBACKFEEARG="" -if bitcoind -version | grep -q "v0\.2"; then - FALLBACKFEEARG="-fallbackfee=0.00001000" -fi +# Pre-create faucet wallet "main" so the test can fund addresses +dash-cli -regtest -datadir="${TESTDIR}/dash" -rpcport=19898 -named createwallet wallet_name=main descriptors=false >/dev/null 2>&1 || true -bitcoind -regtest $BLOCKFILTERARG $FALLBACKFEEARG \ - -datadir=${TESTDIR}/2 \ - -connect=127.0.0.1:12348 \ - -rpcport=12349 \ - -server=1 \ - -txindex=1 \ - -printtoconsole=0 & -PID2=$! +# Fund the faucet wallet with mature coins +FAUCET_ADDR=$(dash-cli -regtest -datadir="${TESTDIR}/dash" -rpcport=19898 -rpcwallet=main getnewaddress) +dash-cli -regtest -datadir="${TESTDIR}/dash" -rpcport=19898 generatetoaddress 110 "$FAUCET_ADDR" >/dev/null -# Let it connect to the other node. -sleep 5 +# Export per-node env vars expected by the test (both point to same node) +export WALLET_NODE_RPC_URL="http://127.0.0.1:19898" +export EVO_NODE_RPC_URL="http://127.0.0.1:19898" +export WALLET_NODE_RPC_COOKIE="${TESTDIR}/dash/regtest/.cookie" +export EVO_NODE_RPC_COOKIE="${TESTDIR}/dash/regtest/.cookie" -RPC_URL=http://localhost:12349 \ - RPC_COOKIE=${TESTDIR}/2/regtest/.cookie \ - cargo run +cargo run RESULT=$? -kill -9 $PID1 $PID2 +kill -9 $PID 2>/dev/null || true exit $RESULT diff --git a/rpc-integration-test/src/main.rs b/rpc-integration-test/src/main.rs index eb86b7fb..54022a06 100644 --- a/rpc-integration-test/src/main.rs +++ b/rpc-integration-test/src/main.rs @@ -40,8 +40,9 @@ use dashcore_rpc::json::QuorumType::LlmqTest; const FAUCET_WALLET_NAME: &str = "main"; const TEST_WALLET_NAME: &str = "testwallet"; -const DEFAULT_WALLET_NODE_RPC_URL: &str = "http://127.0.0.1:20002"; -const DEFAULT_EVO_NODE_RPC_URL: &str = "http://127.0.0.1:20302"; +// Dash regtest default RPC port is 19898. For mainnet/testnet use 9998/19998. +const DEFAULT_WALLET_NODE_RPC_URL: &str = "http://127.0.0.1:19898"; +const DEFAULT_EVO_NODE_RPC_URL: &str = "http://127.0.0.1:19898"; lazy_static! { static ref SECP: secp256k1::Secp256k1 = secp256k1::Secp256k1::new(); @@ -120,26 +121,46 @@ fn sbtc>(btc: F) -> SignedAmount { } fn get_rpc_urls() -> (Option, Option) { - let wallet_node_url = std::env::var("WALLET_NODE_RPC_URL").ok().filter(|s| !s.is_empty()); - - let evo_node_rpc_url = std::env::var("EVO_NODE_RPC_URL").ok().filter(|s| !s.is_empty()); + // Prefer explicit per-node URLs; fall back to a generic RPC_URL for both + let generic_url = std::env::var("RPC_URL").ok().filter(|s| !s.is_empty()); + let wallet_node_url = std::env::var("WALLET_NODE_RPC_URL") + .ok() + .filter(|s| !s.is_empty()) + .or_else(|| generic_url.clone()); + let evo_node_rpc_url = std::env::var("EVO_NODE_RPC_URL") + .ok() + .filter(|s| !s.is_empty()) + .or_else(|| generic_url.clone()); (wallet_node_url, evo_node_rpc_url) } fn get_auth() -> (Auth, Auth) { + // Prefer explicit per-node cookie; fall back to generic RPC_COOKIE let wallet_node_auth = std::env::var("WALLET_NODE_RPC_COOKIE") .ok() .filter(|s| !s.is_empty()) .map(|cookie| Auth::CookieFile(cookie.into())) .unwrap_or_else(|| { + // Prefer per-node user/pass; fall back to generic RPC_USER/PASS std::env::var("WALLET_NODE_RPC_USER") + .or_else(|_| std::env::var("RPC_USER")) .ok() .filter(|s| !s.is_empty()) .map(|user| { - Auth::UserPass(user, std::env::var("WALLET_NODE_RPC_PASS").unwrap_or_default()) + let pass = std::env::var("WALLET_NODE_RPC_PASS") + .or_else(|_| std::env::var("RPC_PASS")) + .unwrap_or_default(); + Auth::UserPass(user, pass) + }) + .unwrap_or_else(|| { + // Generic cookie as last resort + std::env::var("RPC_COOKIE") + .ok() + .filter(|s| !s.is_empty()) + .map(|cookie| Auth::CookieFile(cookie.into())) + .unwrap_or(Auth::None) }) - .unwrap_or(Auth::None) }); let evo_node_auth = std::env::var("EVO_NODE_RPC_COOKIE") @@ -148,12 +169,22 @@ fn get_auth() -> (Auth, Auth) { .map(|cookie| Auth::CookieFile(cookie.into())) .unwrap_or_else(|| { std::env::var("EVO_NODE_RPC_USER") + .or_else(|_| std::env::var("RPC_USER")) .ok() .filter(|s| !s.is_empty()) .map(|user| { - Auth::UserPass(user, std::env::var("EVO_NODE_RPC_PASS").unwrap_or_default()) + let pass = std::env::var("EVO_NODE_RPC_PASS") + .or_else(|_| std::env::var("RPC_PASS")) + .unwrap_or_default(); + Auth::UserPass(user, pass) + }) + .unwrap_or_else(|| { + std::env::var("RPC_COOKIE") + .ok() + .filter(|s| !s.is_empty()) + .map(|cookie| Auth::CookieFile(cookie.into())) + .unwrap_or(Auth::None) }) - .unwrap_or(Auth::None) }); (wallet_node_auth, evo_node_auth) @@ -189,7 +220,8 @@ fn main() { let faucet_rpc_url = format!("{}/wallet/{}", wallet_node_rpc_url, FAUCET_WALLET_NAME); let wallet_rpc_url = format!("{}/wallet/{}", wallet_node_rpc_url, TEST_WALLET_NAME); - let evo_rpc_url = format!("{}/wallet/{}", evo_node_rpc_url, TEST_WALLET_NAME); + // Evo/masternode RPCs are non-wallet; use base RPC URL + let evo_rpc_url = evo_node_rpc_url.clone(); let faucet_client = Client::new(&faucet_rpc_url, wallet_node_auth.clone().clone()).unwrap(); let wallet_client = Client::new(&wallet_rpc_url, wallet_node_auth).unwrap(); @@ -247,7 +279,17 @@ fn main() { trace!(target: "integration_test", "Funded wallet \"{}\". Total balance: {}", TEST_WALLET_NAME, balance); faucet_client.generate_to_address(8, &test_wallet_address).unwrap(); test_wallet_node_endpoints(&wallet_client); - test_evo_node_endpoints(&evo_client, &wallet_client); + + // Gate evo/masternode tests behind env, as they require a proper evo-enabled setup. + let run_evo = std::env::var("RUN_EVO_TESTS") + .ok() + .map(|v| v.eq_ignore_ascii_case("1") || v.eq_ignore_ascii_case("true")) + .unwrap_or(false); + if run_evo { + test_evo_node_endpoints(&evo_client, &wallet_client); + } else { + trace!(target: "integration_test", "Skipping evo/masternode RPC tests (set RUN_EVO_TESTS=true to enable)"); + } // //TODO import_multi( // //TODO verify_message( @@ -272,7 +314,14 @@ fn test_wallet_node_endpoints(wallet_client: &Client) { // test_get_balance_generate_to_address(wallet_client); test_get_balances_generate_to_address(wallet_client); test_get_best_block_hash(wallet_client); - test_get_best_chain_lock(wallet_client); + // ChainLocks depend on LLMQ; run only when evo tests are enabled + let run_evo = std::env::var("RUN_EVO_TESTS") + .ok() + .map(|v| v.eq_ignore_ascii_case("1") || v.eq_ignore_ascii_case("true")) + .unwrap_or(false); + if run_evo { + test_get_best_chain_lock(wallet_client); + } test_get_block_count(wallet_client); test_get_block_hash(wallet_client); // TODO(dashcore): - fails to parse block @@ -735,7 +784,46 @@ fn test_sign_raw_transaction_with_send_raw_transaction(cl: &Client) { minimum_amount: Some(btc(2)), ..Default::default() }; - let unspent = cl.list_unspent(Some(6), None, None, None, Some(options)).unwrap(); + // Ensure we have a confirmed, sufficiently large UTXO owned by this wallet. + // 1) Create a fresh funding output to a new wallet address, with fallbacks if balance is tight. + let fund_addr = cl.get_new_address(None).unwrap().require_network(*NET).unwrap(); + let mut funded_amount_btc: Option = None; + for amt in [3.0_f64, 1.0_f64, 0.5_f64] { + match cl.send_to_address( + &fund_addr, + btc(amt), + None, + None, + None, + None, + None, + None, + None, + None, + ) { + Ok(_) => { + funded_amount_btc = Some(amt); + break; + } + Err(dashcore_rpc::Error::JsonRpc(dashcore_rpc::jsonrpc::error::Error::Rpc(e))) + if e.code == -6 && e.message.contains("Insufficient funds") => + { + continue; + } + Err(e) => panic!("Unexpected error funding test UTXO: {:?}", e), + } + } + let funded_amount_btc = + funded_amount_btc.expect("wallet has insufficient balance even for 0.5 DASH"); + // 2) Mine 6 blocks to confirm all pending transactions (not coinbases). + let mine_addr = cl.get_new_address(None).unwrap().require_network(*NET).unwrap(); + let _ = cl.generate_to_address(6, &mine_addr).unwrap(); + // 3) Select a confirmed UTXO with at least the funded amount (the vout to fund_addr equals the send amount). + let options = json::ListUnspentQueryOptions { + minimum_amount: Some(btc(funded_amount_btc)), + ..Default::default() + }; + let unspent = cl.list_unspent(Some(6), None, Some(&[&fund_addr]), None, Some(options)).unwrap(); let unspent = unspent.into_iter().next().unwrap(); let tx = Transaction { diff --git a/rpc-json/Cargo.toml b/rpc-json/Cargo.toml index 3f3dda5f..b3953ed0 100644 --- a/rpc-json/Cargo.toml +++ b/rpc-json/Cargo.toml @@ -26,6 +26,6 @@ serde_repr = "0.1" hex = { version="0.4", features=["serde"]} key-wallet = { path = "../key-wallet", features=["serde"] } -dashcore = { path = "../dash", features=["std", "secp-recovery", "rand-std", "signer", "serde"], default-features = false } +dashcore = { path = "../dash", features=["std", "secp-recovery", "rand-std", "signer", "serde", "core-block-hash-use-x11"], default-features = false } bincode = { version = "=2.0.0-rc.3", features = ["serde"] } diff --git a/rpc-json/src/lib.rs b/rpc-json/src/lib.rs index d7f6228e..46742c23 100644 --- a/rpc-json/src/lib.rs +++ b/rpc-json/src/lib.rs @@ -83,16 +83,11 @@ pub struct GetNetworkInfoResult { #[serde(rename = "networkactive")] pub network_active: bool, pub connections: usize, - #[serde(rename = "inboundconnections")] - pub inbound_connections: usize, - #[serde(rename = "outboundconnections")] - pub outbound_connections: usize, - #[serde(rename = "mnconnections")] - pub mn_connections: usize, - #[serde(rename = "inboundmnconnections")] - pub inbound_mn_connections: usize, - #[serde(rename = "outboundmnconnections")] - pub outbound_mn_connections: usize, + pub connections_in: usize, + pub connections_out: usize, + pub connections_mn: usize, + pub connections_mn_in: usize, + pub connections_mn_out: usize, #[serde(rename = "socketevents")] pub socket_events: String, pub networks: Vec,