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

Support transaction policies #623

Merged
merged 24 commits into from
Nov 9, 2023
Merged

Support transaction policies #623

merged 24 commits into from
Nov 9, 2023

Conversation

xgreenx
Copy link
Collaborator

@xgreenx xgreenx commented Nov 4, 2023

Closes #576 Closes FuelLabs/fuel-core#1398

Added support for transaction policies. The Script and Create
transactions received a new field, policies. Policies allow the addition
of some limits to the transaction to protect the user or specify some details regarding execution.

This change makes the GasPrice and Maturity fields optional, allowing to save space in the future. Also, this will enable us to support multidimensional prices later.

Along with this change, we introduced two new policies:

  • WitnessLimit - allows the limitation of the maximum size of witnesses in bytes for the contract. Because of the changes in the gas calculation model(the blockchain also charges the user for the witness data), the user should protect himself from the block producer or third parties blowing up witness data and draining the user's funds.
  • MaxFee - allows the upper bound for the maximum fee that users agree to pay for the transaction.

This change brings the following modification to the gas model:

  • The GasLimit only limits the script execution. Previously, the GasLimit also limited the predicate execution time, but it is not valid anymore. So, it is not possible to use the GasLimit for transaction cost limitations. A new MaxFee policy is a way to do that. The GasLimit field was removed from the Create transaction because it only relates to the script execution(which the Create transaction doesn't have).
  • The blockchain changes the user for the size of witness data(before it was free). There is no separate price for the storage, so it uses gas to charge the user. It affects the min_gas and min_fee calculation.
  • A new WhitnessLimit also impacts the max_gas and max_fee calculation along with the GasLimit(in the case of Create transaction only WitnessLimit affects the max_gas and max_fee).
  • The minimal gas also charges the user for transaction ID calculation.

The change has the following modification to the layout transaction:

  • The Create transaction doesn't have the GasLimit field anymore. Because the Create transaction doesn't have any script to execute
  • The Create and Script transactions don't have explicit maturity and gas_price fields. Instead, these fields can be set via a new policies field.
  • The Create and Script transactions have a new policies field with a unique canonical serialization and deserialization for optimal space consumption.

Other breaking changes caused by the change:

  • Each transaction requires setting the GasPrice policy.
  • Previously, GasLimit should be less than the MAX_GAS_PER_TX constant. After removing this field from the Create transaction, it is impossible to require it. Instead, it requires that max_gas <= MAX_GAS_PER_TX for any transaction. Consequently, any Script transaction that uses MAX_GAS_PER_TX as a GasLimit will always fail because of a new rule. Setting the estimated gas usage instead solves the problem.
  • If the max_fee > policies.max_fee, then transaction will be rejected.
  • If the witnessses_size > policies.witness_limit, then transaction will be rejected.
  • GTF opcode changed its hardcoded constants for fields. It should be updated according to the values from the specification on the Sway side.

Updated transaction validity rules according to policies.
Updated fee calculation and refund logic.
Fixed all tests.
@xgreenx xgreenx requested a review from a team November 4, 2023 22:46
@xgreenx xgreenx self-assigned this Nov 4, 2023
fuel-vm/src/interpreter/metadata.rs Show resolved Hide resolved
fuel-vm/src/interpreter/metadata.rs Show resolved Hide resolved
pub fn free() -> Self {
Self {
base: 0,
dep_per_unit: 0,
dep_per_unit: u64::MAX,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will produce zero-price

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a comment explaining that would be nice. Although, I'm also considering using 0 to make them free anyway in #625

Comment on lines +346 to +349
let max_gas = tx.max_gas(gas_costs, fee_params);
if max_gas > tx_params.max_gas_per_tx {
Err(CheckError::TransactionMaxGasExceeded)?
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The specification says GasLimit > MAX_GAS_PER_TX, while in real life should limit the total transaction cost.

I've created a specification PR to actualize it.

But it is a huge breaking change because SDK right now uses MAX_GAS_PER_TX as a GasLimit -> the transaction always fails because of this check.

Comment on lines +16 to +21
#[test_case(0, 0, 1 => Some(96))]
#[test_case(88, 0, 1 => Some(184))]
#[test_case(0, 1, 2 => Some(168))]
#[test_case(0, 2, 3 => Some(240))]
#[test_case(0, 1, 3 => Some(168))]
#[test_case(44, 2, 3 => Some(284))]
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we removed two fields, we need to subtract 16.

fuel-tx/src/transaction/fee.rs Show resolved Hide resolved

#[cfg(test)]
#[allow(clippy::cast_possible_truncation)]
mod tests {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is tested in the fuel_vm/src/checked_transaction.rs

# Conflicts:
#	.github/workflows/ci.yml
#	fuel-tx/src/transaction/fee.rs
@xgreenx xgreenx marked this pull request as ready for review November 7, 2023 13:09
@xgreenx xgreenx requested a review from a team November 7, 2023 13:09
@@ -129,11 +116,10 @@ pub struct TransactionBuilder<Tx> {
impl TransactionBuilder<Script> {
pub fn script(script: Vec<u8>, script_data: Vec<u8>) -> Self {
let tx = Script {
gas_price: Default::default(),
gas_limit: Default::default(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also rename this to script_gas_limit to more closely match the spec?

@@ -313,8 +297,11 @@ impl<Tx: Buildable> TransactionBuilder<Tx> {
self
}

pub fn gas_limit(&mut self, gas_limit: Word) -> &mut Self {
self.tx.set_gas_limit(gas_limit);
pub fn gas_limit(&mut self, gas_limit: Word) -> &mut Self
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn gas_limit(&mut self, gas_limit: Word) -> &mut Self
pub fn script_gas_limit(&mut self, gas_limit: Word) -> &mut Self

}

#[test]
fn script_set_witness_limit_for_non_empty_witness_fails() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fn script_set_witness_limit_for_non_empty_witness_fails() {
fn script_set_witness_limit_less_than_witness_data_size_fails() {

}

#[test]
fn create_set_witness_limit_for_non_empty_witness_fails() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fn create_set_witness_limit_for_non_empty_witness_fails() {
fn create_set_witness_limit_less_than_witness_data_size_fails() {

@@ -17,6 +39,7 @@ use itertools::Itertools;

mod fee;
mod metadata;
pub mod policies;
Copy link
Member

@Voxelot Voxelot Nov 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] Should pub mods be sorted into a separate section from private mods?

Comment on lines +61 to +64
PolicyType::GasPrice => 0,
PolicyType::WitnessLimit => 1,
PolicyType::Maturity => 2,
PolicyType::MaxFee => 3,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use the inverse operation of how you defined the PolicyType to find the index:

Suggested change
PolicyType::GasPrice => 0,
PolicyType::WitnessLimit => 1,
PolicyType::Maturity => 2,
PolicyType::MaxFee => 3,
PolicyType::GasPrice => PoliciesBits::GasPrice.trailing_zeros(),
PolicyType::WitnessLimit => PoliciesBits::WitnessLimit.trailing_zeros(),
PolicyType::Maturity => PoliciesBits::Maturity.trailing_zeros(),
PolicyType::MaxFee => PoliciesBits::MaxFee.trailing_zeros(),

or:

Suggested change
PolicyType::GasPrice => 0,
PolicyType::WitnessLimit => 1,
PolicyType::Maturity => 2,
PolicyType::MaxFee => 3,
self.bit().trailinig_zeroes()

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea was to write the implementation manually to control values because, in the future, we may remove GasPrice or any other policy.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as they don't get out of sync 👍

/// The total number of policies.
pub const POLICIES_NUMBER: usize = PoliciesBits::all().bits().count_ones() as usize;

/// It is a container for managing policies.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// It is a container for managing policies.
/// Container for managing policies.

/// The transaction doesn't contain enough gas to evaluate all predicates
#[display(fmt = "Insufficient gas available for all predicates")]
CumulativePredicateGasExceededTxGasLimit,
/// The transaction `max_gas` more than global gas limit.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// The transaction `max_gas` more than global gas limit.
/// The transaction's `max_gas` is greater than the global gas limit.

or

Suggested change
/// The transaction `max_gas` more than global gas limit.
/// The transaction policy value for `MaxGas` is greater than the global gas limit.

MitchTurner
MitchTurner previously approved these changes Nov 8, 2023
@bvrooman
Copy link
Contributor

bvrooman commented Nov 9, 2023

I proposed some changes in #630 - mostly for the purpose of allowing us to encapsulate policy definitions and checks better. It would be nice to have this logic centralized rather than spread out, because it means a reduction in overall complexity: Having one place to define this logic would mean better maintainability/less duplication and easier extensibility. But I am simply suggesting one approach - if you have an idea on how you would like to do this, we can review that too now or at a later date after this PR is in.

@xgreenx xgreenx added this pull request to the merge queue Nov 9, 2023
Merged via the queue into master with commit 61c6992 Nov 9, 2023
37 checks passed
@xgreenx xgreenx deleted the feature/transaction-policy branch November 9, 2023 10:09
@xgreenx xgreenx restored the feature/transaction-policy branch November 9, 2023 10:53
@xgreenx xgreenx deleted the feature/transaction-policy branch November 9, 2023 10:55
@xgreenx xgreenx mentioned this pull request Nov 13, 2023
xgreenx added a commit to FuelLabs/fuel-core that referenced this pull request Nov 14, 2023
Imports FuelLabs/fuel-vm#623

---------

Co-authored-by: Brandon Vrooman <[email protected]>
Co-authored-by: Brandon Vrooman <[email protected]>
Co-authored-by: hal3e <[email protected]>
xgreenx added a commit to FuelLabs/fuel-specs that referenced this pull request Nov 30, 2023
crypto523 added a commit to crypto523/fuel-core that referenced this pull request Oct 7, 2024
Imports FuelLabs/fuel-vm#623

---------

Co-authored-by: Brandon Vrooman <[email protected]>
Co-authored-by: Brandon Vrooman <[email protected]>
Co-authored-by: hal3e <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Incorrectly refunded used gas Support Transaction Policies
5 participants