Skip to content

Commit

Permalink
Fix the GTF for upgrade and add a test for the create specific GTF
Browse files Browse the repository at this point in the history
  • Loading branch information
AurelienFT committed Dec 10, 2024
1 parent 7ec1911 commit 4618cf6
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 17 deletions.
25 changes: 17 additions & 8 deletions fuel-asm/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,8 @@ crate::enum_try_from! {
/// Set `$rA` to `tx.witnessIndex`
BlobWitnessIndex = 0x701,

/// Set `$rA` to `tx.purpose.root` if `tx.purpose.type == StateTransition`
UpgradeStateTransitionRoot = 0x800,

/// Set `$rA` to `tx.purpose.witnessIndex` if `tx.purpose.type == ConsensusParameters`
UpgradeConsensusParametersWitnessIndex = 0x801,

/// Set `$rA` to `Memory address of tx.purpose.checksum` if `tx.purpose.type == ConsensusParameters`
UpgradeConsensusParametersChecksum = 0x802,
/// Set `$rA` to `Memory address of tx.purpose`
UpgradePurpose = 0x800,

/// Set `$rA` to `tx.inputsCount`
TxInputsCount = 0x900,
Expand Down Expand Up @@ -410,6 +404,21 @@ fn encode_gtf_args() {
GTFArgs::PolicyMaturity,
GTFArgs::PolicyExpiration,
GTFArgs::PolicyMaxFee,
GTFArgs::UploadRoot,
GTFArgs::UploadWitnessIndex,
GTFArgs::UploadSubsectionIndex,
GTFArgs::UploadSubsectionsCount,
GTFArgs::UploadProofSetCount,
GTFArgs::UploadProofSetAtIndex,
GTFArgs::BlobId,
GTFArgs::BlobWitnessIndex,
GTFArgs::UpgradePurpose,
GTFArgs::TxInputsCount,
GTFArgs::TxOutputsCount,
GTFArgs::TxWitnessesCount,
GTFArgs::TxInputAtIndex,
GTFArgs::TxOutputAtIndex,
GTFArgs::TxWitnessAtIndex,
];

args.into_iter().for_each(|a| {
Expand Down
5 changes: 5 additions & 0 deletions fuel-vm/src/interpreter/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use fuel_tx::{
StorageSlots,
SubsectionIndex,
SubsectionsNumber,
UpgradePurpose,
},
policies::PolicyType,
Blob,
Expand Down Expand Up @@ -610,6 +611,10 @@ impl<Tx> GTFInput<'_, Tx> {
) as Word,

// Upgrade
(ExecutableTxType::Upgrade(upgrade), GTFArgs::UpgradePurpose) => {
ofs.saturating_add(upgrade.upgrade_purpose_offset()) as Word
}

_ => return Err(PanicReason::InvalidMetadataIdentifier.into()),
}
}
Expand Down
162 changes: 153 additions & 9 deletions fuel-vm/src/tests/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ use alloc::{
vec,
vec::Vec,
};
use consensus_parameters::gas::GasCostsValuesV5;

use crate::{
checked_transaction::EstimatePredicates,
consts::*,
interpreter::{
InterpreterParams,
NotSupportedEcal,
},
storage::predicate::EmptyStorage,
};
use fuel_asm::{
op,
Expand Down Expand Up @@ -356,6 +359,7 @@ fn get_metadata_tx_start() {
}
}

#[allow(deprecated)]
#[test]
fn get_transaction_fields() {
let rng = &mut StdRng::seed_from_u64(2322u64);
Expand Down Expand Up @@ -552,18 +556,21 @@ fn get_transaction_fields() {
let script_data: Vec<u8> = cases.iter().flat_map(|c| c.iter()).copied().collect();

// Maybe use predicates to check create context?
// TODO GTFArgs::CreateBytecodeLength
// TODO GTFArgs::CreateBytecodeWitnessIndex
// TODO GTFArgs::CreateStorageSlotsCount
// TODO GTFArgs::CreateSalt
// TODO GTFArgs::CreateStorageSlotAtIndex
// TODO GTFArgs::OutputContractCreatedContractId
// TODO GTFArgs::OutputContractCreatedStateRoot

// blocked by https://github.com/FuelLabs/fuel-vm/issues/59
// TODO GTFArgs::InputCoinTxPointer
// TODO GTFArgs::InputContractTxPointer

// TODO GTFArgs::UploadRoot
// TODO GTFArgs::UploadWitnessIndex
// TODO GTFArgs::UploadSubsectionIndex
// TODO GTFArgs::UploadSubsectionsCount
// TODO GTFArgs::UploadProofSetCount
// TODO GTFArgs::UploadProofSetAtIndex

// TODO GTFArgs::BlobId
// TODO GTFArgs::BlobWitnessIndex

// TODO GTFArgs::UpgradePurpose

#[rustfmt::skip]
let mut script: Vec<u8> = vec![
op::movi(0x20, 0x01),
Expand Down Expand Up @@ -924,6 +931,46 @@ fn get_transaction_fields() {
op::add(0x30, 0x30, 0x11),
op::and(0x20, 0x20, 0x10),

op::movi(0x19, 0x00),
op::movi(0x11, inputs.len() as Immediate18),
op::gtf_args(0x10, 0x19, GTFArgs::TxInputsCount),
op::eq(0x10, 0x10, 0x11),
op::and(0x20, 0x20, 0x10),

op::movi(0x19, 0x00),
op::movi(0x11, outputs.len() as Immediate18),
op::gtf_args(0x10, 0x19, GTFArgs::TxOutputsCount),
op::eq(0x10, 0x10, 0x11),
op::and(0x20, 0x20, 0x10),

op::movi(0x19, 0x00),
op::movi(0x11, witnesses.len() as Immediate18),
op::gtf_args(0x10, 0x19, GTFArgs::TxWitnessesCount),
op::eq(0x10, 0x10, 0x11),
op::and(0x20, 0x20, 0x10),

op::gtf_args(0x30, 0x19, GTFArgs::ScriptData),
op::movi(0x19, 0x00),
op::gtf_args(0x10, 0x19, GTFArgs::TxInputAtIndex),
op::movi(0x11, cases[0].len() as Immediate18),
op::meq(0x10, 0x10, 0x30, 0x11),
op::add(0x30, 0x30, 0x11),
op::and(0x20, 0x20, 0x10),

op::movi(0x19, 0x00),
op::gtf_args(0x10, 0x19, GTFArgs::TxOutputAtIndex),
op::movi(0x11, cases[1].len() as Immediate18),
op::meq(0x10, 0x10, 0x30, 0x11),
op::add(0x30, 0x30, 0x11),
op::and(0x20, 0x20, 0x10),

op::movi(0x19, 0x01),
op::gtf_args(0x10, 0x19, GTFArgs::TxWitnessAtIndex),
op::movi(0x11, cases[2].len() as Immediate18),
op::meq(0x10, 0x10, 0x30, 0x11),
op::add(0x30, 0x30, 0x11),
op::and(0x20, 0x20, 0x10),

op::log(0x20, 0x00, 0x00, 0x00),
op::ret(0x00)
].into_iter().collect();
Expand Down Expand Up @@ -964,3 +1011,100 @@ fn get_transaction_fields() {

assert!(success);
}

#[allow(deprecated)]
#[allow(unused_must_use)]
#[test]
fn get__create_specific_transaction_fields__success() {
// TODO GTFArgs::OutputContractCreatedContractId
const PREDICATE_COUNT: u64 = 1;
const MAX_PREDICATE_GAS: u64 = 1_000_000;
const MAX_TX_GAS: u64 = MAX_PREDICATE_GAS * PREDICATE_COUNT;
let rng = &mut StdRng::seed_from_u64(8586);
let mut client = MemoryClient::default();

let salt = Salt::new([1; 32]);
let storage_slots = vec![
StorageSlot::new(Bytes32::new([0; 32]), Bytes32::new([0; 32])),
StorageSlot::new(Bytes32::new([2; 32]), Bytes32::new([3; 32])),
];
// Write the elements we want to check into the bytecode
// so that they are available in the predicate memory
// doesn't work for the contract_id because changing the bytecode would change the
// contract_id
let mut bytecode = Vec::new();
bytecode.extend(salt.to_bytes());
bytecode.extend(storage_slots[1].to_bytes());
bytecode.extend(Contract::initial_state_root(storage_slots.iter()).iter());
let mut tx = TransactionBuilder::create(bytecode.into(), salt, storage_slots);
tx.add_fee_input();
tx.add_contract_created();
let predicate_code = vec![
op::gtf_args(0x10, 0x00, GTFArgs::CreateBytecodeWitnessIndex),
op::movi(0x11, 0x00),
op::eq(0x20, 0x10, 0x11),
// Store the bytecode pointer for later use
op::gtf_args(0x13, 0x10, GTFArgs::TxWitnessAtIndex),
// Skip the length of the bytecode
op::addi(0x13, 0x13, 0x08),
op::gtf_args(0x10, 0x00, GTFArgs::CreateStorageSlotsCount),
op::movi(0x11, 0x02),
op::eq(0x10, 0x10, 0x11),
op::and(0x20, 0x20, 0x10),
op::gtf_args(0x10, 0x00, GTFArgs::CreateSalt),
op::movi(0x11, 0x20),
// Salt is at the start of the bytecode which start at value stored in 0x13
op::meq(0x10, 0x10, 0x13, 0x11),
op::and(0x20, 0x20, 0x10),
op::gtf_args(0x10, 0x01, GTFArgs::CreateStorageSlotAtIndex),
op::movi(0x11, StorageSlot::SLOT_SIZE as Immediate18),
// Increase bytecode pointer by 32 bytes to pass the salt
op::addi(0x13, 0x13, 0x20),
op::meq(0x10, 0x10, 0x13, 0x11),
op::and(0x20, 0x20, 0x10),
op::gtf_args(0x10, 0x00, GTFArgs::OutputContractCreatedStateRoot),
op::movi(0x11, 0x20),
// Increase bytecode pointer by SLOTSIZE bytes to pass the storage slot written
// in bytecode
op::addi(0x13, 0x13, StorageSlot::SLOT_SIZE as Immediate12),
op::meq(0x10, 0x10, 0x13, 0x11),
op::and(0x20, 0x20, 0x10),
op::ret(0x20),
]
.into_iter()
.collect();
let predicate_owner: Address = Input::predicate_owner(&predicate_code);
tx.add_input(Input::coin_predicate(
rng.gen(),
predicate_owner,
rng.gen(),
*tx.get_params().base_asset_id(),
rng.gen(),
0,
predicate_code,
vec![],
));
let tx_param = TxParameters::default().with_max_gas_per_tx(MAX_TX_GAS);
let mut tx = tx.finalize();
let gas_costs = GasCosts::new(GasCostsValuesV5::free().into());
let predicate_param =
PredicateParameters::default().with_max_gas_per_predicate(MAX_PREDICATE_GAS);
let fee_param = FeeParameters::default().with_gas_per_byte(0);

let mut consensus_params = ConsensusParameters::standard();
consensus_params.set_gas_costs(gas_costs.clone());
consensus_params.set_predicate_params(predicate_param);
consensus_params.set_tx_params(tx_param);
consensus_params.set_fee_params(fee_param);
tx.estimate_predicates(
&consensus_params.clone().into(),
MemoryInstance::new(),
&EmptyStorage,
)
.unwrap();
dbg!("estimation done");
let tx = tx
.into_checked(BlockHeight::new(0), &consensus_params)
.unwrap();
dbg!(client.deploy(tx.clone()));
}
1 change: 1 addition & 0 deletions fuel-vm/src/tests/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ fn transaction__execution__works_current_height_expiration() {
}

/// Malleable fields should not affect validity of the create transaction
#[allow(deprecated)]
#[test]
fn malleable_fields_do_not_affect_validity_of_create() {
let params = ConsensusParameters::default();
Expand Down

0 comments on commit 4618cf6

Please sign in to comment.