Skip to content

Commit

Permalink
[gas] permission (#15232)
Browse files Browse the repository at this point in the history
add Gas permission
  • Loading branch information
lightmark authored Jan 17, 2025
1 parent 17540fa commit bb609ba
Show file tree
Hide file tree
Showing 5 changed files with 359 additions and 56 deletions.
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

0 comments on commit bb609ba

Please sign in to comment.