Do not panic when encoding call data with invalid fields (#2070)

* don't panic

* Add unit tests

* fmt

* clippy

* fmt

---------

Co-authored-by: elfedy <federico@moonsonglabs.com>
Co-authored-by: Federico Rodríguez <federodriguez.88@gmail.com>
This commit is contained in:
James Wilson
2025-08-26 17:54:51 +01:00
committed by GitHub
parent 739b9f84cf
commit 770fc9dc7a
+61 -2
View File
@@ -182,8 +182,7 @@ impl<CallData: EncodeAsFields> Payload for DefaultPayload<CallData> {
.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");
}
}