diff --git a/consensus/Cargo.toml b/consensus/Cargo.toml index f151e404b4..3f4a1b456d 100644 --- a/consensus/Cargo.toml +++ b/consensus/Cargo.toml @@ -30,6 +30,7 @@ kaspa-muhash.workspace = true kaspa-notify.workspace = true kaspa-pow.workspace = true kaspa-txscript.workspace = true +kaspa-txscript-errors.workspace = true kaspa-utils.workspace = true log.workspace = true once_cell.workspace = true diff --git a/consensus/core/src/errors/tx.rs b/consensus/core/src/errors/tx.rs index ec1899faad..1aeb5220fe 100644 --- a/consensus/core/src/errors/tx.rs +++ b/consensus/core/src/errors/tx.rs @@ -80,6 +80,9 @@ pub enum TxRuleError { #[error("failed to verify the signature script: {0}")] SignatureInvalid(TxScriptError), + #[error("failed to verify empty signature script. Inner error: {0}")] + SignatureEmpty(TxScriptError), + #[error("input {0} sig op count is {1}, but the calculated value is {2}")] WrongSigOpCount(usize, u64, u64), diff --git a/consensus/src/processes/transaction_validator/transaction_validator_populated.rs b/consensus/src/processes/transaction_validator/transaction_validator_populated.rs index 1835ba61e4..f7a43aad2d 100644 --- a/consensus/src/processes/transaction_validator/transaction_validator_populated.rs +++ b/consensus/src/processes/transaction_validator/transaction_validator_populated.rs @@ -1,7 +1,11 @@ use crate::constants::{MAX_SOMPI, SEQUENCE_LOCK_TIME_DISABLED, SEQUENCE_LOCK_TIME_MASK}; -use kaspa_consensus_core::{hashing::sighash::SigHashReusedValues, tx::VerifiableTransaction}; +use kaspa_consensus_core::{ + hashing::sighash::SigHashReusedValues, + tx::{TransactionInput, VerifiableTransaction}, +}; use kaspa_core::warn; use kaspa_txscript::{get_sig_op_count, TxScriptEngine}; +use kaspa_txscript_errors::TxScriptError; use super::{ errors::{TxResult, TxRuleError}, @@ -167,14 +171,22 @@ impl TransactionValidator { let mut reused_values = SigHashReusedValues::new(); for (i, (input, entry)) in tx.populated_inputs().enumerate() { let mut engine = TxScriptEngine::from_transaction_input(tx, input, i, entry, &mut reused_values, &self.sig_cache) - .map_err(TxRuleError::SignatureInvalid)?; - engine.execute().map_err(TxRuleError::SignatureInvalid)?; + .map_err(|err| map_script_err(err, input))?; + engine.execute().map_err(|err| map_script_err(err, input))?; } Ok(()) } } +fn map_script_err(script_err: TxScriptError, input: &TransactionInput) -> TxRuleError { + if input.signature_script.is_empty() { + TxRuleError::SignatureEmpty(script_err) + } else { + TxRuleError::SignatureInvalid(script_err) + } +} + #[cfg(test)] mod tests { use super::super::errors::TxRuleError; diff --git a/rpc/core/src/error.rs b/rpc/core/src/error.rs index 59f6b910e7..6e1083ab75 100644 --- a/rpc/core/src/error.rs +++ b/rpc/core/src/error.rs @@ -1,4 +1,4 @@ -use kaspa_consensus_core::{subnets::SubnetworkConversionError, tx::TransactionId}; +use kaspa_consensus_core::{subnets::SubnetworkConversionError, tx::TransactionId}; use kaspa_utils::networking::IpAddress; use std::{net::AddrParseError, num::TryFromIntError}; use thiserror::Error; @@ -116,9 +116,9 @@ pub enum RpcError { #[error("transaction query must either not filter transactions or include orphans")] InconsistentMempoolTxQuery, - #[error(transparent)] - SubnetParsingError(#[from] SubnetworkConversionError), - + #[error(transparent)] + SubnetParsingError(#[from] SubnetworkConversionError), + #[error(transparent)] WasmError(#[from] workflow_wasm::error::Error),