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