From 770fc9dc7a05814fe78c41eb9120239f8233754c Mon Sep 17 00:00:00 2001 From: James Wilson Date: Tue, 26 Aug 2025 17:54:51 +0100 Subject: [PATCH] Do not panic when encoding call data with invalid fields (#2070) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * don't panic * Add unit tests * fmt * clippy * fmt --------- Co-authored-by: elfedy Co-authored-by: Federico Rodríguez --- core/src/tx/payload.rs | 63 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/core/src/tx/payload.rs b/core/src/tx/payload.rs index 40d5e564e0..a3842cf03b 100644 --- a/core/src/tx/payload.rs +++ b/core/src/tx/payload.rs @@ -182,8 +182,7 @@ impl Payload for DefaultPayload { .map(|f| scale_encode::Field::new(f.ty.id, f.name.as_deref())); self.call_data - .encode_as_fields_to(&mut fields, metadata.types(), out) - .expect("The fields are valid types from the metadata, qed;"); + .encode_as_fields_to(&mut fields, metadata.types(), out)?; Ok(()) } @@ -205,3 +204,63 @@ pub fn dynamic( ) -> DynamicPayload { DefaultPayload::new(pallet_name, call_name, call_data.into()) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::metadata::Metadata; + use codec::Decode; + use scale_value::Composite; + + fn test_metadata() -> Metadata { + let metadata_bytes = include_bytes!("../../../artifacts/polkadot_metadata_small.scale"); + Metadata::decode(&mut &metadata_bytes[..]).expect("Valid metadata") + } + + #[test] + fn encode_call_with_incompatible_types_returns_error() { + let metadata = test_metadata(); + + let incompatible_data = Composite::named([ + ("dest", scale_value::Value::bool(true)), // Boolean instead of MultiAddress + ("value", scale_value::Value::string("not_a_number")), // String instead of u128 + ]); + + let payload = DefaultPayload::new("Balances", "transfer_allow_death", incompatible_data); + + let mut out = Vec::new(); + let result = payload.encode_call_data_to(&metadata, &mut out); + + assert!( + result.is_err(), + "Expected error when encoding with incompatible types" + ); + } + + #[test] + fn encode_call_with_valid_data_succeeds() { + let metadata = test_metadata(); + + // Create a valid payload to ensure our error handling doesn't break valid cases + // For MultiAddress, we'll use the Id variant with a 32-byte account + let valid_address = + scale_value::Value::unnamed_variant("Id", [scale_value::Value::from_bytes([0u8; 32])]); + + let valid_data = Composite::named([ + ("dest", valid_address), + ("value", scale_value::Value::u128(1000)), + ]); + + let payload = DefaultPayload::new("Balances", "transfer_allow_death", valid_data); + + // This should succeed + let mut out = Vec::new(); + let result = payload.encode_call_data_to(&metadata, &mut out); + + assert!( + result.is_ok(), + "Expected success when encoding with valid data" + ); + assert!(!out.is_empty(), "Expected encoded output to be non-empty"); + } +}