Skip to content

Commit e9732e4

Browse files
authored
Merge pull request #207 from darosior/segwit_limits_tests
Test Segwit standard limitation
2 parents 4501216 + 0d9fa8e commit e9732e4

File tree

2 files changed

+95
-2
lines changed

2 files changed

+95
-2
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "miniscript"
3-
version = "4.0.2"
3+
version = "4.0.3"
44
authors = ["Andrew Poelstra <[email protected]>, Sanket Kanjalkar <[email protected]>"]
55
repository = "https://github.com/apoelstra/miniscript"
66
description = "Miniscript: a subset of Bitcoin Script designed for analysis"

src/policy/compiler.rs

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)