Handling CHECKMULTISIG(VERIFY) ops in TapScript context; refactoring classifier
This commit is contained in:
parent
b0ad6748e4
commit
c75f3ef4a8
|
@ -674,77 +674,62 @@ impl All {
|
||||||
/// Classifies an Opcode into a broad class
|
/// Classifies an Opcode into a broad class
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn classify(self, ctx: ClassifyContext) -> Class {
|
pub fn classify(self, ctx: ClassifyContext) -> Class {
|
||||||
// 3 opcodes
|
use self::all::*;
|
||||||
match ctx {
|
match (self, ctx) {
|
||||||
ClassifyContext::TapScript => // 3 opcodes
|
// 3 opcodes illegal in all contexts
|
||||||
if self == all::OP_VERIF || self == all::OP_VERNOTIF ||
|
(OP_VERIF, _) | (OP_VERNOTIF, _) | (OP_INVALIDOPCODE, _) => Class::IllegalOp,
|
||||||
self == all::OP_INVALIDOPCODE {
|
|
||||||
Class::IllegalOp
|
// 15 opcodes illegal in Legacy context
|
||||||
// 11 opcodes
|
(OP_CAT, ctx) | (OP_SUBSTR, ctx)
|
||||||
} else if self == all::OP_NOP ||
|
| (OP_LEFT, ctx) | (OP_RIGHT, ctx)
|
||||||
(all::OP_NOP1.code <= self.code &&
|
| (OP_INVERT, ctx)
|
||||||
self.code <= all::OP_NOP10.code) {
|
| (OP_AND, ctx) | (OP_OR, ctx) | (OP_XOR, ctx)
|
||||||
Class::NoOp
|
| (OP_2MUL, ctx) | (OP_2DIV, ctx)
|
||||||
// 87 opcodes
|
| (OP_MUL, ctx) | (OP_DIV, ctx) | (OP_MOD, ctx)
|
||||||
} else if self.code == 80 || self.code == 98 ||
|
| (OP_LSHIFT, ctx) | (OP_RSHIFT, ctx) if ctx == ClassifyContext::Legacy => Class::IllegalOp,
|
||||||
(self.code >= 126 && self.code <= 129) ||
|
|
||||||
(self.code >= 131 && self.code <= 134) ||
|
// 87 opcodes of SuccessOp class only in TapScript context
|
||||||
(self.code >= 137 && self.code <= 138) ||
|
(op, ClassifyContext::TapScript)
|
||||||
(self.code >= 141 && self.code <= 142) ||
|
if op.code == 80 || op.code == 98 ||
|
||||||
(self.code >= 149 && self.code <= 153) ||
|
(op.code >= 126 && op.code <= 129) ||
|
||||||
(self.code >= 187 && self.code <= 254) {
|
(op.code >= 131 && op.code <= 134) ||
|
||||||
Class::SuccessOp
|
(op.code >= 137 && op.code <= 138) ||
|
||||||
// 1 opcode
|
(op.code >= 141 && op.code <= 142) ||
|
||||||
} else if self == all::OP_RETURN{
|
(op.code >= 149 && op.code <= 153) ||
|
||||||
Class::ReturnOp
|
(op.code >= 187 && op.code <= 254) => Class::SuccessOp,
|
||||||
// 1 opcode
|
|
||||||
} else if self == all::OP_PUSHNUM_NEG1 {
|
// 11 opcodes of NoOp class
|
||||||
Class::PushNum(-1)
|
(OP_NOP, _) => Class::NoOp,
|
||||||
// 16 opcodes
|
(op, _) if op.code >= OP_NOP1.code && op.code <= OP_NOP10.code => Class::NoOp,
|
||||||
} else if all::OP_PUSHNUM_1.code <= self.code &&
|
|
||||||
self.code <= all::OP_PUSHNUM_16.code {
|
// 1 opcode for `OP_RETURN`
|
||||||
Class::PushNum(1 + self.code as i32 - all::OP_PUSHNUM_1.code as i32)
|
(OP_RETURN, _) => Class::ReturnOp,
|
||||||
// 76 opcodes
|
|
||||||
} else if self.code <= all::OP_PUSHBYTES_75.code {
|
// 4 opcodes operating equally to `OP_RETURN` only in Legacy context
|
||||||
Class::PushBytes(self.code as u32)
|
(OP_RESERVED, ctx)
|
||||||
// 61 opcodes
|
| (OP_RESERVED1, ctx) | (OP_RESERVED2, ctx)
|
||||||
} else {
|
| (OP_VER, ctx) if ctx == ClassifyContext::Legacy => Class::ReturnOp,
|
||||||
Class::Ordinary(Ordinary::try_from_all(self).unwrap())
|
|
||||||
},
|
// 71 opcodes operating equally to `OP_RETURN` only in Legacy context
|
||||||
ClassifyContext::Legacy =>
|
(op, ClassifyContext::Legacy) if op.code >= OP_CHECKSIGADD.code => Class::ReturnOp,
|
||||||
if self == all::OP_VERIF || self == all::OP_VERNOTIF ||
|
|
||||||
self == all::OP_CAT || self == all::OP_SUBSTR ||
|
// 2 opcodes operating equally to `OP_RETURN` only in TapScript context
|
||||||
self == all::OP_LEFT || self == all::OP_RIGHT ||
|
(OP_CHECKMULTISIG, ClassifyContext::TapScript)
|
||||||
self == all::OP_INVERT || self == all::OP_AND ||
|
| (OP_CHECKMULTISIGVERIFY, ClassifyContext::TapScript) => Class::ReturnOp,
|
||||||
self == all::OP_OR || self == all::OP_XOR ||
|
|
||||||
self == all::OP_2MUL || self == all::OP_2DIV ||
|
// 1 opcode of PushNum class
|
||||||
self == all::OP_MUL || self == all::OP_DIV || self == all::OP_MOD ||
|
(OP_PUSHNUM_NEG1, _) => Class::PushNum(-1),
|
||||||
self == all::OP_LSHIFT || self == all::OP_RSHIFT {
|
|
||||||
Class::IllegalOp
|
// 16 opcodes of PushNum class
|
||||||
// 11 opcodes
|
(op, _) if op.code >= OP_PUSHNUM_1.code && op.code <= OP_PUSHNUM_16.code => {
|
||||||
} else if self == all::OP_NOP ||
|
Class::PushNum(1 + self.code as i32 - OP_PUSHNUM_1.code as i32)
|
||||||
(all::OP_NOP1.code <= self.code &&
|
},
|
||||||
self.code <= all::OP_NOP10.code) {
|
|
||||||
Class::NoOp
|
// 76 opcodes of PushBytes class
|
||||||
// 75 opcodes
|
(op, _) if op.code <= OP_PUSHBYTES_75.code => Class::PushBytes(self.code as u32),
|
||||||
} else if self == all::OP_RESERVED || self == all::OP_VER || self == all::OP_RETURN ||
|
|
||||||
self == all::OP_RESERVED1 || self == all::OP_RESERVED2 ||
|
// opcodes of Ordinary class: 61 for Legacy and 60 for TapScript context
|
||||||
self.code >= all::OP_CHECKSIGADD.code {
|
(_, _) => Class::Ordinary(Ordinary::with(self)),
|
||||||
Class::ReturnOp
|
|
||||||
// 1 opcode
|
|
||||||
} else if self == all::OP_PUSHNUM_NEG1 {
|
|
||||||
Class::PushNum(-1)
|
|
||||||
// 16 opcodes
|
|
||||||
} else if all::OP_PUSHNUM_1.code <= self.code &&
|
|
||||||
self.code <= all::OP_PUSHNUM_16.code {
|
|
||||||
Class::PushNum(1 + self.code as i32 - all::OP_PUSHNUM_1.code as i32)
|
|
||||||
// 76 opcodes
|
|
||||||
} else if self.code <= all::OP_PUSHBYTES_75.code {
|
|
||||||
Class::PushBytes(self.code as u32)
|
|
||||||
// 61 opcodes
|
|
||||||
} else {
|
|
||||||
Class::Ordinary(Ordinary::try_from_all(self).unwrap())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -825,6 +810,13 @@ macro_rules! ordinary_opcode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ordinary {
|
impl Ordinary {
|
||||||
|
fn with(b: All) -> Self {
|
||||||
|
match b {
|
||||||
|
$( all::$op => { Ordinary::$op } ),*
|
||||||
|
_ => unreachable!("construction of `Ordinary` type from non-ordinary opcode {}", b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Try to create from an All
|
/// Try to create from an All
|
||||||
pub fn try_from_all(b: All) -> Option<Self> {
|
pub fn try_from_all(b: All) -> Option<Self> {
|
||||||
match b {
|
match b {
|
||||||
|
@ -890,6 +882,14 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn classify_test() {
|
fn classify_test() {
|
||||||
|
let op174 = all::OP_CHECKMULTISIG;
|
||||||
|
assert_eq!(op174.classify(ClassifyContext::Legacy), Class::Ordinary(Ordinary::OP_CHECKMULTISIG));
|
||||||
|
assert_eq!(op174.classify(ClassifyContext::TapScript), Class::ReturnOp);
|
||||||
|
|
||||||
|
let op175 = all::OP_CHECKMULTISIGVERIFY;
|
||||||
|
assert_eq!(op175.classify(ClassifyContext::Legacy), Class::Ordinary(Ordinary::OP_CHECKMULTISIGVERIFY));
|
||||||
|
assert_eq!(op175.classify(ClassifyContext::TapScript), Class::ReturnOp);
|
||||||
|
|
||||||
let op186 = all::OP_CHECKSIGADD;
|
let op186 = all::OP_CHECKSIGADD;
|
||||||
assert_eq!(op186.classify(ClassifyContext::Legacy), Class::ReturnOp);
|
assert_eq!(op186.classify(ClassifyContext::Legacy), Class::ReturnOp);
|
||||||
assert_eq!(op186.classify(ClassifyContext::TapScript), Class::Ordinary(Ordinary::OP_CHECKSIGADD));
|
assert_eq!(op186.classify(ClassifyContext::TapScript), Class::Ordinary(Ordinary::OP_CHECKSIGADD));
|
||||||
|
|
Loading…
Reference in New Issue