Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more test cases for transfer and transfer_output #535

Merged
merged 13 commits into from
Aug 4, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- [#525](https://github.com/FuelLabs/fuel-vm/pull/525): The `$hp` register is no longer restored to it's previous value when returning from a call, making it possible to return heap-allocated types from `CALL`.
- [#531](https://github.com/FuelLabs/fuel-vm/pull/531): UtxoId::from_str and TxPointer::from_str no longer crash on invalid input with multibyte characters. Also adds clippy lints to prevent future issues.
- [#535](https://github.com/FuelLabs/fuel-vm/pull/535): Add better test coverage for TR and TRO

#### Breaking

Expand Down
73 changes: 27 additions & 46 deletions fuel-vm/src/interpreter/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ use fuel_types::{
ContractId,
};

use crate::interpreter::memory::read_bytes;
use std::borrow::Cow;

#[cfg(test)]
Expand Down Expand Up @@ -201,37 +202,27 @@ struct TransferCtx<'vm, S, Tx> {
}

impl<'vm, S, Tx> TransferCtx<'vm, S, Tx> {
/// In Fuel specs:
/// Transfer $rB coins with asset ID at $rC to contract with ID at $rA.
/// $rA -> recipient_contract_id_offset
/// $rB -> transfer_amount
/// $rC -> asset_id_offset
pub(crate) fn transfer(
self,
panic_context: &mut PanicContext,
a: Word,
b: Word,
c: Word,
recipient_contract_id_offset: Word,
transfer_amount: Word,
asset_id_offset: Word,
) -> Result<(), RuntimeError>
where
Tx: ExecutableTransaction,
S: ContractsAssetsStorage,
<S as StorageInspect<ContractsAssets>>::Error: Into<std::io::Error>,
{
let ax = a
.checked_add(ContractId::LEN as Word)
.ok_or(PanicReason::ArithmeticOverflow)?;

let cx = c
.checked_add(AssetId::LEN as Word)
.ok_or(PanicReason::ArithmeticOverflow)?;

// if above usize::MAX then it cannot be safely cast to usize,
// check the tighter bound between VM_MAX_RAM and usize::MAX
if ax > MIN_VM_MAX_RAM_USIZE_MAX || cx > MIN_VM_MAX_RAM_USIZE_MAX {
return Err(PanicReason::MemoryOverflow.into())
}

let amount = b;
let destination = ContractId::try_from(&self.memory[a as usize..ax as usize])
.expect("Unreachable! Checked memory range");
let asset_id = AssetId::try_from(&self.memory[c as usize..cx as usize])
.expect("Unreachable! Checked memory range");
let amount = transfer_amount;
let destination =
ContractId::from(read_bytes(self.memory, recipient_contract_id_offset)?);
let asset_id = AssetId::from(read_bytes(self.memory, asset_id_offset)?);

InputContracts::new(self.tx.input_contracts(), panic_context)
.check(&destination)?;
Expand Down Expand Up @@ -282,38 +273,28 @@ impl<'vm, S, Tx> TransferCtx<'vm, S, Tx> {
inc_pc(self.pc)
}

/// In Fuel specs:
/// Transfer $rC coins with asset ID at $rD to address at $rA, with output $rB.
/// $rA -> recipient_offset
/// $rB -> output_index
/// $rC -> transfer_amount
/// $rD -> asset_id_offset
pub(crate) fn transfer_output(
self,
a: Word,
b: Word,
c: Word,
d: Word,
recipient_offset: Word,
output_index: Word,
transfer_amount: Word,
asset_id_offset: Word,
) -> Result<(), RuntimeError>
where
Tx: ExecutableTransaction,
S: ContractsAssetsStorage,
<S as StorageInspect<ContractsAssets>>::Error: Into<std::io::Error>,
{
let ax = a
.checked_add(ContractId::LEN as Word)
.ok_or(PanicReason::ArithmeticOverflow)?;

let dx = d
.checked_add(AssetId::LEN as Word)
.ok_or(PanicReason::ArithmeticOverflow)?;

// if above usize::MAX then it cannot be safely cast to usize,
// check the tighter bound between VM_MAX_RAM and usize::MAX
if ax > MIN_VM_MAX_RAM_USIZE_MAX || dx > MIN_VM_MAX_RAM_USIZE_MAX {
return Err(PanicReason::MemoryOverflow.into())
}

let out_idx = b as usize;
let to = Address::try_from(&self.memory[a as usize..ax as usize])
.expect("Unreachable! Checked memory range");
let asset_id = AssetId::try_from(&self.memory[d as usize..dx as usize])
.expect("Unreachable! Checked memory range");
let amount = c;
let out_idx = output_index as usize;
let to = Address::from(read_bytes(self.memory, recipient_offset)?);
let asset_id = AssetId::from(read_bytes(self.memory, asset_id_offset)?);
let amount = transfer_amount;

if amount == 0 {
return Err(PanicReason::TransferZeroCoins.into())
Expand Down
Loading
Loading