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

[gas] permission #15232

Merged
merged 3 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 155 additions & 54 deletions aptos-move/framework/aptos-framework/doc/transaction_validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@


- [Resource `TransactionValidation`](#0x1_transaction_validation_TransactionValidation)
- [Struct `GasPermission`](#0x1_transaction_validation_GasPermission)
- [Constants](#@Constants_0)
- [Function `grant_gas_permission`](#0x1_transaction_validation_grant_gas_permission)
- [Function `revoke_gas_permission`](#0x1_transaction_validation_revoke_gas_permission)
- [Function `initialize`](#0x1_transaction_validation_initialize)
- [Function `prologue_common`](#0x1_transaction_validation_prologue_common)
- [Function `script_prologue`](#0x1_transaction_validation_script_prologue)
Expand All @@ -28,6 +31,8 @@
- [Specification](#@Specification_1)
- [High-level Requirements](#high-level-req)
- [Module-level Specification](#module-level-spec)
- [Function `grant_gas_permission`](#@Specification_1_grant_gas_permission)
- [Function `revoke_gas_permission`](#@Specification_1_revoke_gas_permission)
- [Function `initialize`](#@Specification_1_initialize)
- [Function `prologue_common`](#@Specification_1_prologue_common)
- [Function `script_prologue`](#@Specification_1_script_prologue)
Expand Down Expand Up @@ -57,6 +62,7 @@
<b>use</b> <a href="../../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error">0x1::error</a>;
<b>use</b> <a href="../../aptos-stdlib/../move-stdlib/doc/features.md#0x1_features">0x1::features</a>;
<b>use</b> <a href="../../aptos-stdlib/../move-stdlib/doc/option.md#0x1_option">0x1::option</a>;
<b>use</b> <a href="permissioned_signer.md#0x1_permissioned_signer">0x1::permissioned_signer</a>;
<b>use</b> <a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">0x1::signer</a>;
<b>use</b> <a href="system_addresses.md#0x1_system_addresses">0x1::system_addresses</a>;
<b>use</b> <a href="timestamp.md#0x1_timestamp">0x1::timestamp</a>;
Expand Down Expand Up @@ -123,6 +129,33 @@ correct chain-specific prologue and epilogue functions
</dl>


</details>

<a id="0x1_transaction_validation_GasPermission"></a>

## Struct `GasPermission`



<pre><code><b>struct</b> <a href="transaction_validation.md#0x1_transaction_validation_GasPermission">GasPermission</a> <b>has</b> <b>copy</b>, drop, store
</code></pre>



<details>
<summary>Fields</summary>


<dl>
<dt>
<code>dummy_field: bool</code>
</dt>
<dd>

</dd>
</dl>


</details>

<a id="@Constants_0"></a>
Expand Down Expand Up @@ -243,6 +276,76 @@ important to the semantics of the system.



<a id="0x1_transaction_validation_PROLOGUE_PERMISSIONED_GAS_LIMIT_INSUFFICIENT"></a>



<pre><code><b>const</b> <a href="transaction_validation.md#0x1_transaction_validation_PROLOGUE_PERMISSIONED_GAS_LIMIT_INSUFFICIENT">PROLOGUE_PERMISSIONED_GAS_LIMIT_INSUFFICIENT</a>: u64 = 1011;
</code></pre>



<a id="0x1_transaction_validation_grant_gas_permission"></a>

## Function `grant_gas_permission`

Permission management

Master signer grant permissioned signer ability to consume a given amount of gas in octas.


<pre><code><b>public</b> <b>fun</b> <a href="transaction_validation.md#0x1_transaction_validation_grant_gas_permission">grant_gas_permission</a>(master: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, permissioned: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, gas_amount: u64)
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="transaction_validation.md#0x1_transaction_validation_grant_gas_permission">grant_gas_permission</a>(
master: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>,
permissioned: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>,
gas_amount: u64
) {
<a href="permissioned_signer.md#0x1_permissioned_signer_authorize_increase">permissioned_signer::authorize_increase</a>(
master,
permissioned,
(gas_amount <b>as</b> u256),
<a href="transaction_validation.md#0x1_transaction_validation_GasPermission">GasPermission</a> {}
)
}
</code></pre>



</details>

<a id="0x1_transaction_validation_revoke_gas_permission"></a>

## Function `revoke_gas_permission`

Removing permissions from permissioned signer.


<pre><code><b>public</b> <b>fun</b> <a href="transaction_validation.md#0x1_transaction_validation_revoke_gas_permission">revoke_gas_permission</a>(permissioned: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>)
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="transaction_validation.md#0x1_transaction_validation_revoke_gas_permission">revoke_gas_permission</a>(permissioned: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>) {
<a href="permissioned_signer.md#0x1_permissioned_signer_revoke_permission">permissioned_signer::revoke_permission</a>(permissioned, <a href="transaction_validation.md#0x1_transaction_validation_GasPermission">GasPermission</a> {})
}
</code></pre>



</details>

<a id="0x1_transaction_validation_initialize"></a>

## Function `initialize`
Expand Down Expand Up @@ -382,6 +485,14 @@ Only called during genesis to initialize system resources for this module.
is_simulation,
gas_payer_address
)) {
<b>assert</b>!(
<a href="permissioned_signer.md#0x1_permissioned_signer_check_permission_capacity_above">permissioned_signer::check_permission_capacity_above</a>(
gas_payer,
(max_transaction_fee <b>as</b> u256),
<a href="transaction_validation.md#0x1_transaction_validation_GasPermission">GasPermission</a> {}
),
<a href="../../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_permission_denied">error::permission_denied</a>(<a href="transaction_validation.md#0x1_transaction_validation_PROLOGUE_PERMISSIONED_GAS_LIMIT_INSUFFICIENT">PROLOGUE_PERMISSIONED_GAS_LIMIT_INSUFFICIENT</a>)
);
<b>if</b> (<a href="../../aptos-stdlib/../move-stdlib/doc/features.md#0x1_features_operations_default_to_fa_apt_store_enabled">features::operations_default_to_fa_apt_store_enabled</a>()) {
<b>assert</b>!(
<a href="aptos_account.md#0x1_aptos_account_is_fungible_balance_at_least">aptos_account::is_fungible_balance_at_least</a>(gas_payer_address, max_transaction_fee),
Expand Down Expand Up @@ -965,7 +1076,7 @@ Called by the Adapter
<a href="transaction_fee.md#0x1_transaction_fee_burn_fee">transaction_fee::burn_fee</a>(gas_payer, burn_amount);
} <b>else</b> <b>if</b> (transaction_fee_amount &lt; storage_fee_refunded) {
<b>let</b> mint_amount = storage_fee_refunded - transaction_fee_amount;
<a href="transaction_fee.md#0x1_transaction_fee_mint_and_refund">transaction_fee::mint_and_refund</a>(gas_payer, mint_amount)
<a href="transaction_fee.md#0x1_transaction_fee_mint_and_refund">transaction_fee::mint_and_refund</a>(gas_payer, mint_amount);
};
};

Expand Down Expand Up @@ -1195,9 +1306,19 @@ If there is no fee_payer, fee_payer = sender
<b>if</b> (transaction_fee_amount &gt; storage_fee_refunded) {
<b>let</b> burn_amount = transaction_fee_amount - storage_fee_refunded;
<a href="transaction_fee.md#0x1_transaction_fee_burn_fee">transaction_fee::burn_fee</a>(gas_payer_address, burn_amount);
<a href="permissioned_signer.md#0x1_permissioned_signer_check_permission_consume">permissioned_signer::check_permission_consume</a>(
&gas_payer,
(burn_amount <b>as</b> u256),
<a href="transaction_validation.md#0x1_transaction_validation_GasPermission">GasPermission</a> {}
);
} <b>else</b> <b>if</b> (transaction_fee_amount &lt; storage_fee_refunded) {
<b>let</b> mint_amount = storage_fee_refunded - transaction_fee_amount;
<a href="transaction_fee.md#0x1_transaction_fee_mint_and_refund">transaction_fee::mint_and_refund</a>(gas_payer_address, mint_amount)
<a href="transaction_fee.md#0x1_transaction_fee_mint_and_refund">transaction_fee::mint_and_refund</a>(gas_payer_address, mint_amount);
<a href="permissioned_signer.md#0x1_permissioned_signer_increase_limit">permissioned_signer::increase_limit</a>(
&gas_payer,
(mint_amount <b>as</b> u256),
<a href="transaction_validation.md#0x1_transaction_validation_GasPermission">GasPermission</a> {}
);
};
};

Expand Down Expand Up @@ -1267,6 +1388,38 @@ If there is no fee_payer, fee_payer = sender



<a id="@Specification_1_grant_gas_permission"></a>

### Function `grant_gas_permission`


<pre><code><b>public</b> <b>fun</b> <a href="transaction_validation.md#0x1_transaction_validation_grant_gas_permission">grant_gas_permission</a>(master: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, permissioned: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, gas_amount: u64)
</code></pre>




<pre><code><b>pragma</b> aborts_if_is_partial;
</code></pre>



<a id="@Specification_1_revoke_gas_permission"></a>

### Function `revoke_gas_permission`


<pre><code><b>public</b> <b>fun</b> <a href="transaction_validation.md#0x1_transaction_validation_revoke_gas_permission">revoke_gas_permission</a>(permissioned: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>)
</code></pre>




<pre><code><b>pragma</b> aborts_if_is_partial;
</code></pre>



<a id="@Specification_1_initialize"></a>

### Function `initialize`
Expand All @@ -1287,58 +1440,6 @@ Aborts if TransactionValidation already exists.
</code></pre>


Create a schema to reuse some code.
Give some constraints that may abort according to the conditions.


<a id="0x1_transaction_validation_PrologueCommonAbortsIf"></a>


<pre><code><b>schema</b> <a href="transaction_validation.md#0x1_transaction_validation_PrologueCommonAbortsIf">PrologueCommonAbortsIf</a> {
sender: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>;
gas_payer: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>;
txn_sequence_number: u64;
txn_authentication_key: Option&lt;<a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>&lt;u8&gt;&gt;;
txn_gas_price: u64;
txn_max_gas_units: u64;
txn_expiration_time: u64;
<a href="chain_id.md#0x1_chain_id">chain_id</a>: u8;
<b>aborts_if</b> !<b>exists</b>&lt;CurrentTimeMicroseconds&gt;(@aptos_framework);
<b>aborts_if</b> !(<a href="timestamp.md#0x1_timestamp_now_seconds">timestamp::now_seconds</a>() &lt; txn_expiration_time);
<b>aborts_if</b> !<b>exists</b>&lt;ChainId&gt;(@aptos_framework);
<b>aborts_if</b> !(<a href="chain_id.md#0x1_chain_id_get">chain_id::get</a>() == <a href="chain_id.md#0x1_chain_id">chain_id</a>);
<b>let</b> transaction_sender = <a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer_address_of">signer::address_of</a>(sender);
<b>let</b> gas_payer_addr = <a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer_address_of">signer::address_of</a>(gas_payer);
<b>aborts_if</b> (
!<a href="../../aptos-stdlib/../move-stdlib/doc/features.md#0x1_features_spec_is_enabled">features::spec_is_enabled</a>(<a href="../../aptos-stdlib/../move-stdlib/doc/features.md#0x1_features_SPONSORED_AUTOMATIC_ACCOUNT_CREATION">features::SPONSORED_AUTOMATIC_ACCOUNT_CREATION</a>)
|| <a href="account.md#0x1_account_exists_at">account::exists_at</a>(transaction_sender)
|| transaction_sender == gas_payer_addr
|| txn_sequence_number &gt; 0
) && (
!(txn_sequence_number &gt;= <b>global</b>&lt;Account&gt;(transaction_sender).sequence_number)
|| !(<a href="../../aptos-stdlib/../move-stdlib/doc/option.md#0x1_option_spec_is_none">option::spec_is_none</a>(txn_authentication_key) || <a href="../../aptos-stdlib/../move-stdlib/doc/option.md#0x1_option_spec_borrow">option::spec_borrow</a>(
txn_authentication_key
) == <b>global</b>&lt;Account&gt;(transaction_sender).authentication_key)
|| !<a href="account.md#0x1_account_exists_at">account::exists_at</a>(transaction_sender)
|| !(txn_sequence_number == <b>global</b>&lt;Account&gt;(transaction_sender).sequence_number)
);
<b>aborts_if</b> <a href="../../aptos-stdlib/../move-stdlib/doc/features.md#0x1_features_spec_is_enabled">features::spec_is_enabled</a>(<a href="../../aptos-stdlib/../move-stdlib/doc/features.md#0x1_features_SPONSORED_AUTOMATIC_ACCOUNT_CREATION">features::SPONSORED_AUTOMATIC_ACCOUNT_CREATION</a>)
&& transaction_sender != gas_payer_addr
&& txn_sequence_number == 0
&& !<a href="account.md#0x1_account_exists_at">account::exists_at</a>(transaction_sender)
&& (<a href="../../aptos-stdlib/../move-stdlib/doc/option.md#0x1_option_spec_is_none">option::spec_is_none</a>(txn_authentication_key) || <a href="../../aptos-stdlib/../move-stdlib/doc/option.md#0x1_option_spec_borrow">option::spec_borrow</a>(
txn_authentication_key
) != <a href="../../aptos-stdlib/../move-stdlib/doc/bcs.md#0x1_bcs_to_bytes">bcs::to_bytes</a>(transaction_sender));
<b>aborts_if</b> !(txn_sequence_number &lt; (1u64 &lt;&lt; 63));
<b>let</b> max_transaction_fee = txn_gas_price * txn_max_gas_units;
<b>aborts_if</b> max_transaction_fee &gt; <a href="transaction_validation.md#0x1_transaction_validation_MAX_U64">MAX_U64</a>;
<b>aborts_if</b> !<b>exists</b>&lt;CoinStore&lt;AptosCoin&gt;&gt;(gas_payer_addr);
// This enforces <a id="high-level-req-1" href="#high-level-req">high-level requirement 1</a>:
<b>aborts_if</b> !(<b>global</b>&lt;CoinStore&lt;AptosCoin&gt;&gt;(gas_payer_addr).<a href="coin.md#0x1_coin">coin</a>.value &gt;= max_transaction_fee);
}
</code></pre>



<a id="@Specification_1_prologue_common"></a>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module aptos_framework::transaction_validation {
use aptos_framework::chain_id;
use aptos_framework::coin;
use aptos_framework::create_signer;
use aptos_framework::permissioned_signer;
use aptos_framework::system_addresses;
use aptos_framework::timestamp;
use aptos_framework::transaction_fee;
Expand All @@ -32,6 +33,8 @@ module aptos_framework::transaction_validation {
user_epilogue_name: vector<u8>,
}

struct GasPermission has copy, drop, store {}

/// MSB is used to indicate a gas payer tx
const MAX_U64: u128 = 18446744073709551615;

Expand All @@ -51,6 +54,28 @@ module aptos_framework::transaction_validation {
const PROLOGUE_ESEQUENCE_NUMBER_TOO_BIG: u64 = 1008;
const PROLOGUE_ESECONDARY_KEYS_ADDRESSES_COUNT_MISMATCH: u64 = 1009;
const PROLOGUE_EFEE_PAYER_NOT_ENABLED: u64 = 1010;
const PROLOGUE_PERMISSIONED_GAS_LIMIT_INSUFFICIENT: u64 = 1011;

/// Permission management
///
/// Master signer grant permissioned signer ability to consume a given amount of gas in octas.
public fun grant_gas_permission(
master: &signer,
permissioned: &signer,
gas_amount: u64
) {
permissioned_signer::authorize_increase(
master,
permissioned,
(gas_amount as u256),
GasPermission {}
)
}

/// Removing permissions from permissioned signer.
public fun revoke_gas_permission(permissioned: &signer) {
permissioned_signer::revoke_permission(permissioned, GasPermission {})
}

/// Only called during genesis to initialize system resources for this module.
public(friend) fun initialize(
Expand Down Expand Up @@ -156,6 +181,14 @@ module aptos_framework::transaction_validation {
is_simulation,
gas_payer_address
)) {
assert!(
permissioned_signer::check_permission_capacity_above(
gas_payer,
(max_transaction_fee as u256),
GasPermission {}
),
error::permission_denied(PROLOGUE_PERMISSIONED_GAS_LIMIT_INSUFFICIENT)
);
if (features::operations_default_to_fa_apt_store_enabled()) {
assert!(
aptos_account::is_fungible_balance_at_least(gas_payer_address, max_transaction_fee),
Expand Down Expand Up @@ -534,7 +567,7 @@ module aptos_framework::transaction_validation {
transaction_fee::burn_fee(gas_payer, burn_amount);
} else if (transaction_fee_amount < storage_fee_refunded) {
let mint_amount = storage_fee_refunded - transaction_fee_amount;
transaction_fee::mint_and_refund(gas_payer, mint_amount)
transaction_fee::mint_and_refund(gas_payer, mint_amount);
};
};

Expand Down Expand Up @@ -667,9 +700,19 @@ module aptos_framework::transaction_validation {
if (transaction_fee_amount > storage_fee_refunded) {
let burn_amount = transaction_fee_amount - storage_fee_refunded;
transaction_fee::burn_fee(gas_payer_address, burn_amount);
permissioned_signer::check_permission_consume(
&gas_payer,
(burn_amount as u256),
GasPermission {}
);
} else if (transaction_fee_amount < storage_fee_refunded) {
let mint_amount = storage_fee_refunded - transaction_fee_amount;
transaction_fee::mint_and_refund(gas_payer_address, mint_amount)
transaction_fee::mint_and_refund(gas_payer_address, mint_amount);
permissioned_signer::increase_limit(
&gas_payer,
(mint_amount as u256),
GasPermission {}
);
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ spec aptos_framework::transaction_validation {
pragma aborts_if_is_strict;
}

spec grant_gas_permission(
master: &signer,
permissioned: &signer,
gas_amount: u64
) {
pragma aborts_if_is_partial;
}

spec revoke_gas_permission(permissioned: &signer) {
pragma aborts_if_is_partial;
}

/// Ensure caller is `aptos_framework`.
/// Aborts if TransactionValidation already exists.
spec initialize(
Expand Down
Loading
Loading