@@ -1411,3 +1411,164 @@ impl std::fmt::Display for HttpError {
1411
1411
write ! ( f, "status_code: {}, contents: {}" , self . status_code, contents)
1412
1412
}
1413
1413
}
1414
+
1415
+ #[ cfg( test) ]
1416
+ mod tests {
1417
+ use bitcoin:: hashes:: Hash ;
1418
+ use bitcoin:: { FeeRate , OutPoint , ScriptBuf , Transaction , TxIn , TxOut , Txid , Witness } ;
1419
+ use lightning_block_sync:: http:: JsonResponse ;
1420
+ use proptest:: { arbitrary:: any, collection:: vec, prop_assert_eq, prop_compose, proptest} ;
1421
+ use serde_json:: json;
1422
+
1423
+ use crate :: chain:: bitcoind:: {
1424
+ FeeResponse , GetMempoolEntryResponse , GetRawMempoolResponse , GetRawTransactionResponse ,
1425
+ MempoolMinFeeResponse ,
1426
+ } ;
1427
+
1428
+ prop_compose ! {
1429
+ fn arbitrary_witness( ) (
1430
+ witness_elements in vec( vec( any:: <u8 >( ) , 0 ..100 ) , 0 ..20 )
1431
+ ) -> Witness {
1432
+ let mut witness = Witness :: new( ) ;
1433
+ for element in witness_elements {
1434
+ witness. push( element) ;
1435
+ }
1436
+ witness
1437
+ }
1438
+ }
1439
+
1440
+ prop_compose ! {
1441
+ fn arbitrary_txin( ) (
1442
+ outpoint_hash in any:: <[ u8 ; 32 ] >( ) ,
1443
+ outpoint_vout in any:: <u32 >( ) ,
1444
+ script_bytes in vec( any:: <u8 >( ) , 0 ..100 ) ,
1445
+ witness in arbitrary_witness( ) ,
1446
+ sequence in any:: <u32 >( )
1447
+ ) -> TxIn {
1448
+ TxIn {
1449
+ previous_output: OutPoint {
1450
+ txid: Txid :: from_byte_array( outpoint_hash) ,
1451
+ vout: outpoint_vout,
1452
+ } ,
1453
+ script_sig: ScriptBuf :: from_bytes( script_bytes) ,
1454
+ sequence: bitcoin:: Sequence :: from_consensus( sequence) ,
1455
+ witness,
1456
+ }
1457
+ }
1458
+ }
1459
+
1460
+ prop_compose ! {
1461
+ fn arbitrary_txout( ) (
1462
+ value in 0u64 ..21_000_000_00_000_000u64 ,
1463
+ script_bytes in vec( any:: <u8 >( ) , 0 ..100 )
1464
+ ) -> TxOut {
1465
+ TxOut {
1466
+ value: bitcoin:: Amount :: from_sat( value) ,
1467
+ script_pubkey: ScriptBuf :: from_bytes( script_bytes) ,
1468
+ }
1469
+ }
1470
+ }
1471
+
1472
+ prop_compose ! {
1473
+ fn arbitrary_transaction( ) (
1474
+ version in any:: <i32 >( ) ,
1475
+ inputs in vec( arbitrary_txin( ) , 1 ..20 ) ,
1476
+ outputs in vec( arbitrary_txout( ) , 1 ..20 ) ,
1477
+ lock_time in any:: <u32 >( )
1478
+ ) -> Transaction {
1479
+ Transaction {
1480
+ version: bitcoin:: transaction:: Version ( version) ,
1481
+ input: inputs,
1482
+ output: outputs,
1483
+ lock_time: bitcoin:: absolute:: LockTime :: from_consensus( lock_time) ,
1484
+ }
1485
+ }
1486
+ }
1487
+
1488
+ proptest ! {
1489
+ #![ proptest_config( proptest:: test_runner:: Config :: with_cases( 250 ) ) ]
1490
+
1491
+ #[ test]
1492
+ fn prop_get_raw_mempool_response_roundtrip( txids in vec( any:: <[ u8 ; 32 ] >( ) , 0 ..10 ) ) {
1493
+ let txid_vec: Vec <Txid > = txids. into_iter( ) . map( Txid :: from_byte_array) . collect( ) ;
1494
+ let original = GetRawMempoolResponse ( txid_vec. clone( ) ) ;
1495
+
1496
+ let json_vec: Vec <String > = txid_vec. iter( ) . map( |t| t. to_string( ) ) . collect( ) ;
1497
+ let json_val = serde_json:: Value :: Array ( json_vec. iter( ) . map( |s| json!( s) ) . collect( ) ) ;
1498
+
1499
+ let resp = JsonResponse ( json_val) ;
1500
+ let decoded: GetRawMempoolResponse = resp. try_into( ) . unwrap( ) ;
1501
+
1502
+ prop_assert_eq!( original. 0 . len( ) , decoded. 0 . len( ) ) ;
1503
+
1504
+ prop_assert_eq!( original. 0 , decoded. 0 ) ;
1505
+ }
1506
+
1507
+ #[ test]
1508
+ fn prop_get_mempool_entry_response_roundtrip(
1509
+ time in any:: <u64 >( ) ,
1510
+ height in any:: <u32 >( )
1511
+ ) {
1512
+ let json_val = json!( {
1513
+ "time" : time,
1514
+ "height" : height
1515
+ } ) ;
1516
+
1517
+ let resp = JsonResponse ( json_val) ;
1518
+ let decoded: GetMempoolEntryResponse = resp. try_into( ) . unwrap( ) ;
1519
+
1520
+ prop_assert_eq!( decoded. time, time) ;
1521
+ prop_assert_eq!( decoded. height, height) ;
1522
+ }
1523
+
1524
+ #[ test]
1525
+ fn prop_get_raw_transaction_response_roundtrip( tx in arbitrary_transaction( ) ) {
1526
+ let hex = bitcoin:: consensus:: encode:: serialize_hex( & tx) ;
1527
+ let json_val = serde_json:: Value :: String ( hex. clone( ) ) ;
1528
+
1529
+ let resp = JsonResponse ( json_val) ;
1530
+ let decoded: GetRawTransactionResponse = resp. try_into( ) . unwrap( ) ;
1531
+
1532
+ prop_assert_eq!( decoded. 0 . compute_txid( ) , tx. compute_txid( ) ) ;
1533
+ prop_assert_eq!( decoded. 0 . compute_wtxid( ) , tx. compute_wtxid( ) ) ;
1534
+
1535
+ prop_assert_eq!( decoded. 0 , tx) ;
1536
+ }
1537
+
1538
+ #[ test]
1539
+ fn prop_fee_response_roundtrip( fee_rate in any:: <f64 >( ) ) {
1540
+ let fee_rate = fee_rate. abs( ) ;
1541
+ let json_val = json!( {
1542
+ "feerate" : fee_rate,
1543
+ "errors" : serde_json:: Value :: Null
1544
+ } ) ;
1545
+
1546
+ let resp = JsonResponse ( json_val) ;
1547
+ let decoded: FeeResponse = resp. try_into( ) . unwrap( ) ;
1548
+
1549
+ let expected = {
1550
+ let fee_rate_sat_per_kwu = ( fee_rate * 25_000_000.0 ) . round( ) as u64 ;
1551
+ FeeRate :: from_sat_per_kwu( fee_rate_sat_per_kwu)
1552
+ } ;
1553
+ prop_assert_eq!( decoded. 0 , expected) ;
1554
+ }
1555
+
1556
+ #[ test]
1557
+ fn prop_mempool_min_fee_response_roundtrip( fee_rate in any:: <f64 >( ) ) {
1558
+ let fee_rate = fee_rate. abs( ) ;
1559
+ let json_val = json!( {
1560
+ "mempoolminfee" : fee_rate
1561
+ } ) ;
1562
+
1563
+ let resp = JsonResponse ( json_val) ;
1564
+ let decoded: MempoolMinFeeResponse = resp. try_into( ) . unwrap( ) ;
1565
+
1566
+ let expected = {
1567
+ let fee_rate_sat_per_kwu = ( fee_rate * 25_000_000.0 ) . round( ) as u64 ;
1568
+ FeeRate :: from_sat_per_kwu( fee_rate_sat_per_kwu)
1569
+ } ;
1570
+ prop_assert_eq!( decoded. 0 , expected) ;
1571
+ }
1572
+
1573
+ }
1574
+ }
0 commit comments