@@ -1125,6 +1125,17 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
1125
1125
Ok ( serde_json:: from_value ( result) ?)
1126
1126
}
1127
1127
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
+
1128
1139
fn txid_from_pos ( & self , height : usize , tx_pos : usize ) -> Result < Txid , Error > {
1129
1140
let params = vec ! [ Param :: Usize ( height) , Param :: Usize ( tx_pos) ] ;
1130
1141
let req = Request :: new_id (
@@ -1471,6 +1482,98 @@ mod test {
1471
1482
) ) ;
1472
1483
}
1473
1484
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
+
1474
1577
#[ test]
1475
1578
fn test_txid_from_pos ( ) {
1476
1579
use bitcoin:: Txid ;
0 commit comments