@@ -1165,7 +1165,7 @@ mod tests {
11651165 use std:: str:: FromStr ;
11661166 use std:: string:: String ;
11671167
1168- use miniscript:: { satisfy, Segwitv0 } ;
1168+ use miniscript:: { satisfy, Legacy , Segwitv0 } ;
11691169 use policy:: Liftable ;
11701170 use script_num_size;
11711171 use BitcoinSig ;
@@ -1469,6 +1469,99 @@ mod tests {
14691469 } ;
14701470 }
14711471 }
1472+
1473+ #[ test]
1474+ fn segwit_limits ( ) {
1475+ // Hit the maximum witness script size limit.
1476+ // or(thresh(52, [pubkey; 52]), thresh(52, [pubkey; 52])) results in a 3642-bytes long
1477+ // witness script with only 54 stack elements
1478+ let ( keys, _) = pubkeys_and_a_sig ( 104 ) ;
1479+ let keys_a: Vec < Concrete < bitcoin:: PublicKey > > = keys[ ..keys. len ( ) / 2 ]
1480+ . iter ( )
1481+ . map ( |pubkey| Concrete :: Key ( * pubkey) )
1482+ . collect ( ) ;
1483+ let keys_b: Vec < Concrete < bitcoin:: PublicKey > > = keys[ keys. len ( ) / 2 ..]
1484+ . iter ( )
1485+ . map ( |pubkey| Concrete :: Key ( * pubkey) )
1486+ . collect ( ) ;
1487+
1488+ let thresh_res: Result < SegwitMiniScript , _ > = Concrete :: Or ( vec ! [
1489+ ( 1 , Concrete :: Threshold ( keys_a. len( ) , keys_a) ) ,
1490+ ( 1 , Concrete :: Threshold ( keys_b. len( ) , keys_b) ) ,
1491+ ] )
1492+ . compile ( ) ;
1493+ let script_size = thresh_res. clone ( ) . and_then ( |m| Ok ( m. script_size ( NullCtx ) ) ) ;
1494+ assert_eq ! (
1495+ thresh_res,
1496+ Err ( CompilerError :: LimitsExceeded ) ,
1497+ "Compilation succeeded with a witscript size of '{:?}'" ,
1498+ script_size,
1499+ ) ;
1500+
1501+ // Hit the maximum witness stack elements limit
1502+ let ( keys, _) = pubkeys_and_a_sig ( 100 ) ;
1503+ let keys: Vec < Concrete < bitcoin:: PublicKey > > =
1504+ keys. iter ( ) . map ( |pubkey| Concrete :: Key ( * pubkey) ) . collect ( ) ;
1505+ let thresh_res: Result < SegwitMiniScript , _ > =
1506+ Concrete :: Threshold ( keys. len ( ) , keys) . compile ( ) ;
1507+ let n_elements = thresh_res
1508+ . clone ( )
1509+ . and_then ( |m| Ok ( m. max_satisfaction_witness_elements ( ) ) ) ;
1510+ assert_eq ! (
1511+ thresh_res,
1512+ Err ( CompilerError :: LimitsExceeded ) ,
1513+ "Compilation succeeded with '{:?}' elements" ,
1514+ n_elements,
1515+ ) ;
1516+ }
1517+
1518+ #[ test]
1519+ fn shared_limits ( ) {
1520+ // Test the maximum number of OPs with a 67-of-68 multisig
1521+ let ( keys, _) = pubkeys_and_a_sig ( 68 ) ;
1522+ let keys: Vec < Concrete < bitcoin:: PublicKey > > =
1523+ keys. iter ( ) . map ( |pubkey| Concrete :: Key ( * pubkey) ) . collect ( ) ;
1524+ let thresh_res: Result < SegwitMiniScript , _ > =
1525+ Concrete :: Threshold ( keys. len ( ) - 1 , keys) . compile ( ) ;
1526+ let ops_count = thresh_res. clone ( ) . and_then ( |m| Ok ( m. ext . ops_count_sat ) ) ;
1527+ assert_eq ! (
1528+ thresh_res,
1529+ Err ( CompilerError :: LimitsExceeded ) ,
1530+ "Compilation succeeded with '{:?}' OP count (sat)" ,
1531+ ops_count,
1532+ ) ;
1533+ // For legacy too..
1534+ let ( keys, _) = pubkeys_and_a_sig ( 68 ) ;
1535+ let keys: Vec < Concrete < bitcoin:: PublicKey > > =
1536+ keys. iter ( ) . map ( |pubkey| Concrete :: Key ( * pubkey) ) . collect ( ) ;
1537+ let thresh_res = Concrete :: Threshold ( keys. len ( ) - 1 , keys) . compile :: < Legacy > ( ) ;
1538+ let ops_count = thresh_res. clone ( ) . and_then ( |m| Ok ( m. ext . ops_count_sat ) ) ;
1539+ assert_eq ! (
1540+ thresh_res,
1541+ Err ( CompilerError :: LimitsExceeded ) ,
1542+ "Compilation succeeded with '{:?}' OP count (sat)" ,
1543+ ops_count,
1544+ ) ;
1545+
1546+ // Test that we refuse to compile policies with duplicated keys
1547+ let ( keys, _) = pubkeys_and_a_sig ( 1 ) ;
1548+ let key = Concrete :: Key ( keys[ 0 ] ) ;
1549+ let res = Concrete :: Or ( vec ! [ ( 1 , key. clone( ) ) , ( 1 , key. clone( ) ) ] ) . compile :: < Segwitv0 > ( ) ;
1550+ assert_eq ! (
1551+ res,
1552+ Err ( CompilerError :: PolicyError (
1553+ policy:: concrete:: PolicyError :: DuplicatePubKeys
1554+ ) )
1555+ ) ;
1556+ // Same for legacy
1557+ let res = Concrete :: Or ( vec ! [ ( 1 , key. clone( ) ) , ( 1 , key) ] ) . compile :: < Legacy > ( ) ;
1558+ assert_eq ! (
1559+ res,
1560+ Err ( CompilerError :: PolicyError (
1561+ policy:: concrete:: PolicyError :: DuplicatePubKeys
1562+ ) )
1563+ ) ;
1564+ }
14721565}
14731566
14741567#[ cfg( all( test, feature = "unstable" ) ) ]
0 commit comments