|
| 1 | +//! # rust-miniscript integration test |
| 2 | +//! |
| 3 | +//! This is how some external user would use rust-miniscript |
| 4 | +
|
| 5 | +use bitcoincore_rpc::{Auth, Client, RpcApi}; |
| 6 | + |
| 7 | +mod test_cpp; |
| 8 | +mod test_desc; |
| 9 | +mod test_util; |
| 10 | +use crate::test_util::TestData; |
| 11 | + |
| 12 | +struct StdLogger; |
| 13 | + |
| 14 | +impl log::Log for StdLogger { |
| 15 | + fn enabled(&self, metadata: &log::Metadata<'_>) -> bool { |
| 16 | + metadata.target().contains("jsonrpc") || metadata.target().contains("bitcoincore_rpc") |
| 17 | + } |
| 18 | + |
| 19 | + fn log(&self, record: &log::Record<'_>) { |
| 20 | + if self.enabled(record.metadata()) { |
| 21 | + println!( |
| 22 | + "[{}][{}]: {}", |
| 23 | + record.level(), |
| 24 | + record.metadata().target(), |
| 25 | + record.args() |
| 26 | + ); |
| 27 | + } |
| 28 | + } |
| 29 | + |
| 30 | + fn flush(&self) {} |
| 31 | +} |
| 32 | + |
| 33 | +static LOGGER: StdLogger = StdLogger; |
| 34 | + |
| 35 | +fn get_rpc_url() -> String { |
| 36 | + return std::env::var("RPC_URL").expect("RPC_URL must be set"); |
| 37 | +} |
| 38 | + |
| 39 | +fn get_auth() -> bitcoincore_rpc::Auth { |
| 40 | + if let Ok(cookie) = std::env::var("RPC_COOKIE") { |
| 41 | + return Auth::CookieFile(cookie.into()); |
| 42 | + } else if let Ok(user) = std::env::var("RPC_USER") { |
| 43 | + return Auth::UserPass(user, std::env::var("RPC_PASS").unwrap_or_default()); |
| 44 | + } else { |
| 45 | + panic!("Either RPC_COOKIE or RPC_USER + RPC_PASS must be set."); |
| 46 | + }; |
| 47 | +} |
| 48 | + |
| 49 | +fn main() { |
| 50 | + log::set_logger(&LOGGER) |
| 51 | + .map(|()| log::set_max_level(log::LevelFilter::max())) |
| 52 | + .unwrap(); |
| 53 | + |
| 54 | + let rpc_url = format!("{}/wallet/testwallet", get_rpc_url()); |
| 55 | + let auth = get_auth(); |
| 56 | + |
| 57 | + let cl = Client::new(&rpc_url, auth).unwrap(); |
| 58 | + |
| 59 | + // 0.21 does not create default wallet.. |
| 60 | + cl.create_wallet("testwallet", None, None, None, None) |
| 61 | + .unwrap(); |
| 62 | + |
| 63 | + let testdata = TestData::new_fixed_data(50); |
| 64 | + test_cpp::test_from_cpp_ms(&cl, &testdata); |
| 65 | + |
| 66 | + test_descs(&cl, &testdata); |
| 67 | +} |
| 68 | + |
| 69 | +fn test_descs(cl: &Client, testdata: &TestData) { |
| 70 | + // K : Compressed key available |
| 71 | + // K!: Compressed key with corresponding secret key unknown |
| 72 | + // X: X-only key available |
| 73 | + // X!: X-only key with corresponding secret key unknown |
| 74 | + |
| 75 | + // Test 1: Simple spend with internal key |
| 76 | + let wit = test_desc::test_desc_satisfy(cl, testdata, "tr(X)").unwrap(); |
| 77 | + assert!(wit.len() == 1); |
| 78 | + |
| 79 | + // Test 2: Same as above, but with leaves |
| 80 | + let wit = test_desc::test_desc_satisfy(cl, testdata, "tr(X,{pk(X1!),pk(X2!)})").unwrap(); |
| 81 | + assert!(wit.len() == 1); |
| 82 | + |
| 83 | + // Test 3: Force to spend with script spend. Unknown internal key and only one known script path |
| 84 | + // X! -> Internal key unknown |
| 85 | + // Leaf 1 -> pk(X1) with X1 known |
| 86 | + // Leaf 2-> and_v(v:pk(X2),pk(X3!)) with partial witness only to X2 known |
| 87 | + let wit = test_desc::test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1),and_v(v:pk(X2),pk(X3!))})").unwrap(); |
| 88 | + assert!(wit.len() == 3); // control block, script and signature |
| 89 | + |
| 90 | + // Test 4: Force to spend with script spend. Unknown internal key and multiple script paths |
| 91 | + // Should select the one with minimum weight |
| 92 | + // X! -> Internal key unknown |
| 93 | + // Leaf 1 -> pk(X1!) with X1 unknown |
| 94 | + // Leaf 2-> and_v(v:pk(X2),pk(X3)) X2 and X3 known |
| 95 | + let wit = test_desc::test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1),and_v(v:pk(X2),pk(X3))})").unwrap(); |
| 96 | + assert!(wit.len() == 3); // control block, script and one signatures |
| 97 | + |
| 98 | + // Test 5: When everything is available, we should select the key spend path |
| 99 | + let wit = test_desc::test_desc_satisfy(cl, testdata, "tr(X,{pk(X1),and_v(v:pk(X2),pk(X3!))})").unwrap(); |
| 100 | + assert!(wit.len() == 1); // control block, script and signature |
| 101 | + |
| 102 | + // Test 6: Test the new multi_a opcodes |
| 103 | + test_desc::test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),multi_a(1,X2,X3!,X4!,X5!)})"); |
| 104 | + test_desc::test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),multi_a(2,X2,X3,X4!,X5!)})"); |
| 105 | + test_desc::test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),multi_a(3,X2,X3,X4,X5!)})"); |
| 106 | + test_desc::test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),multi_a(4,X2,X3,X4,X5)})"); |
| 107 | + |
| 108 | + // Test 7: Test script tree of depth 127 is valid, only X128 is known |
| 109 | + test_desc::test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),{pk(X2!),{pk(X3!),{pk(X4!),{pk(X5!),{pk(X6!),{pk(X7!),{pk(X8!),{pk(X9!),{pk(X10!),{pk(X11!),{pk(X12!),{pk(X13!),{pk(X14!),{pk(X15!),{pk(X16!),{pk(X17!),{pk(X18!),{pk(X19!),{pk(X20!),{pk(X21!),{pk(X22!),{pk(X23!),{pk(X24!),{pk(X25!),{pk(X26!),{pk(X27!),{pk(X28!),{pk(X29!),{pk(X30!),{pk(X31!),{pk(X32!),{pk(X33!),{pk(X34!),{pk(X35!),{pk(X36!),{pk(X37!),{pk(X38!),{pk(X39!),{pk(X40!),{pk(X41!),{pk(X42!),{pk(X43!),{pk(X44!),{pk(X45!),{pk(X46!),{pk(X47!),{pk(X48!),{pk(X49!),{pk(X50!),{pk(X51!),{pk(X52!),{pk(X53!),{pk(X54!),{pk(X55!),{pk(X56!),{pk(X57!),{pk(X58!),{pk(X59!),{pk(X60!),{pk(X61!),{pk(X62!),{pk(X63!),{pk(X64!),{pk(X65!),{pk(X66!),{pk(X67!),{pk(X68!),{pk(X69!),{pk(X70!),{pk(X71!),{pk(X72!),{pk(X73!),{pk(X74!),{pk(X75!),{pk(X76!),{pk(X77!),{pk(X78!),{pk(X79!),{pk(X80!),{pk(X81!),{pk(X82!),{pk(X83!),{pk(X84!),{pk(X85!),{pk(X86!),{pk(X87!),{pk(X88!),{pk(X89!),{pk(X90!),{pk(X91!),{pk(X92!),{pk(X93!),{pk(X94!),{pk(X95!),{pk(X96!),{pk(X97!),{pk(X98!),{pk(X99!),{pk(X100!),{pk(X101!),{pk(X102!),{pk(X103!),{pk(X104!),{pk(X105!),{pk(X106!),{pk(X107!),{pk(X108!),{pk(X109!),{pk(X110!),{pk(X111!),{pk(X112!),{pk(X113!),{pk(X114!),{pk(X115!),{pk(X116!),{pk(X117!),{pk(X118!),{pk(X119!),{pk(X120!),{pk(X121!),{pk(X122!),{pk(X123!),{pk(X124!),{pk(X125!),{pk(X126!),{pk(X127!),pk(X128)}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}})"); |
| 110 | + |
| 111 | + // Test 8: Test script tree of depth 128 is valid, only X129 is known |
| 112 | + test_desc::test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),{pk(X2!),{pk(X3!),{pk(X4!),{pk(X5!),{pk(X6!),{pk(X7!),{pk(X8!),{pk(X9!),{pk(X10!),{pk(X11!),{pk(X12!),{pk(X13!),{pk(X14!),{pk(X15!),{pk(X16!),{pk(X17!),{pk(X18!),{pk(X19!),{pk(X20!),{pk(X21!),{pk(X22!),{pk(X23!),{pk(X24!),{pk(X25!),{pk(X26!),{pk(X27!),{pk(X28!),{pk(X29!),{pk(X30!),{pk(X31!),{pk(X32!),{pk(X33!),{pk(X34!),{pk(X35!),{pk(X36!),{pk(X37!),{pk(X38!),{pk(X39!),{pk(X40!),{pk(X41!),{pk(X42!),{pk(X43!),{pk(X44!),{pk(X45!),{pk(X46!),{pk(X47!),{pk(X48!),{pk(X49!),{pk(X50!),{pk(X51!),{pk(X52!),{pk(X53!),{pk(X54!),{pk(X55!),{pk(X56!),{pk(X57!),{pk(X58!),{pk(X59!),{pk(X60!),{pk(X61!),{pk(X62!),{pk(X63!),{pk(X64!),{pk(X65!),{pk(X66!),{pk(X67!),{pk(X68!),{pk(X69!),{pk(X70!),{pk(X71!),{pk(X72!),{pk(X73!),{pk(X74!),{pk(X75!),{pk(X76!),{pk(X77!),{pk(X78!),{pk(X79!),{pk(X80!),{pk(X81!),{pk(X82!),{pk(X83!),{pk(X84!),{pk(X85!),{pk(X86!),{pk(X87!),{pk(X88!),{pk(X89!),{pk(X90!),{pk(X91!),{pk(X92!),{pk(X93!),{pk(X94!),{pk(X95!),{pk(X96!),{pk(X97!),{pk(X98!),{pk(X99!),{pk(X100!),{pk(X101!),{pk(X102!),{pk(X103!),{pk(X104!),{pk(X105!),{pk(X106!),{pk(X107!),{pk(X108!),{pk(X109!),{pk(X110!),{pk(X111!),{pk(X112!),{pk(X113!),{pk(X114!),{pk(X115!),{pk(X116!),{pk(X117!),{pk(X118!),{pk(X119!),{pk(X120!),{pk(X121!),{pk(X122!),{pk(X123!),{pk(X124!),{pk(X125!),{pk(X126!),{pk(X127!),{pk(X128!),pk(X129)}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}})"); |
| 113 | + |
| 114 | + // Test 9: Test script complete tree having 128 leaves with depth log(128), only X1 is known |
| 115 | + test_desc::test_desc_satisfy(cl, testdata, "tr(X!,{{{{{{{pk(X1),pk(X2!)},{pk(X3!),pk(X4!)}},{{pk(X5!),pk(X6!)},{pk(X7!),pk(X8!)}}},{{{pk(X9!),pk(X10!)},{pk(X11!),pk(X12!)}},{{pk(X13!),pk(X14!)},{pk(X15!),pk(X16!)}}}},{{{{pk(X17!),pk(X18!)},{pk(X19!),pk(X20!)}},{{pk(X21!),pk(X22!)},{pk(X23!),pk(X24!)}}},{{{pk(X25!),pk(X26!)},{pk(X27!),pk(X28!)}},{{pk(X29!),pk(X30!)},{pk(X31!),pk(X32!)}}}}},{{{{{pk(X33!),pk(X34!)},{pk(X35!),pk(X36!)}},{{pk(X37!),pk(X38!)},{pk(X39!),pk(X40!)}}},{{{pk(X41!),pk(X42!)},{pk(X43!),pk(X44!)}},{{pk(X45!),pk(X46!)},{pk(X47!),pk(X48!)}}}},{{{{pk(X49!),pk(X50!)},{pk(X51!),pk(X52!)}},{{pk(X53!),pk(X54!)},{pk(X55!),pk(X56!)}}},{{{pk(X57!),pk(X58!)},{pk(X59!),pk(X60!)}},{{pk(X61!),pk(X62!)},{pk(X63!),pk(X64!)}}}}}},{{{{{{pk(X65!),pk(X66!)},{pk(X67!),pk(X68!)}},{{pk(X69!),pk(X70!)},{pk(X71!),pk(X72!)}}},{{{pk(X73!),pk(X74!)},{pk(X75!),pk(X76!)}},{{pk(X77!),pk(X78!)},{pk(X79!),pk(X80!)}}}},{{{{pk(X81!),pk(X82!)},{pk(X83!),pk(X84!)}},{{pk(X85!),pk(X86!)},{pk(X87!),pk(X88!)}}},{{{pk(X89!),pk(X90!)},{pk(X91!),pk(X92!)}},{{pk(X93!),pk(X94!)},{pk(X95!),pk(X96!)}}}}},{{{{{pk(X97!),pk(X98!)},{pk(X99!),pk(X100!)}},{{pk(X101!),pk(X102!)},{pk(X103!),pk(X104!)}}},{{{pk(X105!),pk(X106!)},{pk(X107!),pk(X108!)}},{{pk(X109!),pk(X110!)},{pk(X111!),pk(X112!)}}}},{{{{pk(X113!),pk(X114!)},{pk(X115!),pk(X116!)}},{{pk(X117!),pk(X118!)},{pk(X119!),pk(X120!)}}},{{{pk(X121!),pk(X122!)},{pk(X123!),pk(X124!)}},{{pk(X125!),pk(X126!)},{pk(X127!),pk(X128!)}}}}}}})"); |
| 116 | + |
| 117 | + // Test 10: Test taproot desc with ZERO known keys |
| 118 | + let result = test_desc::test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),pk(X2!)})"); |
| 119 | + match result { |
| 120 | + Ok(wit) => (), |
| 121 | + Err(error) => println!("taproot desc with ZERO known keys : {}", error) |
| 122 | + } |
| 123 | + |
| 124 | + // Test 11: Test taproot with insufficient known keys |
| 125 | + let result = test_desc::test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),multi_a(3,X2!,X3,X4)})"); |
| 126 | + match result { |
| 127 | + Ok(wit) => (), |
| 128 | + Err(error) => println!("taproot desc with insufficient known keys : {}", error) |
| 129 | + } |
| 130 | + |
| 131 | + // Test 12: size exceeds the limit |
| 132 | + let result = test_desc::test_desc_satisfy(cl, testdata, "wsh(thresh(1,pk(K1),a:pk(K2),a:pk(K3),a:pk(K4),a:pk(K5),a:pk(K6),a:pk(K7),a:pk(K8),a:pk(K9),a:pk(K10),a:pk(K11),a:pk(K12),a:pk(K13),a:pk(K14),a:pk(K15),a:pk(K16),a:pk(K17),a:pk(K18),a:pk(K19),a:pk(K20),a:pk(K21),a:pk(K22),a:pk(K23),a:pk(K24),a:pk(K25),a:pk(K26),a:pk(K27),a:pk(K28),a:pk(K29),a:pk(K30),a:pk(K31),a:pk(K32),a:pk(K33),a:pk(K34),a:pk(K35),a:pk(K36),a:pk(K37),a:pk(K38),a:pk(K39),a:pk(K40),a:pk(K41),a:pk(K42),a:pk(K43),a:pk(K44),a:pk(K45),a:pk(K46),a:pk(K47),a:pk(K48),a:pk(K49),a:pk(K50),a:pk(K51),a:pk(K52),a:pk(K53),a:pk(K54),a:pk(K55),a:pk(K56),a:pk(K57),a:pk(K58),a:pk(K59),a:pk(K60),a:pk(K61),a:pk(K62),a:pk(K63),a:pk(K64),a:pk(K65),a:pk(K66),a:pk(K67),a:pk(K68),a:pk(K69),a:pk(K70),a:pk(K71),a:pk(K72),a:pk(K73),a:pk(K74),a:pk(K75),a:pk(K76),a:pk(K77),a:pk(K78),a:pk(K79),a:pk(K80),a:pk(K81),a:pk(K82),a:pk(K83),a:pk(K84),a:pk(K85),a:pk(K86),a:pk(K87),a:pk(K88),a:pk(K89),a:pk(K90),a:pk(K91),a:pk(K92),a:pk(K93),a:pk(K94),a:pk(K95),a:pk(K96),a:pk(K97),a:pk(K98),a:pk(K99),a:pk(K100)))"); |
| 133 | + match result { |
| 134 | + Ok(wit) => (), |
| 135 | + Err(error) => println!("Witness script size exceeds 3600 bytes : {}", error) |
| 136 | + } |
| 137 | + |
| 138 | + // Test 13: Test script tree of depth > 128 is invalid |
| 139 | + let result = test_desc::test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),{pk(X2!),{pk(X3!),{pk(X4!),{pk(X5!),{pk(X6!),{pk(X7!),{pk(X8!),{pk(X9!),{pk(X10!),{pk(X11!),{pk(X12!),{pk(X13!),{pk(X14!),{pk(X15!),{pk(X16!),{pk(X17!),{pk(X18!),{pk(X19!),{pk(X20!),{pk(X21!),{pk(X22!),{pk(X23!),{pk(X24!),{pk(X25!),{pk(X26!),{pk(X27!),{pk(X28!),{pk(X29!),{pk(X30!),{pk(X31!),{pk(X32!),{pk(X33!),{pk(X34!),{pk(X35!),{pk(X36!),{pk(X37!),{pk(X38!),{pk(X39!),{pk(X40!),{pk(X41!),{pk(X42!),{pk(X43!),{pk(X44!),{pk(X45!),{pk(X46!),{pk(X47!),{pk(X48!),{pk(X49!),{pk(X50!),{pk(X51!),{pk(X52!),{pk(X53!),{pk(X54!),{pk(X55!),{pk(X56!),{pk(X57!),{pk(X58!),{pk(X59!),{pk(X60!),{pk(X61!),{pk(X62!),{pk(X63!),{pk(X64!),{pk(X65!),{pk(X66!),{pk(X67!),{pk(X68!),{pk(X69!),{pk(X70!),{pk(X71!),{pk(X72!),{pk(X73!),{pk(X74!),{pk(X75!),{pk(X76!),{pk(X77!),{pk(X78!),{pk(X79!),{pk(X80!),{pk(X81!),{pk(X82!),{pk(X83!),{pk(X84!),{pk(X85!),{pk(X86!),{pk(X87!),{pk(X88!),{pk(X89!),{pk(X90!),{pk(X91!),{pk(X92!),{pk(X93!),{pk(X94!),{pk(X95!),{pk(X96!),{pk(X97!),{pk(X98!),{pk(X99!),{pk(X100!),{pk(X101!),{pk(X102!),{pk(X103!),{pk(X104!),{pk(X105!),{pk(X106!),{pk(X107!),{pk(X108!),{pk(X109!),{pk(X110!),{pk(X111!),{pk(X112!),{pk(X113!),{pk(X114!),{pk(X115!),{pk(X116!),{pk(X117!),{pk(X118!),{pk(X119!),{pk(X120!),{pk(X121!),{pk(X122!),{pk(X123!),{pk(X124!),{pk(X125!),{pk(X126!),{pk(X127!),{pk(X128!),{pk(X129!),pk(X130)}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}})"); |
| 140 | + match result { |
| 141 | + Ok(wit) => (), |
| 142 | + Err(error) => println!("script tree is having depth 129 and hence it is invalid : {}", error) |
| 143 | + } |
| 144 | + |
| 145 | + // Misc tests for other descriptors that we support |
| 146 | + // Keys |
| 147 | + test_desc::test_desc_satisfy(cl, testdata, "wpkh(K)"); |
| 148 | + test_desc::test_desc_satisfy(cl, testdata, "pkh(K)"); |
| 149 | + test_desc::test_desc_satisfy(cl, testdata, "sh(wpkh(K))"); |
| 150 | + |
| 151 | + // sorted multi |
| 152 | + test_desc::test_desc_satisfy(cl, testdata, "sh(sortedmulti(2,K1,K2,K3))"); |
| 153 | + test_desc::test_desc_satisfy(cl, testdata, "wsh(sortedmulti(2,K1,K2,K3))"); |
| 154 | + test_desc::test_desc_satisfy(cl, testdata, "sh(wsh(sortedmulti(2,K1,K2,K3)))"); |
| 155 | + |
| 156 | + // Miniscripts |
| 157 | + test_desc::test_desc_satisfy(cl, testdata, "sh(and_v(v:pk(K1),pk(K2)))"); |
| 158 | + test_desc::test_desc_satisfy(cl, testdata, "wsh(and_v(v:pk(K1),pk(K2)))"); |
| 159 | + test_desc::test_desc_satisfy(cl, testdata, "sh(wsh(and_v(v:pk(K1),pk(K2))))"); |
| 160 | +} |
0 commit comments