diff --git a/packages/engine/src/errors.cairo b/packages/engine/src/errors.cairo index 4754e7f..c87aec2 100644 --- a/packages/engine/src/errors.cairo +++ b/packages/engine/src/errors.cairo @@ -17,7 +17,6 @@ pub mod Error { pub const UNSATISFIED_LOCKTIME: felt252 = 'Unsatisfied locktime'; pub const SCRIPT_STRICT_MULTISIG: felt252 = 'OP_CHECKMULTISIG invalid dummy'; pub const FINALIZED_TX_CLTV: felt252 = 'Finalized tx in OP_CLTV'; - pub const INVALID_TX_VERSION: felt252 = 'Invalid transaction version'; pub const SCRIPT_INVALID: felt252 = 'Invalid script data'; pub const INVALID_COINBASE: felt252 = 'Invalid coinbase transaction'; pub const SIG_NULLFAIL: felt252 = 'Sig non-zero on failed checksig'; @@ -50,6 +49,7 @@ pub mod Error { pub const SIG_HIGH_S: felt252 = 'Sig not canonical high S value'; pub const SIG_HASHTYPE: felt252 = 'invalid hash type'; pub const INVALID_PUBKEY_LEN: felt252 = 'Invalid public key length'; + pub const NEGATIVE_LOCKTIME: felt252 = 'Stack top is negative'; } pub fn byte_array_err(err: felt252) -> ByteArray { diff --git a/packages/engine/src/opcodes/locktime.cairo b/packages/engine/src/opcodes/locktime.cairo index 4cd068c..8921df9 100644 --- a/packages/engine/src/opcodes/locktime.cairo +++ b/packages/engine/src/opcodes/locktime.cairo @@ -107,14 +107,14 @@ pub fn opcode_checksequenceverify< )?; if stack_sequence < 0 { - return Result::Err(Error::UNSATISFIED_LOCKTIME); + return Result::Err(Error::NEGATIVE_LOCKTIME); } // Redefine 'stack_sequence' to perform bitwise operation easily - let stack_sequence_u32: u32 = stack_sequence.try_into().unwrap(); + let stack_sequence_u64: u64 = stack_sequence.try_into().unwrap(); // Disabled bit set in 'stack_sequence' result as OP_NOP behavior - if stack_sequence_u32 & SEQUENCE_LOCKTIME_DISABLED != 0 { + if stack_sequence_u64 & SEQUENCE_LOCKTIME_DISABLED.into() != 0 { return Result::Ok(()); } @@ -123,7 +123,7 @@ pub fn opcode_checksequenceverify< T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait >::get_version(engine.transaction); if version < 2 { - return Result::Err(Error::INVALID_TX_VERSION); + return Result::Err(Error::UNSATISFIED_LOCKTIME); } let transaction_input = EngineTransactionTrait::< @@ -142,6 +142,6 @@ pub fn opcode_checksequenceverify< verify_locktime( (tx_sequence & locktime_mask).into(), SEQUENCE_LOCKTIME_IS_SECOND.into(), - (stack_sequence_u32 & locktime_mask).into() + (stack_sequence_u64 & locktime_mask.into()).try_into().unwrap() ) } diff --git a/packages/tests/src/tests/opcodes/test_locktime.cairo b/packages/tests/src/tests/opcodes/test_locktime.cairo index 4951609..91f837c 100644 --- a/packages/tests/src/tests/opcodes/test_locktime.cairo +++ b/packages/tests/src/tests/opcodes/test_locktime.cairo @@ -156,7 +156,7 @@ fn test_opcode_checksequence_tx_version_fail() { // Running with tx v1 let flags: u32 = ScriptFlags::ScriptVerifyCheckSequenceVerify.into(); let mut engine = utils::test_compile_and_run_with_tx_flags_err( - program, tx, flags, Error::INVALID_TX_VERSION + program, tx, flags, Error::UNSATISFIED_LOCKTIME ); utils::check_dstack_size(ref engine, 1); } diff --git a/tests/run-core-tests.sh b/tests/run-core-tests.sh index 08406a2..cb3902e 100755 --- a/tests/run-core-tests.sh +++ b/tests/run-core-tests.sh @@ -146,7 +146,8 @@ jq -c '.[]' $SCRIPT_TESTS_JSON | { PUBKEYTYPE="Execution failed: Unsupported public key type" INVALID_SIG_FMT="Execution failed: invalid sig fmt: too short" INVALID_HASH_TYPE="Execution failed: invalid hash type" - INVALID_LOCKTIME="Execution failed: Unsatisfied locktime" + NEGATIVE_LOCKTIME="Execution failed: Stack top is negative" + UNSATISFIED_LOCKTIME="Execution failed: Unsatisfied locktime" SCRIPT_SIZE="Execution failed: Engine::new: script too large" CLEAN_STACK="Execution failed: Non-clean stack after execute" MINIMAL_DATA="Execution failed: Opcode represents non-minimal" @@ -220,8 +221,10 @@ jq -c '.[]' $SCRIPT_TESTS_JSON | { SCRIPT_RESULT="PUSH_SIZE" elif echo "$RESULT" | grep -q "$OP_COUNT"; then SCRIPT_RESULT="OP_COUNT" - elif echo "$RESULT" | grep -q "$INVALID_LOCKTIME"; then + elif echo "$RESULT" | grep -q "$NEGATIVE_LOCKTIME"; then SCRIPT_RESULT="NEGATIVE_LOCKTIME" + elif echo "$RESULT" | grep -q "$UNSATISFIED_LOCKTIME"; then + SCRIPT_RESULT="UNSATISFIED_LOCKTIME" elif echo "$RESULT" | grep -q "$SCRIPT_SIZE"; then SCRIPT_RESULT="SCRIPT_SIZE" elif echo "$RESULT" | grep -q "$CLEAN_STACK"; then diff --git a/tests/run-failing-core-tests.sh b/tests/run-failing-core-tests.sh index 2efc8f3..cc5ef19 100755 --- a/tests/run-failing-core-tests.sh +++ b/tests/run-failing-core-tests.sh @@ -131,7 +131,8 @@ jq -c '.[]' $SCRIPT_TESTS_JSON | { PUBKEYTYPE="Execution failed: Unsupported public key type" INVALID_SIG_FMT="Execution failed: invalid sig fmt: too short" INVALID_HASH_TYPE="Execution failed: invalid hash type" - INVALID_LOCKTIME="Execution failed: Unsatisfied locktime" + NEGATIVE_LOCKTIME="Execution failed: Stack top is negative" + UNSATISFIED_LOCKTIME="Execution failed: Unsatisfied locktime" SCRIPT_SIZE="Execution failed: Engine::new: script too large" CLEAN_STACK="Execution failed: Non-clean stack after execute" MINIMAL_DATA="Execution failed: Opcode represents non-minimal" @@ -198,7 +199,9 @@ jq -c '.[]' $SCRIPT_TESTS_JSON | { SCRIPT_RESULT="PUSH_SIZE" elif echo "$RESULT" | grep -q "$OP_COUNT"; then SCRIPT_RESULT="OP_COUNT" - elif echo "$RESULT" | grep -q "$INVALID_LOCKTIME"; then + elif echo "$RESULT" | grep -q "$UNSATISFIED_LOCKTIME"; then + SCRIPT_RESULT="UNSATISFIED_LOCKTIME" + elif echo "$RESULT" | grep -q "$NEGATIVE_LOCKTIME"; then SCRIPT_RESULT="NEGATIVE_LOCKTIME" elif echo "$RESULT" | grep -q "$SCRIPT_SIZE"; then SCRIPT_RESULT="SCRIPT_SIZE" diff --git a/tests/script_tests_failing.json b/tests/script_tests_failing.json index db0f3ca..fe51488 100644 --- a/tests/script_tests_failing.json +++ b/tests/script_tests_failing.json @@ -1,3 +1 @@ -[ -["0","CHECKSEQUENCEVERIFY","CHECKSEQUENCEVERIFY","UNSATISFIED_LOCKTIME","CSV fails if stack top bit 1 << 31 is set and the tx version < 2"], -["0x050000000001","CHECKSEQUENCEVERIFY","CHECKSEQUENCEVERIFY","UNSATISFIED_LOCKTIME","CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"]] +[] diff --git a/tests/script_tests_passing.json b/tests/script_tests_passing.json index fa56d07..1c41d62 100644 --- a/tests/script_tests_passing.json +++ b/tests/script_tests_passing.json @@ -1126,6 +1126,8 @@ ["","CHECKSEQUENCEVERIFY","CHECKSEQUENCEVERIFY","INVALID_STACK_OPERATION","CSV automatically fails on an empty stack"], ["-1","CHECKSEQUENCEVERIFY","CHECKSEQUENCEVERIFY","NEGATIVE_LOCKTIME","CSV automatically fails if stack top is negative"], ["0x0100","CHECKSEQUENCEVERIFY","CHECKSEQUENCEVERIFY,MINIMALDATA","UNKNOWN_ERROR","CSV fails if stack top is not minimally encoded"], +["0","CHECKSEQUENCEVERIFY","CHECKSEQUENCEVERIFY","UNSATISFIED_LOCKTIME","CSV fails if stack top bit 1 << 31 is set and the tx version < 2"], +["0x050000000001","CHECKSEQUENCEVERIFY","CHECKSEQUENCEVERIFY","UNSATISFIED_LOCKTIME","CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"], ["1","IF 1 ENDIF","P2SH,WITNESS,MINIMALIF","OK"], ["2","IF 1 ENDIF","P2SH,WITNESS,MINIMALIF","OK"], ["0x02 0x0100","IF 1 ENDIF","P2SH,WITNESS,MINIMALIF","OK"],