@@ -1411,3 +1411,164 @@ impl std::fmt::Display for HttpError {
14111411 write ! ( f, "status_code: {}, contents: {}" , self . status_code, contents)
14121412 }
14131413}
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( 20 ) ) ]
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