Skip to content

Commit 1760da4

Browse files
committed
Fixed panic during adding change outputs.
Added test to cover it
1 parent ca42157 commit 1760da4

File tree

3 files changed

+78
-16
lines changed

3 files changed

+78
-16
lines changed

crates/fuel-core/src/schema/tx/assemble_tx.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,9 @@ impl<'a> AssembleArguments<'a> {
117117
)
118118
.await?
119119
.into_iter()
120-
.next()
121-
.expect("The query returns a single result; qed");
120+
.next();
121+
122+
let result = result.ok_or(anyhow::anyhow!("No result for the coins to spend"))?;
122123

123124
Ok(result)
124125
}
@@ -525,14 +526,17 @@ where
525526

526527
fn satisfy_change_policy(&mut self, asset_id: AssetId) -> anyhow::Result<()> {
527528
if self.set_change_outputs.insert(asset_id) {
528-
match self
529-
.change_output_policies
530-
.get(&asset_id)
531-
.expect("Policy was inserted in the `new`; qed")
532-
{
529+
let change_policy =
530+
if let Some(policy) = self.change_output_policies.get(&asset_id) {
531+
policy.clone()
532+
} else {
533+
ChangePolicy::Change(self.fee_payer_account.owner())
534+
};
535+
536+
match change_policy {
533537
ChangePolicy::Change(change_receiver) => {
534538
self.tx.outputs_mut().push(Output::change(
535-
*change_receiver,
539+
change_receiver,
536540
0,
537541
asset_id,
538542
));

tests/test-helpers/src/assemble_tx.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,13 @@ impl AssembleAndRunTx for FuelClient {
9494
let base_asset_id = *params.base_asset_id();
9595
let wallet_owner = wallet.owner();
9696

97-
let mut base_balance_index = required_balances
97+
let mut fee_payer_index = required_balances
9898
.iter()
9999
.enumerate()
100-
.find(|(_, balance)| {
101-
balance.asset_id == base_asset_id
102-
&& balance.account.owner() == wallet_owner
103-
})
100+
.find(|(_, balance)| balance.account.owner() == wallet_owner)
104101
.map(|(i, _)| i);
105102

106-
if base_balance_index.is_none() {
103+
if fee_payer_index.is_none() {
107104
let required_balance = match &wallet {
108105
SigningAccount::Wallet(_) => RequiredBalance {
109106
asset_id: base_asset_id,
@@ -126,12 +123,12 @@ impl AssembleAndRunTx for FuelClient {
126123
},
127124
};
128125

129-
base_balance_index = Some(required_balances.len());
126+
fee_payer_index = Some(required_balances.len());
130127
required_balances.push(required_balance);
131128
}
132129

133130
let fee_index =
134-
u16::try_from(base_balance_index.expect("Fee index set above; qed")).unwrap();
131+
u16::try_from(fee_payer_index.expect("Fee index set above; qed")).unwrap();
135132
let mut tx = self
136133
.assemble_tx(
137134
tx_to_assemble,

tests/tests/assemble_tx.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use fuel_core_types::{
2525
fuel_crypto::SecretKey,
2626
fuel_tx::{
2727
policies::Policies,
28+
Address,
2829
AssetId,
2930
Input,
3031
Output,
@@ -227,6 +228,66 @@ async fn assemble_transaction__user_provided_change_output() {
227228
));
228229
}
229230

231+
#[tokio::test]
232+
async fn assemble_transaction__transfer_non_based_asset() {
233+
let mut state_config = StateConfig::local_testnet();
234+
let chain_config = ChainConfig::local_testnet();
235+
236+
let secret: SecretKey = TESTNET_WALLET_SECRETS[1].parse().unwrap();
237+
let account = SigningAccount::Wallet(secret);
238+
let owner = account.owner();
239+
let base_asset_id = *chain_config.consensus_parameters.base_asset_id();
240+
let non_base_asset_id = AssetId::from([1; 32]);
241+
assert_ne!(base_asset_id, non_base_asset_id);
242+
243+
// Given
244+
state_config.coins[0].owner = owner;
245+
state_config.coins[0].asset_id = base_asset_id;
246+
state_config.coins[1].owner = owner;
247+
state_config.coins[1].asset_id = non_base_asset_id;
248+
249+
let mut config = Config::local_node_with_configs(chain_config, state_config);
250+
config.utxo_validation = true;
251+
config.gas_price_config.min_exec_gas_price = 1000;
252+
253+
let service = FuelService::new_node(config).await.unwrap();
254+
let client = FuelClient::from(service.bound_address);
255+
256+
// Given
257+
let recipient = Address::new([123; 32]);
258+
let amount = 5_000;
259+
let tx = TransactionBuilder::script(vec![op::ret(1)].into_iter().collect(), vec![])
260+
.add_output(Output::Coin {
261+
to: recipient,
262+
asset_id: non_base_asset_id,
263+
amount,
264+
})
265+
.finalize_as_transaction();
266+
267+
// When
268+
let tx = client
269+
.assemble_transaction(
270+
&tx,
271+
default_signing_wallet(),
272+
vec![RequiredBalance {
273+
asset_id: non_base_asset_id,
274+
amount,
275+
account: account.clone().into_account(),
276+
change_policy: ChangePolicy::Change(owner),
277+
}],
278+
)
279+
.await
280+
.unwrap();
281+
let status = client.dry_run(&vec![tx.clone()]).await.unwrap();
282+
283+
// Then
284+
let status = status.into_iter().next().unwrap();
285+
assert!(matches!(
286+
status.result,
287+
TransactionExecutionResult::Success { .. }
288+
));
289+
}
290+
230291
#[tokio::test]
231292
async fn assemble_transaction__adds_change_output_for_non_required_non_base_balance() {
232293
let mut state_config = StateConfig::local_testnet();

0 commit comments

Comments
 (0)