Skip to content

Commit

Permalink
fix: predicate witness data access (#1156)
Browse files Browse the repository at this point in the history
  • Loading branch information
hal3e authored Oct 24, 2023
1 parent 8121443 commit 66aef68
Show file tree
Hide file tree
Showing 11 changed files with 280 additions and 59 deletions.
8 changes: 4 additions & 4 deletions packages/fuels-accounts/src/accounts_utils.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use fuel_tx::{ConsensusParameters, Output, Receipt};
use fuel_tx::{Output, Receipt};
use fuel_types::MessageId;
use fuels_core::{
constants::BASE_ASSET_ID,
types::{
bech32::Bech32Address,
errors::{error, Error, Result},
input::Input,
transaction_builders::TransactionBuilder,
transaction_builders::{NetworkInfo, TransactionBuilder},
},
};

Expand All @@ -16,11 +16,11 @@ pub fn extract_message_id(receipts: &[Receipt]) -> Option<MessageId> {

pub fn calculate_base_amount_with_fee(
tb: &impl TransactionBuilder,
consensus_params: &ConsensusParameters,
network_info: &NetworkInfo,
previous_base_amount: u64,
) -> Result<u64> {
let transaction_fee = tb
.fee_checked_from_tx(consensus_params)?
.fee_checked_from_tx(network_info)?
.ok_or(error!(InvalidData, "Error calculating TransactionFee"))?;

let mut new_base_amount = transaction_fee.max_fee() + previous_base_amount;
Expand Down
4 changes: 2 additions & 2 deletions packages/fuels-accounts/src/predicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,9 @@ impl Account for Predicate {
mut tb: Tb,
previous_base_amount: u64,
) -> Result<Tb::TxType> {
let consensus_parameters = self.try_provider()?.consensus_parameters();
let network_info = self.try_provider()?.network_info().await?;
let new_base_amount =
calculate_base_amount_with_fee(&tb, &consensus_parameters, previous_base_amount)?;
calculate_base_amount_with_fee(&tb, &network_info, previous_base_amount)?;

let new_base_inputs = self
.get_asset_inputs_for_amount(BASE_ASSET_ID, new_base_amount)
Expand Down
29 changes: 20 additions & 9 deletions packages/fuels-accounts/src/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,25 @@ impl Provider {
Ok(tx_id)
}

pub async fn send_transaction<T: Transaction>(&self, tx: T) -> Result<TxId> {
pub async fn send_transaction<T: Transaction>(&self, mut tx: T) -> Result<TxId> {
tx.precompute(&self.chain_id())?;

let chain_info = self.chain_info().await?;
tx.check_without_signatures(
chain_info.latest_block.header.height,
&self.consensus_parameters(),
)?;

if tx.is_using_predicates() {
tx.estimate_predicates(&self.consensus_parameters, &chain_info.gas_costs)?;
}

self.validate_transaction(tx.clone()).await?;

Ok(self.client.submit(&tx.into()).await?)
}

async fn validate_transaction<T: Transaction>(&self, tx: T) -> Result<()> {
let tolerance = 0.0;
let TransactionCost {
gas_used,
Expand All @@ -219,14 +237,7 @@ impl Provider {
));
}

let chain_info = self.chain_info().await?;
tx.check_without_signatures(
chain_info.latest_block.header.height,
&self.consensus_parameters(),
)?;

let tx_id = self.client.submit(&tx.into()).await?;
Ok(tx_id)
Ok(())
}

pub async fn tx_status(&self, tx_id: &TxId) -> ProviderResult<TxStatus> {
Expand Down
4 changes: 2 additions & 2 deletions packages/fuels-accounts/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,11 +264,11 @@ impl Account for WalletUnlocked {
mut tb: Tb,
previous_base_amount: u64,
) -> Result<Tb::TxType> {
let consensus_parameters = self.try_provider()?.consensus_parameters();
let network_info = self.try_provider()?.network_info().await?;
self.sign_transaction(&mut tb);

let new_base_amount =
calculate_base_amount_with_fee(&tb, &consensus_parameters, previous_base_amount)?;
calculate_base_amount_with_fee(&tb, &network_info, previous_base_amount)?;

let new_base_inputs = self
.get_asset_inputs_for_amount(BASE_ASSET_ID, new_base_amount)
Expand Down
61 changes: 24 additions & 37 deletions packages/fuels-core/src/types/transaction_builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ use std::collections::HashMap;
use fuel_asm::{op, GTFArgs, RegId};
use fuel_crypto::{Message as CryptoMessage, SecretKey, Signature};
use fuel_tx::{
field::{GasLimit, GasPrice, Witnesses},
Cacheable, ConsensusParameters, Create, Input as FuelInput, Output, Script, StorageSlot,
field::Witnesses, ConsensusParameters, Create, Input as FuelInput, Output, Script, StorageSlot,
Transaction as FuelTransaction, TransactionFee, TxPointer, UniqueIdentifier, Witness,
};
use fuel_types::{bytes::padded_len_usize, Bytes32, ChainId, MemLayout, Salt};
use fuel_vm::{checked_transaction::EstimatePredicates, gas::GasCosts};
use fuel_vm::gas::GasCosts;
use zeroize::{Zeroize, ZeroizeOnDrop};

use super::{chain_info::ChainInfo, node_info::NodeInfo};
Expand Down Expand Up @@ -65,7 +64,7 @@ pub trait TransactionBuilder: Send {

fn build(self) -> Result<Self::TxType>;
fn add_unresolved_signature(&mut self, owner: Bech32Address, secret_key: SecretKey);
fn fee_checked_from_tx(&self, params: &ConsensusParameters) -> Result<Option<TransactionFee>>;
fn fee_checked_from_tx(&self, network_info: &NetworkInfo) -> Result<Option<TransactionFee>>;
fn with_maturity(self, maturity: u32) -> Self;
fn with_gas_price(self, gas_price: u64) -> Self;
fn with_gas_limit(self, gas_limit: u64) -> Self;
Expand All @@ -86,25 +85,20 @@ macro_rules! impl_tx_trait {
impl TransactionBuilder for $ty {
type TxType = $tx_ty;
fn build(self) -> Result<$tx_ty> {
let uses_predicates = self.is_using_predicates();
let base_offset = if uses_predicates {
let is_using_predicates = self.is_using_predicates();
let base_offset = if is_using_predicates {
self.base_offset()
} else {
0
};

let network_info = self.network_info.clone();

let num_witnesses = self.num_witnesses()?;
let mut tx = self.resolve_fuel_tx(base_offset, num_witnesses)?;

tx.precompute(&network_info.chain_id())?;

if uses_predicates {
estimate_predicates(&mut tx, &network_info)?;
};
let tx = self.resolve_fuel_tx(base_offset, num_witnesses)?;

Ok($tx_ty { tx })
Ok($tx_ty {
tx,
is_using_predicates,
})
}

fn add_unresolved_signature(&mut self, owner: Bech32Address, secret_key: SecretKey) {
Expand All @@ -117,10 +111,21 @@ macro_rules! impl_tx_trait {

fn fee_checked_from_tx(
&self,
params: &ConsensusParameters,
network_info: &NetworkInfo,
) -> Result<Option<TransactionFee>> {
let tx = self.clone().build()?.tx;
Ok(TransactionFee::checked_from_tx(params, &tx))
let mut tx = self.clone().build()?;

if tx.is_using_predicates() {
tx.estimate_predicates(
&network_info.consensus_parameters,
&network_info.gas_costs,
)?;
};

Ok(TransactionFee::checked_from_tx(
&network_info.consensus_parameters,
&tx.tx,
))
}

fn with_maturity(mut self, maturity: u32) -> Self {
Expand Down Expand Up @@ -704,24 +709,6 @@ fn generate_missing_witnesses(
.collect()
}

fn estimate_predicates<T>(tx: &mut T, network_info: &NetworkInfo) -> Result<()>
where
T: GasLimit + GasPrice + EstimatePredicates,
{
let consensus_parameters = &network_info.consensus_parameters;

let gas_price = *tx.gas_price();
let gas_limit = *tx.gas_limit();
*tx.gas_price_mut() = 0;
*tx.gas_limit_mut() = consensus_parameters.max_gas_per_tx;

tx.estimate_predicates(consensus_parameters, &network_info.gas_costs)?;
*tx.gas_price_mut() = gas_price;
*tx.gas_limit_mut() = gas_limit;

Ok(())
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
87 changes: 84 additions & 3 deletions packages/fuels-core/src/types/wrappers/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ use fuel_tx::{
field::{
GasLimit, GasPrice, Inputs, Maturity, Outputs, Script as ScriptField, ScriptData, Witnesses,
},
Bytes32, Chargeable, ConsensusParameters, Create, FormatValidityChecks, Input, Output,
Salt as FuelSalt, Script, StorageSlot, Transaction as FuelTransaction, TransactionFee,
Bytes32, Cacheable, Chargeable, ConsensusParameters, Create, FormatValidityChecks, Input,
Output, Salt as FuelSalt, Script, StorageSlot, Transaction as FuelTransaction, TransactionFee,
UniqueIdentifier, Witness,
};

use fuel_types::ChainId;
use fuel_vm::{checked_transaction::EstimatePredicates, prelude::GasCosts};

use crate::types::Result;

Expand Down Expand Up @@ -98,6 +100,21 @@ pub trait Transaction: Into<FuelTransaction> + Clone {

fn witnesses(&self) -> &Vec<Witness>;

fn is_using_predicates(&self) -> bool;

/// Precompute transaction metadata. The metadata is required for
/// `check_without_signatures` validation.
fn precompute(&mut self, chain_id: &ChainId) -> Result<()>;

/// If a transactions contains predicates, we have to estimate them
/// before sending the transaction to the node. The estimation will check
/// all predicates and set the `predicate_gas_used` to the actual consumed gas.
fn estimate_predicates(
&mut self,
consensus_parameters: &ConsensusParameters,
gas_costs: &GasCosts,
) -> Result<()>;

/// Append witness and return the corresponding witness index
fn append_witness(&mut self, witness: Witness) -> usize;
}
Expand Down Expand Up @@ -214,6 +231,31 @@ impl Transaction for TransactionType {
}
}

fn is_using_predicates(&self) -> bool {
match self {
TransactionType::Script(tx) => tx.is_using_predicates(),
TransactionType::Create(tx) => tx.is_using_predicates(),
}
}

fn precompute(&mut self, chain_id: &ChainId) -> Result<()> {
match self {
TransactionType::Script(tx) => tx.precompute(chain_id),
TransactionType::Create(tx) => tx.precompute(chain_id),
}
}

fn estimate_predicates(
&mut self,
consensus_parameters: &ConsensusParameters,
gas_costs: &GasCosts,
) -> Result<()> {
match self {
TransactionType::Script(tx) => tx.estimate_predicates(consensus_parameters, gas_costs),
TransactionType::Create(tx) => tx.estimate_predicates(consensus_parameters, gas_costs),
}
}

fn append_witness(&mut self, witness: Witness) -> usize {
match self {
TransactionType::Script(tx) => tx.append_witness(witness),
Expand All @@ -227,6 +269,7 @@ macro_rules! impl_tx_wrapper {
#[derive(Debug, Clone)]
pub struct $wrapper {
pub(crate) tx: $wrapped,
pub(crate) is_using_predicates: bool,
}

impl From<$wrapper> for $wrapped {
Expand All @@ -243,7 +286,19 @@ macro_rules! impl_tx_wrapper {

impl From<$wrapped> for $wrapper {
fn from(tx: $wrapped) -> Self {
$wrapper { tx }
let is_using_predicates = tx.inputs().iter().any(|input| {
matches!(
input,
Input::CoinPredicate { .. }
| Input::MessageCoinPredicate { .. }
| Input::MessageDataPredicate { .. }
)
});

$wrapper {
tx,
is_using_predicates,
}
}
}

Expand Down Expand Up @@ -312,6 +367,32 @@ macro_rules! impl_tx_wrapper {
self.tx.witnesses()
}

fn is_using_predicates(&self) -> bool {
self.is_using_predicates
}

fn precompute(&mut self, chain_id: &ChainId) -> Result<()> {
Ok(self.tx.precompute(chain_id)?)
}

fn estimate_predicates(
&mut self,
consensus_parameters: &ConsensusParameters,
gas_costs: &GasCosts,
) -> Result<()> {
let gas_price = *self.tx.gas_price();
let gas_limit = *self.tx.gas_limit();
*self.tx.gas_price_mut() = 0;
*self.tx.gas_limit_mut() = consensus_parameters.max_gas_per_tx;

self.tx
.estimate_predicates(consensus_parameters, gas_costs)?;
*self.tx.gas_price_mut() = gas_price;
*self.tx.gas_limit_mut() = gas_limit;

Ok(())
}

fn append_witness(&mut self, witness: Witness) -> usize {
let idx = self.tx.witnesses().len();
self.tx.witnesses_mut().push(witness);
Expand Down
1 change: 1 addition & 0 deletions packages/fuels/Forc.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ members = [
'tests/logs/script_with_contract_logs',
'tests/predicates/basic_predicate',
'tests/predicates/predicate_configurables',
'tests/predicates/predicate_witnesses',
'tests/predicates/signatures',
'tests/scripts/arguments',
'tests/scripts/basic_script',
Expand Down
2 changes: 1 addition & 1 deletion packages/fuels/tests/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1644,7 +1644,7 @@ async fn heap_types_correctly_offset_in_create_transactions_w_storage_slots() ->
)?
.with_data(data)
.with_provider(provider);
let wallet: WalletUnlocked = wallet;

wallet
.transfer(
predicate.address(),
Expand Down
Loading

0 comments on commit 66aef68

Please sign in to comment.