@@ -1165,7 +1165,7 @@ mod tests {
1165
1165
use std:: str:: FromStr ;
1166
1166
use std:: string:: String ;
1167
1167
1168
- use miniscript:: { satisfy, Segwitv0 } ;
1168
+ use miniscript:: { satisfy, Legacy , Segwitv0 } ;
1169
1169
use policy:: Liftable ;
1170
1170
use script_num_size;
1171
1171
use BitcoinSig ;
@@ -1469,6 +1469,99 @@ mod tests {
1469
1469
} ;
1470
1470
}
1471
1471
}
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
+ }
1472
1565
}
1473
1566
1474
1567
#[ cfg( all( test, feature = "unstable" ) ) ]
0 commit comments