@@ -1102,6 +1102,17 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
11021102 Ok ( serde_json:: from_value ( result) ?)
11031103 }
11041104
1105+ fn batch_transaction_get_merkle < I > (
1106+ & self ,
1107+ txids_and_heights : I ,
1108+ ) -> Result < Vec < GetMerkleRes > , Error >
1109+ where
1110+ I : IntoIterator + Clone ,
1111+ I :: Item : Borrow < ( Txid , usize ) > ,
1112+ {
1113+ impl_batch_call ! ( self , txids_and_heights, transaction_get_merkle)
1114+ }
1115+
11051116 fn txid_from_pos ( & self , height : usize , tx_pos : usize ) -> Result < Txid , Error > {
11061117 let params = vec ! [ Param :: Usize ( height) , Param :: Usize ( tx_pos) ] ;
11071118 let req = Request :: new_id (
@@ -1448,6 +1459,98 @@ mod test {
14481459 ) ) ;
14491460 }
14501461
1462+ #[ test]
1463+ fn test_batch_transaction_get_merkle ( ) {
1464+ use bitcoin:: Txid ;
1465+
1466+ struct TestCase {
1467+ txid : Txid ,
1468+ block_height : usize ,
1469+ exp_pos : usize ,
1470+ exp_bytes : [ u8 ; 32 ] ,
1471+ }
1472+
1473+ let client = RawClient :: new ( get_test_server ( ) , None ) . unwrap ( ) ;
1474+
1475+ let test_cases: Vec < TestCase > = vec ! [
1476+ TestCase {
1477+ txid: Txid :: from_str(
1478+ "1f7ff3c407f33eabc8bec7d2cc230948f2249ec8e591bcf6f971ca9366c8788d" ,
1479+ )
1480+ . unwrap( ) ,
1481+ block_height: 630000 ,
1482+ exp_pos: 68 ,
1483+ exp_bytes: [
1484+ 34 , 65 , 51 , 64 , 49 , 139 , 115 , 189 , 185 , 246 , 70 , 225 , 168 , 193 , 217 , 195 , 47 ,
1485+ 66 , 179 , 240 , 153 , 24 , 114 , 215 , 144 , 196 , 212 , 41 , 39 , 155 , 246 , 25 ,
1486+ ] ,
1487+ } ,
1488+ TestCase {
1489+ txid: Txid :: from_str(
1490+ "70a8639bc9b743c0610d1231103a2f8e99f4a25670946b91f16c55a5373b37d1" ,
1491+ )
1492+ . unwrap( ) ,
1493+ block_height: 630001 ,
1494+ exp_pos: 25 ,
1495+ exp_bytes: [
1496+ 169 , 100 , 34 , 99 , 168 , 101 , 25 , 168 , 184 , 90 , 77 , 50 , 151 , 245 , 130 , 101 , 193 ,
1497+ 229 , 136 , 128 , 63 , 110 , 241 , 19 , 242 , 59 , 184 , 137 , 245 , 249 , 188 , 110 ,
1498+ ] ,
1499+ } ,
1500+ TestCase {
1501+ txid: Txid :: from_str(
1502+ "a0db149ace545beabbd87a8d6b20ffd6aa3b5a50e58add49a3d435f898c272cf" ,
1503+ )
1504+ . unwrap( ) ,
1505+ block_height: 840000 ,
1506+ exp_pos: 0 ,
1507+ exp_bytes: [
1508+ 43 , 184 , 95 , 75 , 0 , 75 , 230 , 218 , 84 , 247 , 102 , 193 , 124 , 30 , 133 , 81 , 135 , 50 ,
1509+ 113 , 18 , 194 , 49 , 239 , 47 , 243 , 94 , 186 , 208 , 234 , 103 , 198 , 158 ,
1510+ ] ,
1511+ } ,
1512+ ] ;
1513+
1514+ let txids_and_heights: Vec < ( Txid , usize ) > = test_cases
1515+ . iter ( )
1516+ . map ( |case| ( case. txid , case. block_height ) )
1517+ . collect ( ) ;
1518+
1519+ let resp = client
1520+ . batch_transaction_get_merkle ( & txids_and_heights)
1521+ . unwrap ( ) ;
1522+
1523+ for ( i, ( res, test_case) ) in resp. iter ( ) . zip ( test_cases) . enumerate ( ) {
1524+ assert_eq ! ( res. block_height, test_case. block_height) ;
1525+ assert_eq ! ( res. pos, test_case. exp_pos) ;
1526+ assert_eq ! ( res. merkle. len( ) , 12 ) ;
1527+ assert_eq ! ( res. merkle[ 0 ] , test_case. exp_bytes) ;
1528+
1529+ // Check we can verify the merkle proof validity, but fail if we supply wrong data.
1530+ let block_header = client. block_header ( res. block_height ) . unwrap ( ) ;
1531+ assert ! ( utils:: validate_merkle_proof(
1532+ & txids_and_heights[ i] . 0 ,
1533+ & block_header. merkle_root,
1534+ res
1535+ ) ) ;
1536+
1537+ let mut fail_res = res. clone ( ) ;
1538+ fail_res. pos = 13 ;
1539+ assert ! ( !utils:: validate_merkle_proof(
1540+ & txids_and_heights[ i] . 0 ,
1541+ & block_header. merkle_root,
1542+ & fail_res
1543+ ) ) ;
1544+
1545+ let fail_block_header = client. block_header ( res. block_height + 1 ) . unwrap ( ) ;
1546+ assert ! ( !utils:: validate_merkle_proof(
1547+ & txids_and_heights[ i] . 0 ,
1548+ & fail_block_header. merkle_root,
1549+ res
1550+ ) ) ;
1551+ }
1552+ }
1553+
14511554 #[ test]
14521555 fn test_txid_from_pos ( ) {
14531556 use bitcoin:: Txid ;
0 commit comments