Skip to content

Commit aa3691d

Browse files
committed
Merge #760: feature: improve context err
faf16fd feat: unify err msg to contain helpful info (ChrisCho-H) 919bc4b fix: use ImpossibleSatisfaction when op_count is None (ChrisCho-H) Pull request description: 919bc4b - use `ImpossibleSatisfaction` when op_count is None instead of `MaxOpCountExceeded`. 51a50ae - unify error message for satisfaction-kind error and scriptPubKey-kind error so that these error can contain max(limit) with what it got(actual). ACKs for top commit: apoelstra: ACK faf16fd; successfully ran local tests Tree-SHA512: bd2b88c297af6a333c6155ef9eb9103c303e8b6e7df62f78b5c337721c0deefc601a307027fafe50b95bcbcde73594b5a822a0d89a9e869720755dba4f9fdeaf
2 parents 0f03df0 + faf16fd commit aa3691d

File tree

2 files changed

+62
-36
lines changed

2 files changed

+62
-36
lines changed

src/miniscript/context.rs

+60-34
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,19 @@ pub enum ScriptContextError {
4545
MaxWitnessItemsExceeded { actual: usize, limit: usize },
4646
/// At least one satisfaction path in the Miniscript fragment contains more
4747
/// than `MAX_OPS_PER_SCRIPT`(201) opcodes.
48-
MaxOpCountExceeded,
48+
MaxOpCountExceeded { actual: usize, limit: usize },
4949
/// The Miniscript(under segwit context) corresponding
5050
/// Script would be larger than `MAX_STANDARD_P2WSH_SCRIPT_SIZE`,
5151
/// `MAX_SCRIPT_SIZE` or `MAX_BLOCK`(`Tap`) bytes.
5252
MaxWitnessScriptSizeExceeded { max: usize, got: usize },
5353
/// The Miniscript (under p2sh context) corresponding Script would be
5454
/// larger than `MAX_SCRIPT_ELEMENT_SIZE` bytes.
55-
MaxRedeemScriptSizeExceeded,
55+
MaxRedeemScriptSizeExceeded { max: usize, got: usize },
5656
/// The Miniscript(under bare context) corresponding
5757
/// Script would be larger than `MAX_SCRIPT_SIZE` bytes.
58-
MaxBareScriptSizeExceeded,
58+
MaxBareScriptSizeExceeded { max: usize, got: usize },
5959
/// The policy rules of bitcoin core only permit Script size upto 1650 bytes
60-
MaxScriptSigSizeExceeded,
60+
MaxScriptSigSizeExceeded { actual: usize, limit: usize },
6161
/// Impossible to satisfy the miniscript under the current context
6262
ImpossibleSatisfaction,
6363
/// No Multi Node in Taproot context
@@ -81,11 +81,11 @@ impl error::Error for ScriptContextError {
8181
| XOnlyKeysNotAllowed(_, _)
8282
| UncompressedKeysNotAllowed
8383
| MaxWitnessItemsExceeded { .. }
84-
| MaxOpCountExceeded
84+
| MaxOpCountExceeded { .. }
8585
| MaxWitnessScriptSizeExceeded { .. }
86-
| MaxRedeemScriptSizeExceeded
87-
| MaxBareScriptSizeExceeded
88-
| MaxScriptSigSizeExceeded
86+
| MaxRedeemScriptSizeExceeded { .. }
87+
| MaxBareScriptSizeExceeded { .. }
88+
| MaxScriptSigSizeExceeded { .. }
8989
| ImpossibleSatisfaction
9090
| TaprootMultiDisabled
9191
| StackSizeLimitExceeded { .. }
@@ -113,35 +113,39 @@ impl fmt::Display for ScriptContextError {
113113
}
114114
ScriptContextError::MaxWitnessItemsExceeded { actual, limit } => write!(
115115
f,
116-
"At least one spending path in the Miniscript fragment has {} more \
117-
witness items than limit {}.",
116+
"At least one satisfaction path in the Miniscript fragment has {} witness items \
117+
(limit: {}).",
118118
actual, limit
119119
),
120-
ScriptContextError::MaxOpCountExceeded => write!(
120+
ScriptContextError::MaxOpCountExceeded { actual, limit } => write!(
121121
f,
122-
"At least one satisfaction path in the Miniscript fragment contains \
123-
more than MAX_OPS_PER_SCRIPT opcodes."
122+
"At least one satisfaction path in the Miniscript fragment contains {} opcodes \
123+
(limit: {}).",
124+
actual, limit
124125
),
125126
ScriptContextError::MaxWitnessScriptSizeExceeded { max, got } => write!(
126127
f,
127128
"The Miniscript corresponding Script cannot be larger than \
128-
{} bytes, but got {} bytes.",
129+
{} bytes, but got {} bytes.",
129130
max, got
130131
),
131-
ScriptContextError::MaxRedeemScriptSizeExceeded => write!(
132+
ScriptContextError::MaxRedeemScriptSizeExceeded { max, got } => write!(
132133
f,
133-
"The Miniscript corresponding Script would be larger than \
134-
MAX_SCRIPT_ELEMENT_SIZE bytes."
134+
"The Miniscript corresponding Script cannot be larger than \
135+
{} bytes, but got {} bytes.",
136+
max, got
135137
),
136-
ScriptContextError::MaxBareScriptSizeExceeded => write!(
138+
ScriptContextError::MaxBareScriptSizeExceeded { max, got } => write!(
137139
f,
138-
"The Miniscript corresponding Script would be larger than \
139-
MAX_SCRIPT_SIZE bytes."
140+
"The Miniscript corresponding Script cannot be larger than \
141+
{} bytes, but got {} bytes.",
142+
max, got
140143
),
141-
ScriptContextError::MaxScriptSigSizeExceeded => write!(
144+
ScriptContextError::MaxScriptSigSizeExceeded { actual, limit } => write!(
142145
f,
143-
"At least one satisfaction in Miniscript would be larger than \
144-
MAX_SCRIPTSIG_SIZE scriptsig"
146+
"At least one satisfaction path in the Miniscript fragment has {} bytes \
147+
(limit: {}).",
148+
actual, limit
145149
),
146150
ScriptContextError::ImpossibleSatisfaction => {
147151
write!(f, "Impossible to satisfy Miniscript under the current context")
@@ -396,8 +400,12 @@ impl ScriptContext for Legacy {
396400
fn check_witness(witness: &[Vec<u8>]) -> Result<(), ScriptContextError> {
397401
// In future, we could avoid by having a function to count only
398402
// len of script instead of converting it.
399-
if witness_to_scriptsig(witness).len() > MAX_SCRIPTSIG_SIZE {
400-
return Err(ScriptContextError::MaxScriptSigSizeExceeded);
403+
let script_sig = witness_to_scriptsig(witness);
404+
if script_sig.len() > MAX_SCRIPTSIG_SIZE {
405+
return Err(ScriptContextError::MaxScriptSigSizeExceeded {
406+
actual: script_sig.len(),
407+
limit: MAX_SCRIPTSIG_SIZE,
408+
});
401409
}
402410
Ok(())
403411
}
@@ -421,7 +429,10 @@ impl ScriptContext for Legacy {
421429
match node_checked {
422430
Ok(_) => {
423431
if ms.ext.pk_cost > MAX_SCRIPT_ELEMENT_SIZE {
424-
Err(ScriptContextError::MaxRedeemScriptSizeExceeded)
432+
Err(ScriptContextError::MaxRedeemScriptSizeExceeded {
433+
max: MAX_SCRIPT_ELEMENT_SIZE,
434+
got: ms.ext.pk_cost,
435+
})
425436
} else {
426437
Ok(())
427438
}
@@ -434,9 +445,12 @@ impl ScriptContext for Legacy {
434445
ms: &Miniscript<Pk, Self>,
435446
) -> Result<(), ScriptContextError> {
436447
match ms.ext.ops.op_count() {
437-
None => Err(ScriptContextError::MaxOpCountExceeded),
448+
None => Err(ScriptContextError::ImpossibleSatisfaction),
438449
Some(op_count) if op_count > MAX_OPS_PER_SCRIPT => {
439-
Err(ScriptContextError::MaxOpCountExceeded)
450+
Err(ScriptContextError::MaxOpCountExceeded {
451+
actual: op_count,
452+
limit: MAX_OPS_PER_SCRIPT,
453+
})
440454
}
441455
_ => Ok(()),
442456
}
@@ -451,7 +465,10 @@ impl ScriptContext for Legacy {
451465
match ms.max_satisfaction_size() {
452466
Err(_e) => Err(ScriptContextError::ImpossibleSatisfaction),
453467
Ok(size) if size > MAX_SCRIPTSIG_SIZE => {
454-
Err(ScriptContextError::MaxScriptSigSizeExceeded)
468+
Err(ScriptContextError::MaxScriptSigSizeExceeded {
469+
actual: size,
470+
limit: MAX_SCRIPTSIG_SIZE,
471+
})
455472
}
456473
_ => Ok(()),
457474
}
@@ -543,9 +560,12 @@ impl ScriptContext for Segwitv0 {
543560
ms: &Miniscript<Pk, Self>,
544561
) -> Result<(), ScriptContextError> {
545562
match ms.ext.ops.op_count() {
546-
None => Err(ScriptContextError::MaxOpCountExceeded),
563+
None => Err(ScriptContextError::ImpossibleSatisfaction),
547564
Some(op_count) if op_count > MAX_OPS_PER_SCRIPT => {
548-
Err(ScriptContextError::MaxOpCountExceeded)
565+
Err(ScriptContextError::MaxOpCountExceeded {
566+
actual: op_count,
567+
limit: MAX_OPS_PER_SCRIPT,
568+
})
549569
}
550570
_ => Ok(()),
551571
}
@@ -760,7 +780,10 @@ impl ScriptContext for BareCtx {
760780
match node_checked {
761781
Ok(_) => {
762782
if ms.ext.pk_cost > MAX_SCRIPT_SIZE {
763-
Err(ScriptContextError::MaxBareScriptSizeExceeded)
783+
Err(ScriptContextError::MaxBareScriptSizeExceeded {
784+
max: MAX_SCRIPT_SIZE,
785+
got: ms.ext.pk_cost,
786+
})
764787
} else {
765788
Ok(())
766789
}
@@ -773,9 +796,12 @@ impl ScriptContext for BareCtx {
773796
ms: &Miniscript<Pk, Self>,
774797
) -> Result<(), ScriptContextError> {
775798
match ms.ext.ops.op_count() {
776-
None => Err(ScriptContextError::MaxOpCountExceeded),
799+
None => Err(ScriptContextError::ImpossibleSatisfaction),
777800
Some(op_count) if op_count > MAX_OPS_PER_SCRIPT => {
778-
Err(ScriptContextError::MaxOpCountExceeded)
801+
Err(ScriptContextError::MaxOpCountExceeded {
802+
actual: op_count,
803+
limit: MAX_OPS_PER_SCRIPT,
804+
})
779805
}
780806
_ => Ok(()),
781807
}

src/miniscript/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1686,15 +1686,15 @@ mod tests {
16861686
// Should panic for exceeding the max consensus size, as multi properly used
16871687
assert_eq!(
16881688
legacy_multi_ms.unwrap_err().to_string(),
1689-
"The Miniscript corresponding Script would be larger than MAX_SCRIPT_ELEMENT_SIZE bytes."
1689+
"The Miniscript corresponding Script cannot be larger than 520 bytes, but got 685 bytes."
16901690
);
16911691
assert_eq!(
16921692
segwit_multi_ms.unwrap_err().to_string(),
16931693
"The Miniscript corresponding Script cannot be larger than 3600 bytes, but got 4110 bytes."
16941694
);
16951695
assert_eq!(
16961696
bare_multi_ms.unwrap_err().to_string(),
1697-
"The Miniscript corresponding Script would be larger than MAX_SCRIPT_SIZE bytes."
1697+
"The Miniscript corresponding Script cannot be larger than 10000 bytes, but got 10275 bytes."
16981698
);
16991699
}
17001700
}

0 commit comments

Comments
 (0)