@@ -1407,3 +1407,164 @@ impl std::fmt::Display for HttpError {
14071407 write ! ( f, "status_code: {}, contents: {}" , self . status_code, contents)
14081408 }
14091409}
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