Skip to content

Commit 4cafbdf

Browse files
iqdecayMujkicAdigorithmhal3esegfault-magnet
authored
fix!: encoding capacity overflow (#1249)
- This PR closes #1228 by adding the `EncoderConfig` similarly to what was done in #1066. BREAKING CHANGE: - `Configurables` structs now need to be instantiated through a `::new(encoder_config)` or `::default()` method. - `Configurables::with_some_string_config(some_string)` methods now return a `Result<Configurables>` instead of `Configurables`. - `Predicates::encode_data` now returns a `Result<UnresolvedBytes>` instead of `UnresolvedBytes`. - `PredicateEncoder` structs must be instantiated through a `::new(encoder_config)` or `::default()` method. --------- Co-authored-by: MujkicA <[email protected]> Co-authored-by: Rodrigo Araújo <[email protected]> Co-authored-by: hal3e <[email protected]> Co-authored-by: Ahmed Sagdati <[email protected]>
1 parent 9d5051c commit 4cafbdf

File tree

31 files changed

+955
-436
lines changed

31 files changed

+955
-436
lines changed

docs/src/calling-contracts/low-level-calls.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,5 @@ you would construct the function selector and the calldata as such, and provide
2828
```rust,ignore
2929
{{#include ../../../examples/contracts/src/lib.rs:low_level_call}}
3030
```
31+
32+
> Note: the `calldata!` macro uses the default `EncoderConfig` configuration under the hood.

docs/src/codec/encoding.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,27 @@ There is also a shortcut-macro that can encode multiple types which implement [`
1818

1919
> Note:
2020
> The above example will call `.resolve(0)`. Don't use it if you're encoding heap types.
21+
22+
## Configuring the encoder
23+
24+
The encoder can be configured to limit its resource expenditure:
25+
26+
```rust,ignore
27+
{{#include ../../../examples/codec/src/lib.rs:configuring_the_encoder}}
28+
```
29+
30+
The default values for the `EncoderConfig` are:
31+
32+
```rust,ignore
33+
{{#include ../../../packages/fuels-core/src/codec/abi_encoder.rs:default_encoder_config}}
34+
```
35+
36+
## Configuring the encoder for contract/script calls
37+
38+
You can also configure the encoder used to encode the arguments of the contract method:
39+
40+
```rust,ignore
41+
{{#include ../../../examples/contracts/src/lib.rs:contract_encoder_config}}
42+
```
43+
44+
The same method is available for script calls.

examples/codec/src/lib.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#[cfg(test)]
22
mod tests {
3-
use fuels::{core::codec::DecoderConfig, types::errors::Result};
3+
use fuels::{
4+
core::codec::{DecoderConfig, EncoderConfig},
5+
types::errors::Result,
6+
};
47

58
#[test]
69
fn encoding_a_type() -> Result<()> {
@@ -17,7 +20,7 @@ mod tests {
1720
}
1821

1922
let instance = MyStruct { field: 101 };
20-
let encoded: UnresolvedBytes = ABIEncoder::encode(&[instance.into_token()])?;
23+
let encoded: UnresolvedBytes = ABIEncoder::default().encode(&[instance.into_token()])?;
2124
let load_memory_address: u64 = 0x100;
2225
let _: Vec<u8> = encoded.resolve(load_memory_address);
2326
//ANCHOR_END: encoding_example
@@ -98,4 +101,19 @@ mod tests {
98101

99102
Ok(())
100103
}
104+
105+
#[test]
106+
fn configuring_the_encoder() -> Result<()> {
107+
// ANCHOR: configuring_the_encoder
108+
use fuels::core::codec::ABIEncoder;
109+
110+
ABIEncoder::new(EncoderConfig {
111+
max_depth: 5,
112+
max_tokens: 100,
113+
max_total_enum_width: 10_000,
114+
});
115+
// ANCHOR_END: configuring_the_encoder
116+
117+
Ok(())
118+
}
101119
}

examples/contracts/src/lib.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#[cfg(test)]
22
mod tests {
3+
use fuels::core::codec::EncoderConfig;
34
use fuels::{
45
core::codec::DecoderConfig,
56
prelude::{Config, LoadConfiguration, StorageConfiguration},
@@ -677,7 +678,7 @@ mod tests {
677678

678679
// Perform contract call with wallet_2
679680
let response = contract_instance
680-
.with_account(wallet_2)? // Connect wallet_2
681+
.with_account(wallet_2) // Connect wallet_2
681682
.methods() // Get contract methods
682683
.get_msg_amount() // Our contract method
683684
.call() // Perform the contract call.
@@ -830,7 +831,7 @@ mod tests {
830831
.initialize_counter(42)
831832
.with_decoder_config(DecoderConfig {
832833
max_depth: 10,
833-
max_tokens: 20_00,
834+
max_tokens: 2_000,
834835
})
835836
.call()
836837
.await?;
@@ -910,4 +911,37 @@ mod tests {
910911

911912
Ok(())
912913
}
914+
915+
#[tokio::test]
916+
async fn configure_encoder_config() -> Result<()> {
917+
use fuels::prelude::*;
918+
919+
setup_program_test!(
920+
Wallets("wallet"),
921+
Abigen(Contract(
922+
name = "MyContract",
923+
project = "packages/fuels/tests/contracts/contract_test"
924+
)),
925+
Deploy(
926+
name = "contract_instance",
927+
contract = "MyContract",
928+
wallet = "wallet"
929+
)
930+
);
931+
932+
// ANCHOR: contract_encoder_config
933+
let _ = contract_instance
934+
.with_encoder_config(EncoderConfig {
935+
max_depth: 10,
936+
max_tokens: 2_000,
937+
max_total_enum_width: 10_000,
938+
})
939+
.methods()
940+
.initialize_counter(42)
941+
.call()
942+
.await?;
943+
// ANCHOR_END: contract_encoder_config
944+
945+
Ok(())
946+
}
913947
}

examples/predicates/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ mod tests {
6565
abi = "packages/fuels/tests/predicates/signatures/out/debug/signatures-abi.json"
6666
));
6767

68-
let predicate_data = MyPredicateEncoder::encode_data(signatures);
68+
let predicate_data = MyPredicateEncoder::default().encode_data(signatures)?;
6969
let code_path = "../../packages/fuels/tests/predicates/signatures/out/debug/signatures.bin";
7070

7171
let predicate: Predicate = Predicate::load_from(code_path)?
@@ -134,7 +134,7 @@ mod tests {
134134
// ANCHOR_END: predicate_data_setup
135135

136136
// ANCHOR: with_predicate_data
137-
let predicate_data = MyPredicateEncoder::encode_data(4096, 4096);
137+
let predicate_data = MyPredicateEncoder::default().encode_data(4096, 4096)?;
138138
let code_path =
139139
"../../packages/fuels/tests/predicates/basic_predicate/out/debug/basic_predicate.bin";
140140

examples/rust_bindings/src/rust_bindings_formatted.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@ pub mod abigen_bindings {
4141
pub fn account(&self) -> T {
4242
self.account.clone()
4343
}
44-
pub fn with_account<U: Account>(&self, account: U) -> Result<MyContract<U>> {
45-
::core::result::Result::Ok(MyContract {
44+
pub fn with_account<U: Account>(&self, account: U) -> MyContract<U> {
45+
MyContract {
4646
contract_id: self.contract_id.clone(),
4747
account,
4848
log_decoder: self.log_decoder.clone(),
49-
})
49+
}
5050
}
5151
pub async fn get_balances(&self) -> Result<::std::collections::HashMap<AssetId, u64>> {
5252
ViewOnlyAccount::try_provider(&self.account)?
@@ -77,8 +77,8 @@ pub mod abigen_bindings {
7777
&[Tokenizable::into_token(value)],
7878
self.log_decoder.clone(),
7979
false,
80+
ABIEncoder::new(EncoderConfig::default()),
8081
)
81-
.expect("method not found (this should never happen)")
8282
}
8383
#[doc = "Calls the contract's `increment_counter` function"]
8484
pub fn increment_counter(&self, value: u64) -> ContractCallHandler<T, u64> {
@@ -89,8 +89,8 @@ pub mod abigen_bindings {
8989
&[value.into_token()],
9090
self.log_decoder.clone(),
9191
false,
92+
ABIEncoder::new(EncoderConfig::default()),
9293
)
93-
.expect("method not found (this should never happen)")
9494
}
9595
}
9696
impl<T: Account> contract::SettableContract for MyContract<T> {
@@ -120,4 +120,3 @@ pub mod abigen_bindings {
120120
pub use abigen_bindings::my_contract_mod::MyContract;
121121
pub use abigen_bindings::my_contract_mod::MyContractConfigurables;
122122
pub use abigen_bindings::my_contract_mod::MyContractMethods;
123-

packages/fuels-code-gen/src/program_bindings/abigen/bindings/contract.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ pub(crate) fn contract_bindings(
3737
generate_code_for_configurable_constants(&configuration_struct_name, &abi.configurables)?;
3838

3939
let code = quote! {
40+
#[derive(Debug, Clone)]
4041
pub struct #name<T: ::fuels::accounts::Account> {
4142
contract_id: ::fuels::types::bech32::Bech32ContractId,
4243
account: T,
43-
log_decoder: ::fuels::core::codec::LogDecoder
44+
log_decoder: ::fuels::core::codec::LogDecoder,
45+
encoder_config: ::fuels::core::codec::EncoderConfig,
4446
}
4547

4648
impl<T: ::fuels::accounts::Account> #name<T>
@@ -51,7 +53,8 @@ pub(crate) fn contract_bindings(
5153
) -> Self {
5254
let contract_id: ::fuels::types::bech32::Bech32ContractId = contract_id.into();
5355
let log_decoder = ::fuels::core::codec::LogDecoder::new(#log_formatters);
54-
Self { contract_id, account, log_decoder }
56+
let encoder_config = ::fuels::core::codec::EncoderConfig::default();
57+
Self { contract_id, account, log_decoder, encoder_config }
5558
}
5659

5760
pub fn contract_id(&self) -> &::fuels::types::bech32::Bech32ContractId {
@@ -62,8 +65,21 @@ pub(crate) fn contract_bindings(
6265
self.account.clone()
6366
}
6467

65-
pub fn with_account<U: ::fuels::accounts::Account>(&self, account: U) -> ::fuels::types::errors::Result<#name<U>> {
66-
::core::result::Result::Ok(#name { contract_id: self.contract_id.clone(), account, log_decoder: self.log_decoder.clone()})
68+
pub fn with_account<U: ::fuels::accounts::Account>(self, account: U)
69+
-> #name<U> {
70+
#name {
71+
contract_id: self.contract_id,
72+
account,
73+
log_decoder: self.log_decoder,
74+
encoder_config: self.encoder_config
75+
}
76+
}
77+
78+
pub fn with_encoder_config(mut self, encoder_config: ::fuels::core::codec::EncoderConfig)
79+
-> #name::<T> {
80+
self.encoder_config = encoder_config;
81+
82+
self
6783
}
6884

6985
pub async fn get_balances(&self) -> ::fuels::types::errors::Result<::std::collections::HashMap<::fuels::types::AssetId, u64>> {
@@ -77,7 +93,8 @@ pub(crate) fn contract_bindings(
7793
#methods_name {
7894
contract_id: self.contract_id.clone(),
7995
account: self.account.clone(),
80-
log_decoder: self.log_decoder.clone()
96+
log_decoder: self.log_decoder.clone(),
97+
encoder_config: self.encoder_config.clone(),
8198
}
8299
}
83100
}
@@ -86,7 +103,8 @@ pub(crate) fn contract_bindings(
86103
pub struct #methods_name<T: ::fuels::accounts::Account> {
87104
contract_id: ::fuels::types::bech32::Bech32ContractId,
88105
account: T,
89-
log_decoder: ::fuels::core::codec::LogDecoder
106+
log_decoder: ::fuels::core::codec::LogDecoder,
107+
encoder_config: ::fuels::core::codec::EncoderConfig,
90108
}
91109

92110
impl<T: ::fuels::accounts::Account> #methods_name<T> {
@@ -157,8 +175,8 @@ pub(crate) fn expand_fn(abi_fun: &FullABIFunction) -> Result<TokenStream> {
157175
&#arg_tokens,
158176
self.log_decoder.clone(),
159177
#is_payable,
178+
self.encoder_config.clone(),
160179
)
161-
.expect("method not found (this should never happen)")
162180
};
163181
generator.set_body(body);
164182

@@ -355,8 +373,8 @@ mod tests {
355373
],
356374
self.log_decoder.clone(),
357375
false,
376+
self.encoder_config.clone(),
358377
)
359-
.expect("method not found (this should never happen)")
360378
}
361379
};
362380

@@ -411,8 +429,8 @@ mod tests {
411429
&[::fuels::core::traits::Tokenizable::into_token(bimbam)],
412430
self.log_decoder.clone(),
413431
false,
432+
self.encoder_config.clone(),
414433
)
415-
.expect("method not found (this should never happen)")
416434
}
417435
};
418436

@@ -523,8 +541,8 @@ mod tests {
523541
)],
524542
self.log_decoder.clone(),
525543
false,
544+
self.encoder_config.clone(),
526545
)
527-
.expect("method not found (this should never happen)")
528546
}
529547
};
530548

packages/fuels-code-gen/src/program_bindings/abigen/bindings/function_generator.rs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ pub(crate) struct FunctionGenerator {
1818
output_type: TokenStream,
1919
body: TokenStream,
2020
doc: Option<String>,
21-
is_method: bool,
2221
}
2322

2423
impl FunctionGenerator {
@@ -38,7 +37,6 @@ impl FunctionGenerator {
3837
output_type: output_type.to_token_stream(),
3938
body: Default::default(),
4039
doc: None,
41-
is_method: true,
4240
})
4341
}
4442

@@ -47,11 +45,6 @@ impl FunctionGenerator {
4745
self
4846
}
4947

50-
pub fn make_fn_associated(&mut self) -> &mut Self {
51-
self.is_method = false;
52-
self
53-
}
54-
5548
pub fn set_body(&mut self, body: TokenStream) -> &mut Self {
5649
self.body = body;
5750
self
@@ -110,9 +103,7 @@ impl FunctionGenerator {
110103
let output_type = self.output_type();
111104
let body = &self.body;
112105

113-
let self_param = self.is_method.then_some(quote! {&self,});
114-
115-
let params = quote! { #self_param #(#arg_declarations),* };
106+
let params = quote! { &self, #(#arg_declarations),* };
116107

117108
quote! {
118109
#doc

packages/fuels-code-gen/src/program_bindings/abigen/bindings/predicate.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,19 @@ pub(crate) fn predicate_bindings(
2727
generate_code_for_configurable_constants(&configuration_struct_name, &abi.configurables)?;
2828

2929
let code = quote! {
30-
pub struct #encoder_struct_name;
30+
#[derive(Default)]
31+
pub struct #encoder_struct_name{
32+
encoder: ::fuels::core::codec::ABIEncoder,
33+
}
3134

3235
impl #encoder_struct_name {
3336
#encode_function
37+
38+
pub fn new(encoder_config: ::fuels::core::codec::EncoderConfig) -> Self {
39+
Self {
40+
encoder: ::fuels::core::codec::ABIEncoder::new(encoder_config)
41+
}
42+
}
3443
}
3544

3645
#constant_configuration_code
@@ -51,14 +60,16 @@ fn expand_fn(abi: &FullProgramABI) -> Result<TokenStream> {
5160
let arg_tokens = generator.tokenized_args();
5261

5362
let body = quote! {
54-
::fuels::core::codec::ABIEncoder::encode(&#arg_tokens).expect("Cannot encode predicate data")
63+
self.encoder.encode(&#arg_tokens)
64+
};
65+
let output_type = quote! {
66+
::fuels::types::errors::Result<::fuels::types::unresolved_bytes::UnresolvedBytes>
5567
};
5668

5769
generator
5870
.set_doc("Run the predicate's encode function with the provided arguments".to_string())
5971
.set_name("encode_data".to_string())
60-
.set_output_type(quote! { ::fuels::types::unresolved_bytes::UnresolvedBytes})
61-
.make_fn_associated()
72+
.set_output_type(output_type)
6273
.set_body(body);
6374

6475
Ok(generator.generate())

0 commit comments

Comments
 (0)