use fuel_crypto::Hasher;
use fuel_tx::{
field::{Inputs, Outputs, ReceiptsRoot, Script as ScriptField, Witnesses},
Script, TransactionBuilder,
};
use fuel_types::bytes;
use fuel_vm::consts::*;
use rand::{rngs::StdRng, Rng, SeedableRng};
use fuel_vm::prelude::*;
#[test]
fn metadata() {
let rng = &mut StdRng::seed_from_u64(2322u64);
let mut storage = MemoryStorage::default();
let gas_price = 0;
let gas_limit = 1_000_000;
let maturity = 0;
let height = 0;
let params = ConsensusParameters::default();
let gas_costs = GasCosts::default();
#[rustfmt::skip]
let routine_metadata_is_caller_external: Vec<Opcode> = vec![
Opcode::gm(0x10, GMArgs::IsCallerExternal),
Opcode::gm(0x11, GMArgs::GetCaller),
Opcode::LOG(0x10, 0x00, 0x00, 0x00),
Opcode::MOVI(0x20, ContractId::LEN as Immediate18),
Opcode::LOGD(0x00, 0x00, 0x11, 0x20),
Opcode::RET(REG_ONE),
];
let salt: Salt = rng.gen();
let program: Witness = routine_metadata_is_caller_external
.into_iter()
.collect::<Vec<u8>>()
.into();
let contract = Contract::from(program.as_ref());
let contract_root = contract.root();
let state_root = Contract::default_state_root();
let contract_metadata = contract.id(&salt, &contract_root, &state_root);
let output = Output::contract_created(contract_metadata, state_root);
let bytecode_witness = 0;
let tx = Transaction::create(
gas_price,
gas_limit,
maturity,
bytecode_witness,
salt,
vec![],
vec![],
vec![output],
vec![program],
)
.into_checked(height, ¶ms, &gas_costs)
.expect("failed to check tx");
assert!(Transactor::new(&mut storage, Default::default(), gas_costs.clone())
.transact(tx)
.is_success());
let mut routine_call_metadata_contract: Vec<Opcode> = vec![
Opcode::gm(0x10, GMArgs::IsCallerExternal),
Opcode::LOG(0x10, 0x00, 0x00, 0x00),
Opcode::MOVI(0x10, (Bytes32::LEN + 2 * Bytes8::LEN) as Immediate18),
Opcode::ALOC(0x10),
Opcode::ADDI(0x10, REG_HP, 1),
];
contract_metadata.as_ref().iter().enumerate().for_each(|(i, b)| {
routine_call_metadata_contract.push(Opcode::MOVI(0x11, *b as Immediate18));
routine_call_metadata_contract.push(Opcode::SB(0x10, 0x11, i as Immediate12));
});
routine_call_metadata_contract.push(Opcode::CALL(0x10, REG_ZERO, 0x10, REG_CGAS));
routine_call_metadata_contract.push(Opcode::RET(REG_ONE));
let salt: Salt = rng.gen();
let program: Witness = routine_call_metadata_contract.into_iter().collect::<Vec<u8>>().into();
let contract = Contract::from(program.as_ref());
let contract_root = contract.root();
let state_root = Contract::default_state_root();
let contract_call = contract.id(&salt, &contract_root, &state_root);
let output = Output::contract_created(contract_call, state_root);
let bytecode_witness = 0;
let tx = Transaction::create(
gas_price,
gas_limit,
maturity,
bytecode_witness,
salt,
vec![],
vec![],
vec![output],
vec![program],
)
.into_checked(height, ¶ms, &gas_costs)
.expect("failed to check tx");
assert!(Transactor::new(&mut storage, Default::default(), gas_costs.clone())
.transact(tx)
.is_success());
let mut inputs = vec![];
let mut outputs = vec![];
inputs.push(Input::contract(
rng.gen(),
rng.gen(),
rng.gen(),
rng.gen(),
contract_call,
));
outputs.push(Output::contract(0, rng.gen(), rng.gen()));
inputs.push(Input::contract(
rng.gen(),
rng.gen(),
rng.gen(),
rng.gen(),
contract_metadata,
));
outputs.push(Output::contract(1, rng.gen(), rng.gen()));
let mut script = vec![
Opcode::MOVI(0x10, (Bytes32::LEN + 2 * Bytes8::LEN) as Immediate18),
Opcode::ALOC(0x10),
Opcode::ADDI(0x10, REG_HP, 1),
];
contract_call.as_ref().iter().enumerate().for_each(|(i, b)| {
script.push(Opcode::MOVI(0x11, *b as Immediate18));
script.push(Opcode::SB(0x10, 0x11, i as Immediate12));
});
script.push(Opcode::CALL(0x10, REG_ZERO, 0x10, REG_CGAS));
script.push(Opcode::RET(REG_ONE));
#[allow(clippy::iter_cloned_collect)] let script = script.iter().copied().collect::<Vec<u8>>();
let tx = Transaction::script(gas_price, gas_limit, maturity, script, vec![], inputs, outputs, vec![])
.into_checked(height, ¶ms, &gas_costs)
.expect("failed to check tx");
let receipts = Transactor::new(&mut storage, Default::default(), gas_costs)
.transact(tx)
.receipts()
.expect("Failed to transact")
.to_owned();
let ra = receipts[1]
.ra()
.expect("IsCallerExternal should set $rA as boolean flag");
assert_eq!(1, ra);
let ra = receipts[3]
.ra()
.expect("IsCallerExternal should set $rA as boolean flag");
assert_eq!(0, ra);
let contract_call = Hasher::hash(contract_call.as_ref());
let digest = receipts[4].digest().expect("GetCaller should return contract Id");
assert_eq!(&contract_call, digest);
}
#[test]
fn get_transaction_fields() {
let rng = &mut StdRng::seed_from_u64(2322u64);
let mut client = MemoryClient::default();
let gas_price = 1;
let gas_limit = 1_000_000;
let maturity = 50;
let height = 122;
let input = 10_000_000;
let params = ConsensusParameters::default();
let contract: Witness = vec![Opcode::RET(0x01)].into_iter().collect::<Vec<u8>>().into();
let salt = rng.gen();
let code_root = Contract::root_from_code(contract.as_ref());
let storage_slots = vec![];
let state_root = Contract::initial_state_root(storage_slots.iter());
let contract_id = Contract::from(contract.as_ref()).id(&salt, &code_root, &state_root);
let tx = TransactionBuilder::create(contract, salt, storage_slots)
.add_output(Output::contract_created(contract_id, state_root))
.finalize_checked(height, ¶ms, client.gas_costs());
client.deploy(tx);
let predicate = vec![Opcode::RET(REG_ONE)].into_iter().collect::<Vec<u8>>();
let mut predicate_data = vec![0u8; 512];
rng.fill(predicate_data.as_mut_slice());
let owner = (*Contract::root_from_code(&predicate)).into();
let input_coin_predicate = Input::coin_predicate(
rng.gen(),
owner,
1_500,
rng.gen(),
rng.gen(),
100,
predicate.clone(),
predicate_data.clone(),
);
let contract_input_index = 2;
let message_amount = 5_500;
let message_nonce = 0xbeef;
let mut message_data = vec![0u8; 256];
rng.fill(message_data.as_mut_slice());
let mut m_data = vec![0u8; 64];
let m_predicate = vec![Opcode::RET(REG_ONE)].into_iter().collect::<Vec<u8>>();
let mut m_predicate_data = vec![0u8; 512];
rng.fill(m_data.as_mut_slice());
rng.fill(m_predicate_data.as_mut_slice());
let owner = Input::predicate_owner(&m_predicate);
let message_predicate = Input::message_predicate(
rng.gen(),
rng.gen(),
owner,
7_500,
0xdead,
m_data.clone(),
m_predicate.clone(),
m_predicate_data.clone(),
);
let asset = rng.gen();
let asset_amt = 27;
let output_message_amt = 3948;
let tx = TransactionBuilder::script(vec![], vec![])
.prepare_script(true)
.maturity(maturity)
.gas_price(gas_price)
.gas_limit(gas_limit)
.add_unsigned_coin_input(rng.gen(), rng.gen(), input, AssetId::zeroed(), rng.gen(), maturity)
.add_input(input_coin_predicate)
.add_input(Input::contract(
rng.gen(),
rng.gen(),
state_root,
rng.gen(),
contract_id,
))
.add_output(Output::variable(rng.gen(), rng.gen(), rng.gen()))
.add_output(Output::contract(contract_input_index, rng.gen(), state_root))
.add_witness(Witness::from(b"some-data".to_vec()))
.add_unsigned_message_input(
rng.gen(),
rng.gen(),
message_nonce,
message_amount,
message_data.clone(),
)
.add_input(message_predicate)
.add_unsigned_coin_input(rng.gen(), rng.gen(), asset_amt, asset, rng.gen(), maturity)
.add_output(Output::coin(rng.gen(), asset_amt, asset))
.add_output(Output::message(rng.gen(), output_message_amt))
.finalize_checked(height, ¶ms, client.gas_costs());
let inputs = tx.as_ref().inputs();
let outputs = tx.as_ref().outputs();
let witnesses = tx.as_ref().witnesses();
let inputs_bytes: Vec<Vec<u8>> = inputs.iter().map(|i| i.clone().to_bytes()).collect();
let outputs_bytes: Vec<Vec<u8>> = outputs.iter().map(|o| o.clone().to_bytes()).collect();
let witnesses_bytes: Vec<Vec<u8>> = witnesses.iter().map(|w| w.clone().to_bytes()).collect();
let receipts_root = tx.as_ref().receipts_root();
#[rustfmt::skip]
let cases = vec![
inputs_bytes[0].clone(), outputs_bytes[0].clone(), witnesses_bytes[1].clone(), receipts_root.to_vec(), inputs[0].utxo_id().unwrap().clone().to_bytes(), inputs[0].input_owner().unwrap().to_vec(), inputs[0].asset_id().unwrap().to_vec(), predicate.clone(), predicate_data.clone(), inputs[2].utxo_id().unwrap().clone().to_bytes(), inputs[2].balance_root().unwrap().to_vec(), inputs[2].state_root().unwrap().to_vec(), inputs[2].contract_id().unwrap().to_vec(), inputs[3].message_id().unwrap().to_vec(), inputs[3].sender().unwrap().to_vec(), inputs[3].recipient().unwrap().to_vec(), m_data.clone(), m_predicate.clone(), m_predicate_data.clone(), outputs[2].to().unwrap().to_vec(), outputs[2].asset_id().unwrap().to_vec(), outputs[1].balance_root().unwrap().to_vec(), outputs[1].state_root().unwrap().to_vec(), outputs[3].recipient().unwrap().to_vec(), witnesses[1].as_ref().to_vec(), inputs[0].tx_pointer().unwrap().clone().to_bytes(), inputs[2].tx_pointer().unwrap().clone().to_bytes(), ];
let script_reserved_words = 300 * WORD_SIZE;
let script_offset = params.tx_offset() + Script::script_offset_static();
let script_data_offset = script_offset + bytes::padded_len_usize(script_reserved_words);
let script_data: Vec<u8> = cases.iter().flat_map(|c| c.iter()).copied().collect();
#[rustfmt::skip]
let mut script: Vec<u8> = vec![
Opcode::MOVI(0x20, 0x01),
Opcode::gtf(0x30, 0x19, GTFArgs::ScriptData),
Opcode::MOVI(0x19, 0x00),
Opcode::MOVI(0x11, TransactionRepr::Script as Immediate18),
Opcode::gtf(0x10, 0x19, GTFArgs::Type),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, gas_price as Immediate18),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::ScriptGasPrice),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x00),
Opcode::MOVI(0x11, (gas_limit & 0x3ffff) as Immediate18),
Opcode::MOVI(0x12, (gas_limit >> 18) as Immediate18),
Opcode::SLLI(0x12, 0x12, 18),
Opcode::OR(0x11, 0x11, 0x12),
Opcode::gtf(0x10, 0x19, GTFArgs::ScriptGasLimit),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x00),
Opcode::MOVI(0x11, maturity as Immediate18),
Opcode::gtf(0x10, 0x19, GTFArgs::ScriptMaturity),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x00),
Opcode::MOVI(0x11, inputs.len() as Immediate18),
Opcode::gtf(0x10, 0x19, GTFArgs::ScriptInputsCount),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x00),
Opcode::MOVI(0x11, outputs.len() as Immediate18),
Opcode::gtf(0x10, 0x19, GTFArgs::ScriptOutputsCount),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x00),
Opcode::MOVI(0x11, witnesses.len() as Immediate18),
Opcode::gtf(0x10, 0x19, GTFArgs::ScriptWitnessesCound),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::ScriptInputAtIndex),
Opcode::MOVI(0x11, cases[0].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::ScriptOutputAtIndex),
Opcode::MOVI(0x11, cases[1].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x01),
Opcode::gtf(0x10, 0x19, GTFArgs::ScriptWitnessAtIndex),
Opcode::MOVI(0x11, cases[2].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, script_reserved_words as Immediate18),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::ScriptLength),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, script_data.len() as Immediate18),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::ScriptDataLength),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x01),
Opcode::gtf(0x10, 0x19, GTFArgs::ScriptReceiptsRoot),
Opcode::MOVI(0x11, cases[3].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, script_offset as Immediate18),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::Script),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, script_data_offset as Immediate18),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::ScriptData),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, InputRepr::Coin as Immediate18),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::InputType),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::InputCoinTxId),
Opcode::MOVI(0x11, cases[4].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, inputs[0].utxo_id().unwrap().output_index() as Immediate18),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::InputCoinOutputIndex),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::InputCoinOwner),
Opcode::MOVI(0x11, cases[5].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, (inputs[0].amount().unwrap() & 0x3ffff) as Immediate18),
Opcode::MOVI(0x12, (inputs[0].amount().unwrap() >> 18) as Immediate18),
Opcode::SLLI(0x12, 0x12, 18),
Opcode::OR(0x11, 0x11, 0x12),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::InputCoinAmount),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::InputCoinAssetId),
Opcode::MOVI(0x11, cases[6].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, inputs[0].witness_index().unwrap() as Immediate18),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::InputCoinWitnessIndex),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, inputs[0].maturity().unwrap() as Immediate18),
Opcode::MOVI(0x19, 0x00),
Opcode::gtf(0x10, 0x19, GTFArgs::InputCoinMaturity),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, predicate.len() as Immediate18),
Opcode::MOVI(0x19, 0x01),
Opcode::gtf(0x10, 0x19, GTFArgs::InputCoinPredicateLength),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, predicate_data.len() as Immediate18),
Opcode::MOVI(0x19, 0x01),
Opcode::gtf(0x10, 0x19, GTFArgs::InputCoinPredicateDataLength),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x01),
Opcode::gtf(0x10, 0x19, GTFArgs::InputCoinPredicate),
Opcode::MOVI(0x11, cases[7].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x01),
Opcode::gtf(0x10, 0x19, GTFArgs::InputCoinPredicateData),
Opcode::MOVI(0x11, cases[8].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, contract_input_index as Immediate18),
Opcode::gtf(0x10, 0x19, GTFArgs::InputContractTxId),
Opcode::MOVI(0x11, cases[9].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, 0x01),
Opcode::MOVI(0x19, contract_input_index as Immediate18),
Opcode::gtf(0x10, 0x19, GTFArgs::InputContractOutputIndex),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, contract_input_index as Immediate18),
Opcode::gtf(0x10, 0x19, GTFArgs::InputContractBalanceRoot),
Opcode::MOVI(0x11, cases[10].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, contract_input_index as Immediate18),
Opcode::gtf(0x10, 0x19, GTFArgs::InputContractStateRoot),
Opcode::MOVI(0x11, cases[11].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, contract_input_index as Immediate18),
Opcode::gtf(0x10, 0x19, GTFArgs::InputContractId),
Opcode::MOVI(0x11, cases[12].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x03),
Opcode::gtf(0x10, 0x19, GTFArgs::InputMessageId),
Opcode::MOVI(0x11, cases[13].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x03),
Opcode::gtf(0x10, 0x19, GTFArgs::InputMessageSender),
Opcode::MOVI(0x11, cases[14].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x03),
Opcode::gtf(0x10, 0x19, GTFArgs::InputMessageRecipient),
Opcode::MOVI(0x11, cases[15].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, message_amount as Immediate18),
Opcode::MOVI(0x19, 0x03),
Opcode::gtf(0x10, 0x19, GTFArgs::InputMessageAmount),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, message_nonce as Immediate18),
Opcode::MOVI(0x19, 0x03),
Opcode::gtf(0x10, 0x19, GTFArgs::InputMessageNonce),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, 0x02),
Opcode::MOVI(0x19, 0x03),
Opcode::gtf(0x10, 0x19, GTFArgs::InputMessageWitnessIndex),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, message_data.len() as Immediate18),
Opcode::MOVI(0x19, 0x03),
Opcode::gtf(0x10, 0x19, GTFArgs::InputMessageDataLength),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, m_predicate.len() as Immediate18),
Opcode::MOVI(0x19, 0x04),
Opcode::gtf(0x10, 0x19, GTFArgs::InputMessagePredicateLength),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, m_predicate_data.len() as Immediate18),
Opcode::MOVI(0x19, 0x04),
Opcode::gtf(0x10, 0x19, GTFArgs::InputMessagePredicateDataLength),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x04),
Opcode::gtf(0x10, 0x19, GTFArgs::InputMessageData),
Opcode::MOVI(0x11, cases[16].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x04),
Opcode::gtf(0x10, 0x19, GTFArgs::InputMessagePredicate),
Opcode::MOVI(0x11, cases[17].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x04),
Opcode::gtf(0x10, 0x19, GTFArgs::InputMessagePredicateData),
Opcode::MOVI(0x11, cases[18].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, OutputRepr::Contract as Immediate18),
Opcode::MOVI(0x19, 0x01),
Opcode::gtf(0x10, 0x19, GTFArgs::OutputType),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x02),
Opcode::gtf(0x10, 0x19, GTFArgs::OutputCoinTo),
Opcode::MOVI(0x11, cases[19].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, asset_amt as Immediate18),
Opcode::MOVI(0x19, 0x02),
Opcode::gtf(0x10, 0x19, GTFArgs::OutputCoinAmount),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x02),
Opcode::gtf(0x10, 0x19, GTFArgs::OutputCoinAssetId),
Opcode::MOVI(0x11, cases[20].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, asset_amt as Immediate18),
Opcode::MOVI(0x19, 0x02),
Opcode::gtf(0x10, 0x19, GTFArgs::OutputCoinAmount),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, contract_input_index as Immediate18),
Opcode::MOVI(0x19, 0x01),
Opcode::gtf(0x10, 0x19, GTFArgs::OutputContractInputIndex),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x01),
Opcode::gtf(0x10, 0x19, GTFArgs::OutputContractBalanceRoot),
Opcode::MOVI(0x11, cases[21].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x01),
Opcode::gtf(0x10, 0x19, GTFArgs::OutputContractStateRoot),
Opcode::MOVI(0x11, cases[22].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x03),
Opcode::gtf(0x10, 0x19, GTFArgs::OutputMessageRecipient),
Opcode::MOVI(0x11, cases[23].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, 0),
Opcode::MOVI(0x19, 0x03),
Opcode::gtf(0x10, 0x19, GTFArgs::OutputMessageAmount),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x11, witnesses[1].as_ref().len() as Immediate18),
Opcode::MOVI(0x19, 0x01),
Opcode::gtf(0x10, 0x19, GTFArgs::WitnessDataLength),
Opcode::EQ(0x10, 0x10, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0x01),
Opcode::gtf(0x10, 0x19, GTFArgs::WitnessData),
Opcode::MOVI(0x11, cases[24].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, 0),
Opcode::gtf(0x10, 0x19, GTFArgs::InputCoinTxPointer),
Opcode::MOVI(0x11, cases[25].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::MOVI(0x19, contract_input_index as Immediate18),
Opcode::gtf(0x10, 0x19, GTFArgs::InputContractTxPointer),
Opcode::MOVI(0x11, cases[26].len() as Immediate18),
Opcode::MEQ(0x10, 0x10, 0x30, 0x11),
Opcode::ADD(0x30, 0x30, 0x11),
Opcode::AND(0x20, 0x20, 0x10),
Opcode::LOG(0x20, 0x00, 0x00, 0x00),
Opcode::RET(0x00)
].into_iter().collect();
while script.len() < script_reserved_words {
script.extend(Opcode::NOOP.to_bytes());
}
assert_eq!(script.len(), script_reserved_words);
let mut builder = TransactionBuilder::script(script, script_data);
tx.as_ref().inputs().iter().for_each(|i| {
builder.add_input(i.clone());
});
tx.as_ref().outputs().iter().for_each(|o| {
builder.add_output(*o);
});
tx.as_ref().witnesses().iter().for_each(|w| {
builder.add_witness(w.clone());
});
let tx = builder
.maturity(maturity)
.gas_price(gas_price)
.gas_limit(gas_limit)
.finalize_checked_basic(height, ¶ms);
let receipts = client.transact(tx);
let success = receipts.iter().any(|r| matches!(r, Receipt::Log{ ra, .. } if ra == &1));
assert!(success);
}