diff --git a/binary_port/src/error_code.rs b/binary_port/src/error_code.rs index 56cc370e37..cc576c5c16 100644 --- a/binary_port/src/error_code.rs +++ b/binary_port/src/error_code.rs @@ -268,9 +268,9 @@ pub enum ErrorCode { /// Entry point cannot be 'call' #[error("entry point cannot be 'call'")] InvalidTransactionEntryPointCannotBeCall = 83, - /// Invalid transaction kind - #[error("invalid transaction kind")] - InvalidTransactionInvalidTransactionKind = 84, + /// Invalid transaction lane + #[error("invalid transaction lane")] + InvalidTransactionInvalidTransactionLane = 84, /// Gas price tolerance too low #[error("gas price tolerance too low")] GasPriceToleranceTooLow = 85, @@ -307,6 +307,30 @@ pub enum ErrorCode { /// Malformed binary request #[error("malformed binary request")] MalformedBinaryRequest = 96, + /// No matching lane for transaction + #[error("couldn't associate a transaction lane with the transaction")] + InvalidTransactionNoWasmLaneMatches = 97, + /// Entry point must be 'call' + #[error("entry point must be 'call'")] + InvalidTransactionEntryPointMustBeCall = 98, + /// One of the payloads field cannot be deserialized + #[error("One of the payloads field cannot be deserialized")] + InvalidTransactionCannotDeserializeField = 99, + /// Can't calculate hash of the payload fields + #[error("Can't calculate hash of the payload fields")] + InvalidTransactionCannotCalculateFieldsHash = 100, + /// Unexpected fields in payload + #[error("Unexpected fields in payload")] + InvalidTransactionUnexpectedFields = 101, + /// Expected bytes arguments + #[error("expected bytes arguments")] + InvalidTransactionExpectedBytesArguments = 102, + /// Missing seed field in transaction + #[error("Missing seed field in transaction")] + InvalidTransactionMissingSeed = 103, + /// Pricing mode not supported + #[error("Pricing mode not supported")] + PricingModeNotSupported = 104, } impl TryFrom for ErrorCode { @@ -398,7 +422,7 @@ impl TryFrom for ErrorCode { 81 => Ok(ErrorCode::DeployMissingTransferTarget), 82 => Ok(ErrorCode::DeployMissingModuleBytes), 83 => Ok(ErrorCode::InvalidTransactionEntryPointCannotBeCall), - 84 => Ok(ErrorCode::InvalidTransactionInvalidTransactionKind), + 84 => Ok(ErrorCode::InvalidTransactionInvalidTransactionLane), 85 => Ok(ErrorCode::GasPriceToleranceTooLow), 86 => Ok(ErrorCode::ReceivedV1Transaction), 87 => Ok(ErrorCode::PurseNotFound), @@ -411,6 +435,14 @@ impl TryFrom for ErrorCode { 94 => Ok(ErrorCode::MalformedProtocolVersion), 95 => Ok(ErrorCode::MalformedBinaryRequestHeader), 96 => Ok(ErrorCode::MalformedBinaryRequest), + 97 => Ok(ErrorCode::InvalidTransactionNoWasmLaneMatches), + 98 => Ok(ErrorCode::InvalidTransactionEntryPointMustBeCall), + 99 => Ok(ErrorCode::InvalidTransactionCannotDeserializeField), + 100 => Ok(ErrorCode::InvalidTransactionCannotCalculateFieldsHash), + 101 => Ok(ErrorCode::InvalidTransactionUnexpectedFields), + 102 => Ok(ErrorCode::InvalidTransactionExpectedBytesArguments), + 103 => Ok(ErrorCode::InvalidTransactionMissingSeed), + 104 => Ok(ErrorCode::PricingModeNotSupported), _ => Err(UnknownErrorCode), } } @@ -544,7 +576,7 @@ impl From for ErrorCode { ErrorCode::InvalidTransactionEntryPointCannotBeCall } InvalidTransactionV1::InvalidTransactionLane(_) => { - ErrorCode::InvalidTransactionInvalidTransactionKind + ErrorCode::InvalidTransactionInvalidTransactionLane } InvalidTransactionV1::GasPriceToleranceTooLow { .. } => { ErrorCode::GasPriceToleranceTooLow @@ -553,6 +585,26 @@ impl From for ErrorCode { InvalidTransactionV1::InvalidTransactionRuntime { .. } => { ErrorCode::InvalidTransactionRuntime } + InvalidTransactionV1::NoWasmLaneMatchesTransaction() => { + ErrorCode::InvalidTransactionNoWasmLaneMatches + } + InvalidTransactionV1::EntryPointMustBeCall { .. } => { + ErrorCode::InvalidTransactionEntryPointMustBeCall + } + InvalidTransactionV1::CouldNotDeserializeField { .. } => { + ErrorCode::InvalidTransactionCannotDeserializeField + } + InvalidTransactionV1::CannotCalculateFieldsHash => { + ErrorCode::InvalidTransactionCannotCalculateFieldsHash + } + InvalidTransactionV1::UnexpectedTransactionFieldEntries => { + ErrorCode::InvalidTransactionUnexpectedFields + } + InvalidTransactionV1::ExpectedBytesArguments => { + ErrorCode::InvalidTransactionExpectedBytesArguments + } + InvalidTransactionV1::MissingSeed => ErrorCode::InvalidTransactionMissingSeed, + InvalidTransactionV1::PricingModeNotSupported => ErrorCode::PricingModeNotSupported, _other => ErrorCode::InvalidTransactionUnspecified, } } diff --git a/node/src/components/transaction_acceptor/tests.rs b/node/src/components/transaction_acceptor/tests.rs index b559f5f58b..ec2375cad3 100644 --- a/node/src/components/transaction_acceptor/tests.rs +++ b/node/src/components/transaction_acceptor/tests.rs @@ -218,6 +218,7 @@ enum TestScenario { InvalidFields, InvalidFieldsFromPeer, InvalidArgumentsKind, + WasmTransactionWithTooBigPayment, } impl TestScenario { @@ -263,7 +264,8 @@ impl TestScenario { | TestScenario::TooLowGasPriceToleranceForTransactionV1 | TestScenario::TooLowGasPriceToleranceForDeploy | TestScenario::InvalidFields - | TestScenario::InvalidArgumentsKind => Source::Client, + | TestScenario::InvalidArgumentsKind + | TestScenario::WasmTransactionWithTooBigPayment => Source::Client, } } @@ -645,6 +647,30 @@ impl TestScenario { .unwrap(); Transaction::from(txn) } + TestScenario::WasmTransactionWithTooBigPayment => { + let timestamp = Timestamp::now() + + Config::default().timestamp_leeway + + TimeDiff::from_millis(100); + let ttl = TimeDiff::from_seconds(300); + let txn = TransactionV1Builder::new_session( + false, + Bytes::from(vec![1]), + TransactionRuntimeParams::VmCasperV1, + ) + .with_pricing_mode(PricingMode::PaymentLimited { + payment_amount: u64::MAX, /* make sure it's a big value that doesn't match + * any wasm lane */ + gas_price_tolerance: 2, + standard_payment: true, + }) + .with_chain_name("casper-example") + .with_timestamp(timestamp) + .with_ttl(ttl) + .with_secret_key(&secret_key) + .build() + .unwrap(); + Transaction::from(txn) + } } } @@ -704,6 +730,7 @@ impl TestScenario { TestScenario::InvalidFields => false, TestScenario::InvalidFieldsFromPeer => false, TestScenario::InvalidArgumentsKind => false, + TestScenario::WasmTransactionWithTooBigPayment => false, } } @@ -1263,7 +1290,8 @@ async fn run_transaction_acceptor_without_timeout( | TestScenario::TooLowGasPriceToleranceForTransactionV1 | TestScenario::TooLowGasPriceToleranceForDeploy | TestScenario::InvalidFields - | TestScenario::InvalidArgumentsKind => { + | TestScenario::InvalidArgumentsKind + | TestScenario::WasmTransactionWithTooBigPayment => { matches!( event, Event::TransactionAcceptorAnnouncement( @@ -2545,3 +2573,14 @@ async fn should_reject_transaction_with_invalid_transaction_args() { ))) )); } + +#[tokio::test] +async fn should_reject_wasm_transaction_with_limited_too_big_payment() { + let result = run_transaction_acceptor(TestScenario::WasmTransactionWithTooBigPayment).await; + assert!(matches!( + result, + Err(super::Error::InvalidTransaction(InvalidTransaction::V1( + InvalidTransactionV1::NoWasmLaneMatchesTransaction() + ))) + )); +}