@@ -1125,6 +1125,17 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
11251125 Ok ( serde_json:: from_value ( result) ?)
11261126 }
11271127
1128+ fn batch_transaction_get_merkle < I > (
1129+ & self ,
1130+ txids_and_heights : I ,
1131+ ) -> Result < Vec < GetMerkleRes > , Error >
1132+ where
1133+ I : IntoIterator + Clone ,
1134+ I :: Item : Borrow < ( Txid , usize ) > ,
1135+ {
1136+ impl_batch_call ! ( self , txids_and_heights, transaction_get_merkle)
1137+ }
1138+
11281139 fn txid_from_pos ( & self , height : usize , tx_pos : usize ) -> Result < Txid , Error > {
11291140 let params = vec ! [ Param :: Usize ( height) , Param :: Usize ( tx_pos) ] ;
11301141 let req = Request :: new_id (
@@ -1471,6 +1482,98 @@ mod test {
14711482 ) ) ;
14721483 }
14731484
1485+ #[ test]
1486+ fn test_batch_transaction_get_merkle ( ) {
1487+ use bitcoin:: Txid ;
1488+
1489+ struct TestCase {
1490+ txid : Txid ,
1491+ block_height : usize ,
1492+ exp_pos : usize ,
1493+ exp_bytes : [ u8 ; 32 ] ,
1494+ }
1495+
1496+ let client = RawClient :: new ( get_test_server ( ) , None ) . unwrap ( ) ;
1497+
1498+ let test_cases: Vec < TestCase > = vec ! [
1499+ TestCase {
1500+ txid: Txid :: from_str(
1501+ "1f7ff3c407f33eabc8bec7d2cc230948f2249ec8e591bcf6f971ca9366c8788d" ,
1502+ )
1503+ . unwrap( ) ,
1504+ block_height: 630000 ,
1505+ exp_pos: 68 ,
1506+ exp_bytes: [
1507+ 34 , 65 , 51 , 64 , 49 , 139 , 115 , 189 , 185 , 246 , 70 , 225 , 168 , 193 , 217 , 195 , 47 ,
1508+ 66 , 179 , 240 , 153 , 24 , 114 , 215 , 144 , 196 , 212 , 41 , 39 , 155 , 246 , 25 ,
1509+ ] ,
1510+ } ,
1511+ TestCase {
1512+ txid: Txid :: from_str(
1513+ "70a8639bc9b743c0610d1231103a2f8e99f4a25670946b91f16c55a5373b37d1" ,
1514+ )
1515+ . unwrap( ) ,
1516+ block_height: 630001 ,
1517+ exp_pos: 25 ,
1518+ exp_bytes: [
1519+ 169 , 100 , 34 , 99 , 168 , 101 , 25 , 168 , 184 , 90 , 77 , 50 , 151 , 245 , 130 , 101 , 193 ,
1520+ 229 , 136 , 128 , 63 , 110 , 241 , 19 , 242 , 59 , 184 , 137 , 245 , 249 , 188 , 110 ,
1521+ ] ,
1522+ } ,
1523+ TestCase {
1524+ txid: Txid :: from_str(
1525+ "a0db149ace545beabbd87a8d6b20ffd6aa3b5a50e58add49a3d435f898c272cf" ,
1526+ )
1527+ . unwrap( ) ,
1528+ block_height: 840000 ,
1529+ exp_pos: 0 ,
1530+ exp_bytes: [
1531+ 43 , 184 , 95 , 75 , 0 , 75 , 230 , 218 , 84 , 247 , 102 , 193 , 124 , 30 , 133 , 81 , 135 , 50 ,
1532+ 113 , 18 , 194 , 49 , 239 , 47 , 243 , 94 , 186 , 208 , 234 , 103 , 198 , 158 ,
1533+ ] ,
1534+ } ,
1535+ ] ;
1536+
1537+ let txids_and_heights: Vec < ( Txid , usize ) > = test_cases
1538+ . iter ( )
1539+ . map ( |case| ( case. txid , case. block_height ) )
1540+ . collect ( ) ;
1541+
1542+ let resp = client
1543+ . batch_transaction_get_merkle ( & txids_and_heights)
1544+ . unwrap ( ) ;
1545+
1546+ for ( i, ( res, test_case) ) in resp. iter ( ) . zip ( test_cases) . enumerate ( ) {
1547+ assert_eq ! ( res. block_height, test_case. block_height) ;
1548+ assert_eq ! ( res. pos, test_case. exp_pos) ;
1549+ assert_eq ! ( res. merkle. len( ) , 12 ) ;
1550+ assert_eq ! ( res. merkle[ 0 ] , test_case. exp_bytes) ;
1551+
1552+ // Check we can verify the merkle proof validity, but fail if we supply wrong data.
1553+ let block_header = client. block_header ( res. block_height ) . unwrap ( ) ;
1554+ assert ! ( utils:: validate_merkle_proof(
1555+ & txids_and_heights[ i] . 0 ,
1556+ & block_header. merkle_root,
1557+ res
1558+ ) ) ;
1559+
1560+ let mut fail_res = res. clone ( ) ;
1561+ fail_res. pos = 13 ;
1562+ assert ! ( !utils:: validate_merkle_proof(
1563+ & txids_and_heights[ i] . 0 ,
1564+ & block_header. merkle_root,
1565+ & fail_res
1566+ ) ) ;
1567+
1568+ let fail_block_header = client. block_header ( res. block_height + 1 ) . unwrap ( ) ;
1569+ assert ! ( !utils:: validate_merkle_proof(
1570+ & txids_and_heights[ i] . 0 ,
1571+ & fail_block_header. merkle_root,
1572+ res
1573+ ) ) ;
1574+ }
1575+ }
1576+
14741577 #[ test]
14751578 fn test_txid_from_pos ( ) {
14761579 use bitcoin:: Txid ;
0 commit comments