use blvm_node::node::mempool::MempoolManager;
use blvm_node::rpc::rawtx::RawTxRpc;
use blvm_node::storage::Storage;
use serde_json::json;
use std::sync::Arc;
use tempfile::TempDir;
fn create_test_rawtx_rpc() -> RawTxRpc {
let temp_dir = TempDir::new().unwrap();
let storage = Arc::new(Storage::new(temp_dir.path()).unwrap());
let mempool = Arc::new(MempoolManager::new());
RawTxRpc::with_dependencies(storage, mempool, None, None)
}
#[tokio::test]
async fn test_createrawtransaction_basic() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "a1b2c3d4e5f67890123456789012345678901234567890123456789012345678",
"vout": 0
}
]);
let outputs = json!({
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4": 0.001
});
let params = json!([inputs, outputs]);
let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_ok(), "createrawtransaction should succeed");
let tx_hex = result.unwrap();
assert!(tx_hex.is_string(), "Result should be hex string");
let hex_str = tx_hex.as_str().unwrap();
assert!(!hex_str.is_empty(), "Transaction hex should not be empty");
assert!(hex_str.len() % 2 == 0, "Hex string should have even length");
}
#[tokio::test]
async fn test_createrawtransaction_bech32_address() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 0
}
]);
let outputs = json!({
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4": 0.0001
});
let params = json!([inputs, outputs]);
let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_ok(), "Should support Bech32 addresses");
}
#[tokio::test]
async fn test_createrawtransaction_legacy_p2pkh_address() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 0
}
]);
let outputs = json!({
"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa": 0.0001
});
let params = json!([inputs, outputs]);
let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_ok(), "Should support legacy P2PKH addresses");
}
#[tokio::test]
async fn test_createrawtransaction_legacy_p2sh_address() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 0
}
]);
let outputs = json!({
"3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy": 0.0001
});
let params = json!([inputs, outputs]);
let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_ok(), "Should support legacy P2SH addresses");
}
#[tokio::test]
async fn test_createrawtransaction_bech32m_address() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 0
}
]);
let outputs = json!({
"bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr": 0.0001
});
let params = json!([inputs, outputs]);
let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_ok(), "Should support Bech32m addresses");
}
#[tokio::test]
async fn test_createrawtransaction_op_return() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 0
}
]);
let outputs = json!({
"data": "48656c6c6f20576f726c64" });
let params = json!([inputs, outputs]);
let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_ok(), "Should support OP_RETURN outputs");
}
#[tokio::test]
async fn test_createrawtransaction_locktime() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 0
}
]);
let outputs = json!({
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4": 0.001
});
let params = json!([inputs, outputs, 500000]); let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_ok(), "Should support locktime parameter");
}
#[tokio::test]
async fn test_createrawtransaction_no_rbf() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 0
}
]);
let outputs = json!({
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4": 0.001
});
let params = json!([inputs, outputs, 0, false]); let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_ok(), "Should support replaceable=false");
}
#[tokio::test]
async fn test_createrawtransaction_version() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 0
}
]);
let outputs = json!({
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4": 0.001
});
let params = json!([inputs, outputs, 0, true, 1]); let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_ok(), "Should support custom version");
}
#[tokio::test]
async fn test_createrawtransaction_multiple_inputs() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "1111111111111111111111111111111111111111111111111111111111111111",
"vout": 0
},
{
"txid": "2222222222222222222222222222222222222222222222222222222222222222",
"vout": 1
}
]);
let outputs = json!({
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4": 0.002
});
let params = json!([inputs, outputs]);
let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_ok(), "Should support multiple inputs");
}
#[tokio::test]
async fn test_createrawtransaction_multiple_outputs() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 0
}
]);
let outputs = json!({
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4": 0.001,
"bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr": 0.0005
});
let params = json!([inputs, outputs]);
let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_ok(), "Should support multiple outputs");
}
#[tokio::test]
async fn test_createrawtransaction_sequence() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 0,
"sequence": 0xFFFFFFFD_u64 }
]);
let outputs = json!({
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4": 0.001
});
let params = json!([inputs, outputs]);
let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_ok(), "Should support explicit sequence numbers");
}
#[tokio::test]
async fn test_createrawtransaction_missing_inputs() {
let rawtx = create_test_rawtx_rpc();
let outputs = json!({
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4": 0.001
});
let params = json!([json!([]), outputs]); let result = rawtx.createrawtransaction(¶ms).await;
let params_missing = json!([outputs]);
let result_missing = rawtx.createrawtransaction(¶ms_missing).await;
assert!(
result_missing.is_err(),
"Should error on missing inputs parameter"
);
}
#[tokio::test]
async fn test_createrawtransaction_missing_outputs() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 0
}
]);
let params = json!([inputs]); let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_err(), "Should error on missing outputs");
}
#[tokio::test]
async fn test_createrawtransaction_invalid_address() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 0
}
]);
let outputs = json!({
"invalid-address": 0.001
});
let params = json!([inputs, outputs]);
let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_err(), "Should error on invalid address");
}
#[tokio::test]
async fn test_createrawtransaction_empty_outputs() {
let rawtx = create_test_rawtx_rpc();
let inputs = json!([
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 0
}
]);
let outputs = json!({});
let params = json!([inputs, outputs]);
let result = rawtx.createrawtransaction(¶ms).await;
assert!(result.is_err(), "Should error on empty outputs");
}