From e46f95f4f07502ea1222a52dd0622be2c2b24512 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Tue, 27 Feb 2024 11:33:49 +0200 Subject: [PATCH] custom encode/decode --- .../tests/bridge_proxy_blackbox_test.rs | 2 +- common/transaction/src/call_data.rs | 74 +++++++++++++++++++ common/transaction/src/custom_buffer.rs | 38 ++++++++++ common/transaction/src/lib.rs | 23 ++---- .../tests/multi_transfer_blackbox_test.rs | 2 +- 5 files changed, 119 insertions(+), 20 deletions(-) create mode 100644 common/transaction/src/call_data.rs create mode 100644 common/transaction/src/custom_buffer.rs diff --git a/bridge-proxy/tests/bridge_proxy_blackbox_test.rs b/bridge-proxy/tests/bridge_proxy_blackbox_test.rs index d3d93981..ae4865a4 100644 --- a/bridge-proxy/tests/bridge_proxy_blackbox_test.rs +++ b/bridge-proxy/tests/bridge_proxy_blackbox_test.rs @@ -27,7 +27,7 @@ use multiversx_sc_scenario::{ }; use eth_address::*; -use transaction::{CallData, EthTransaction, EthTransactionPayment}; +use transaction::{call_data::CallData, EthTransaction, EthTransactionPayment}; const BRIDGE_TOKEN_ID: &[u8] = b"BRIDGE-123456"; const GAS_LIMIT: u64 = 1_000_000; diff --git a/common/transaction/src/call_data.rs b/common/transaction/src/call_data.rs new file mode 100644 index 00000000..f651d5be --- /dev/null +++ b/common/transaction/src/call_data.rs @@ -0,0 +1,74 @@ +use multiversx_sc::codec::{DefaultErrorHandler, NestedEncodeOutput}; + +use crate::custom_buffer::AlwaysTopEncodedBuffer; + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[derive(TypeAbi, Clone, ManagedVecItem, Default)] +pub struct CallData { + pub endpoint: ManagedBuffer, + pub gas_limit: u64, + pub args: ManagedVec>, +} + +impl TopEncode for CallData { + fn top_encode(&self, output: O) -> Result<(), codec::EncodeError> + where + O: codec::TopEncodeOutput, + { + let mut nested_encode_output = output.start_nested_encode(); + self.dep_encode(&mut nested_encode_output) + } +} + +impl NestedEncode for CallData { + fn dep_encode(&self, dest: &mut O) -> Result<(), codec::EncodeError> { + let endpoint_len_u8 = self.endpoint.len() as u8; + dest.push_byte(endpoint_len_u8); + + let endpoint_buffer = AlwaysTopEncodedBuffer::new(self.endpoint.clone()); + endpoint_buffer.dep_encode(dest)?; + + let gas_limit_u32 = self.gas_limit as u32; + gas_limit_u32.dep_encode(dest)?; + + let args_len_u8 = self.args.len() as u8; + dest.push_byte(args_len_u8); + + for arg in &self.args { + arg.dep_encode(dest)?; + } + + Result::Ok(()) + } +} + +impl NestedDecode for CallData { + fn dep_decode(input: &mut I) -> Result { + let mut temp_buffer = [0u8; u8::MAX as usize + 1]; + let endpoint_len_u8 = u8::dep_decode(input)?; + input.read_into( + &mut temp_buffer[0..endpoint_len_u8 as usize], + DefaultErrorHandler, + )?; + let endpoint_name = + ManagedBuffer::new_from_bytes(&temp_buffer[0..endpoint_len_u8 as usize]); + + let gas_limit_u32 = u32::dep_decode(input)?; + let gas_limit = gas_limit_u32 as u64; + + let args_len_u8 = u8::dep_decode(input)?; + let mut args = ManagedVec::new(); + for _ in 0..args_len_u8 { + let arg = ManagedBuffer::dep_decode(input)?; + args.push(arg); + } + + core::result::Result::Ok(Self { + endpoint: endpoint_name, + gas_limit, + args, + }) + } +} diff --git a/common/transaction/src/custom_buffer.rs b/common/transaction/src/custom_buffer.rs new file mode 100644 index 00000000..fe235de5 --- /dev/null +++ b/common/transaction/src/custom_buffer.rs @@ -0,0 +1,38 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +pub struct AlwaysTopEncodedBuffer { + buffer: ManagedBuffer, +} + +impl AlwaysTopEncodedBuffer { + #[inline(always)] + pub fn new(buffer: ManagedBuffer) -> Self { + Self { buffer } + } +} + +impl TopEncode for AlwaysTopEncodedBuffer { + fn top_encode(&self, output: O) -> Result<(), codec::EncodeError> + where + O: codec::TopEncodeOutput, + { + self.buffer.top_encode(output) + } +} + +impl NestedEncode for AlwaysTopEncodedBuffer { + fn dep_encode( + &self, + dest: &mut O, + ) -> Result<(), codec::EncodeError> { + let mut output_buffer = ManagedBuffer::::new(); + self.buffer.top_encode(&mut output_buffer)?; + + let mut output_buffer_bytes = [0u8; u8::MAX as usize + 1]; + let slice_ref = output_buffer.load_to_byte_array(&mut output_buffer_bytes); + dest.write(slice_ref); + + Result::Ok(()) + } +} diff --git a/common/transaction/src/lib.rs b/common/transaction/src/lib.rs index 11a6a501..5a97e331 100644 --- a/common/transaction/src/lib.rs +++ b/common/transaction/src/lib.rs @@ -3,7 +3,11 @@ multiversx_sc::imports!(); multiversx_sc::derive_imports!(); +use call_data::CallData; use eth_address::EthAddress; + +pub mod call_data; +pub mod custom_buffer; pub mod transaction_status; // revert protection @@ -25,24 +29,7 @@ pub type TxAsMultiValue = MultiValue6< pub type PaymentsVec = ManagedVec>; pub type TxBatchSplitInFields = MultiValue2>>; -#[derive(NestedEncode, NestedDecode, TypeAbi, Clone, ManagedVecItem)] -pub struct CallData { - pub endpoint: ManagedBuffer, - pub gas_limit: u64, - pub args: ManagedVec>, -} - -impl Default for CallData { - #[inline] - fn default() -> Self { - Self { - endpoint: ManagedBuffer::new(), - gas_limit: 0, - args: ManagedVec::new(), - } - } -} -#[derive(TopDecode, TopEncode, NestedEncode, NestedDecode, TypeAbi, Clone, ManagedVecItem)] +#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, TypeAbi, Clone, ManagedVecItem)] pub struct EthTransaction { pub from: EthAddress, pub to: ManagedAddress, diff --git a/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs b/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs index 3d445c3d..50ec1914 100644 --- a/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs +++ b/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs @@ -27,7 +27,7 @@ use multiversx_sc_scenario::{ use eth_address::*; use token_module::ProxyTrait as _; -use transaction::{CallData, EthTransaction, EthTransactionPayment}; +use transaction::{call_data::CallData, EthTransaction, EthTransactionPayment}; const BRIDGE_TOKEN_ID: &[u8] = b"BRIDGE-123456"; const BRIDGE_TOKEN_ID_EXPR: &str = "str:BRIDGE-123456";