Skip to content

Commit

Permalink
Refactor most constants as configurable parameters (#130)
Browse files Browse the repository at this point in the history
* Refactor most constants as configurable parameters

* use u64 for consensus parameters
  • Loading branch information
Voxelot authored May 25, 2022
1 parent c90a2b7 commit 75fbc48
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 121 deletions.
37 changes: 0 additions & 37 deletions src/consts.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,6 @@
use fuel_types::bytes::WORD_SIZE;
use fuel_types::{Bytes32, Salt};

/// Maximum contract size, in bytes.
pub const CONTRACT_MAX_SIZE: u64 = 16 * 1024 * 1024;

/// Maximum number of inputs.
pub const MAX_INPUTS: u8 = 255;

/// Maximum number of outputs.
pub const MAX_OUTPUTS: u8 = 255;

/// Maximum number of witnesses.
pub const MAX_WITNESSES: u8 = 255;

/// Maximum gas per transaction.
pub const MAX_GAS_PER_TX: u64 = 100_000_000;

// TODO set max script length const
/// Maximum length of script, in instructions.
pub const MAX_SCRIPT_LENGTH: u64 = 1024 * 1024;

// TODO set max script length const
/// Maximum length of script data, in bytes.
pub const MAX_SCRIPT_DATA_LENGTH: u64 = 1024 * 1024;

/// Maximum number of static contracts.
pub const MAX_STATIC_CONTRACTS: u64 = 255;

/// Maximum number of initial storage slots.
pub const MAX_STORAGE_SLOTS: u16 = 255;

// TODO set max predicate length value
/// Maximum length of predicate, in instructions.
pub const MAX_PREDICATE_LENGTH: u64 = 1024 * 1024;

// TODO set max predicate data length value
/// Maximum length of predicate data, in bytes.
pub const MAX_PREDICATE_DATA_LENGTH: u64 = 1024 * 1024;

pub const TRANSACTION_SCRIPT_FIXED_SIZE: usize = WORD_SIZE // Identifier
+ WORD_SIZE // Gas price
+ WORD_SIZE // Gas limit
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ pub use receipt::{Receipt, ScriptExecutionResult};

#[cfg(feature = "alloc")]
pub use transaction::{
Input, Metadata, Output, StorageSlot, Transaction, TransactionRepr, TxId, UtxoId,
ValidationError, Witness,
consensus_parameters::*, Input, Metadata, Output, StorageSlot, Transaction, TransactionRepr,
TxId, UtxoId, ValidationError, Witness,
};
14 changes: 3 additions & 11 deletions src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ mod id;
#[cfg(feature = "std")]
mod txio;

pub mod consensus_parameters;

pub use metadata::Metadata;
pub use repr::TransactionRepr;
pub use types::{Input, Output, StorageSlot, UtxoId, Witness};
Expand Down Expand Up @@ -76,17 +78,7 @@ impl Default for Transaction {
// The Return op is mandatory for the execution of any context
let script = Opcode::RET(0x10).to_bytes().to_vec();

Transaction::script(
0,
MAX_GAS_PER_TX,
0,
0,
script,
vec![],
vec![],
vec![],
vec![],
)
Transaction::script(0, 1, 0, 0, script, vec![], vec![], vec![], vec![])
}
}

Expand Down
63 changes: 63 additions & 0 deletions src/transaction/consensus_parameters.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/// Consensus configurable parameters used for verifying transactions

#[derive(Copy, Clone, Debug, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ConsensusParameters {
/// Maximum contract size, in bytes.
pub contract_max_size: u64,
/// Maximum number of inputs.
pub max_inputs: u64,
/// Maximum number of outputs.
pub max_outputs: u64,
/// Maximum number of witnesses.
pub max_witnesses: u64,
/// Maximum gas per transaction.
pub max_gas_per_tx: u64,
/// Maximum length of script, in instructions.
pub max_script_length: u64,
/// Maximum length of script data, in bytes.
pub max_script_data_length: u64,
/// Maximum number of static contracts.
pub max_static_contracts: u64,
/// Maximum number of initial storage slots.
pub max_storage_slots: u64,
/// Maximum length of predicate, in instructions.
pub max_predicate_length: u64,
/// Maximum length of predicate data, in bytes.
pub max_predicate_data_length: u64,
}

impl Default for ConsensusParameters {
fn default() -> Self {
use default_parameters::*;
Self {
contract_max_size: CONTRACT_MAX_SIZE,
max_inputs: MAX_INPUTS,
max_outputs: MAX_OUTPUTS,
max_witnesses: MAX_WITNESSES,
max_gas_per_tx: MAX_GAS_PER_TX,
max_script_length: MAX_SCRIPT_LENGTH,
max_script_data_length: MAX_SCRIPT_DATA_LENGTH,
max_static_contracts: MAX_STATIC_CONTRACTS,
max_storage_slots: MAX_STORAGE_SLOTS,
max_predicate_length: MAX_PREDICATE_LENGTH,
max_predicate_data_length: MAX_PREDICATE_DATA_LENGTH,
}
}
}

/// Arbitrary default consensus parameters. While best-efforts are made to adjust these to
/// reasonable settings, they may not be useful for every network instantiation.
pub mod default_parameters {
pub const CONTRACT_MAX_SIZE: u64 = 16 * 1024 * 1024;
pub const MAX_INPUTS: u64 = 255;
pub const MAX_OUTPUTS: u64 = 255;
pub const MAX_WITNESSES: u64 = 255;
pub const MAX_GAS_PER_TX: u64 = 100_000_000;
pub const MAX_SCRIPT_LENGTH: u64 = 1024 * 1024;
pub const MAX_SCRIPT_DATA_LENGTH: u64 = 1024 * 1024;
pub const MAX_STATIC_CONTRACTS: u64 = 255;
pub const MAX_STORAGE_SLOTS: u64 = 255;
pub const MAX_PREDICATE_LENGTH: u64 = 1024 * 1024;
pub const MAX_PREDICATE_DATA_LENGTH: u64 = 1024 * 1024;
}
2 changes: 1 addition & 1 deletion src/transaction/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl Transaction {

#[cfg(all(test, feature = "random"))]
mod tests {
use crate::consts::MAX_GAS_PER_TX;
use crate::default_parameters::MAX_GAS_PER_TX;
use crate::*;

use fuel_tx_test_helpers::{generate_bytes, generate_nonempty_bytes};
Expand Down
50 changes: 33 additions & 17 deletions src/transaction/validation.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use super::{Input, Output, Transaction, Witness};
use crate::consts::*;
use crate::transaction::internals;

use fuel_crypto::Hasher;
Expand All @@ -13,6 +12,7 @@ use fuel_crypto::{Message, Signature};

mod error;

use crate::transaction::consensus_parameters::ConsensusParameters;
pub use error::ValidationError;

impl Input {
Expand All @@ -23,8 +23,9 @@ impl Input {
txhash: &Bytes32,
outputs: &[Output],
witnesses: &[Witness],
parameters: &ConsensusParameters,
) -> Result<(), ValidationError> {
self.validate_without_signature(index, outputs, witnesses)?;
self.validate_without_signature(index, outputs, witnesses, parameters)?;
self.validate_signature(index, txhash, witnesses)?;

Ok(())
Expand Down Expand Up @@ -76,16 +77,18 @@ impl Input {
index: usize,
outputs: &[Output],
witnesses: &[Witness],
parameters: &ConsensusParameters,
) -> Result<(), ValidationError> {
match self {
Self::CoinPredicate { predicate, .. }
if predicate.is_empty() || predicate.len() > MAX_PREDICATE_LENGTH as usize =>
if predicate.is_empty()
|| predicate.len() > parameters.max_predicate_length as usize =>
{
Err(ValidationError::InputCoinPredicateLength { index })
}

Self::CoinPredicate { predicate_data, .. }
if predicate_data.len() > MAX_PREDICATE_DATA_LENGTH as usize =>
if predicate_data.len() > parameters.max_predicate_data_length as usize =>
{
Err(ValidationError::InputCoinPredicateDataLength { index })
}
Expand Down Expand Up @@ -143,8 +146,12 @@ impl Output {

impl Transaction {
#[cfg(feature = "std")]
pub fn validate(&self, block_height: Word) -> Result<(), ValidationError> {
self.validate_without_signature(block_height)?;
pub fn validate(
&self,
block_height: Word,
parameters: &ConsensusParameters,
) -> Result<(), ValidationError> {
self.validate_without_signature(block_height, parameters)?;
self.validate_input_signature()?;

Ok(())
Expand All @@ -164,24 +171,28 @@ impl Transaction {
Ok(())
}

pub fn validate_without_signature(&self, block_height: Word) -> Result<(), ValidationError> {
if self.gas_limit() > MAX_GAS_PER_TX {
pub fn validate_without_signature(
&self,
block_height: Word,
parameters: &ConsensusParameters,
) -> Result<(), ValidationError> {
if self.gas_limit() > parameters.max_gas_per_tx {
Err(ValidationError::TransactionGasLimit)?
}

if block_height < self.maturity() as Word {
Err(ValidationError::TransactionMaturity)?;
}

if self.inputs().len() > MAX_INPUTS as usize {
if self.inputs().len() > parameters.max_inputs as usize {
Err(ValidationError::TransactionInputsMax)?
}

if self.outputs().len() > MAX_OUTPUTS as usize {
if self.outputs().len() > parameters.max_outputs as usize {
Err(ValidationError::TransactionOutputsMax)?
}

if self.witnesses().len() > MAX_WITNESSES as usize {
if self.witnesses().len() > parameters.max_witnesses as usize {
Err(ValidationError::TransactionWitnessesMax)?
}

Expand Down Expand Up @@ -231,7 +242,12 @@ impl Transaction {
.iter()
.enumerate()
.try_for_each(|(index, input)| {
input.validate_without_signature(index, self.outputs(), self.witnesses())
input.validate_without_signature(
index,
self.outputs(),
self.witnesses(),
parameters,
)
})?;

self.outputs()
Expand Down Expand Up @@ -272,11 +288,11 @@ impl Transaction {
script_data,
..
} => {
if script.len() > MAX_SCRIPT_LENGTH as usize {
if script.len() > parameters.max_script_length as usize {
Err(ValidationError::TransactionScriptLength)?;
}

if script_data.len() > MAX_SCRIPT_DATA_LENGTH as usize {
if script_data.len() > parameters.max_script_data_length as usize {
Err(ValidationError::TransactionScriptDataLength)?;
}

Expand Down Expand Up @@ -308,13 +324,13 @@ impl Transaction {
.map(|w| w.as_ref().len() as Word)
.ok_or(ValidationError::TransactionCreateBytecodeWitnessIndex)?;

if bytecode_witness_len > CONTRACT_MAX_SIZE
if bytecode_witness_len > parameters.contract_max_size
|| bytecode_witness_len / 4 != *bytecode_length
{
return Err(ValidationError::TransactionCreateBytecodeLen);
}

if static_contracts.len() > MAX_STATIC_CONTRACTS as usize {
if static_contracts.len() > parameters.max_static_contracts as usize {
Err(ValidationError::TransactionCreateStaticContractsMax)?;
}

Expand All @@ -324,7 +340,7 @@ impl Transaction {

// Restrict to subset of u16::MAX, allowing this to be increased in the future
// in a non-breaking way.
if storage_slots.len() > MAX_STORAGE_SLOTS as usize {
if storage_slots.len() > parameters.max_storage_slots as usize {
return Err(ValidationError::TransactionCreateStorageSlotMax);
}

Expand Down
3 changes: 1 addition & 2 deletions tests/bytes.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use fuel_asm::Opcode;
use fuel_crypto::Hasher;
use fuel_tx::consts::MAX_GAS_PER_TX;
use fuel_tx::*;
use fuel_tx::{default_parameters::*, *};
use fuel_tx_test_helpers::{generate_bytes, generate_nonempty_bytes};
use fuel_types::{bytes, ContractId, Immediate24};
use rand::rngs::StdRng;
Expand Down
Loading

0 comments on commit 75fbc48

Please sign in to comment.