diff --git a/aptos-move/framework/aptos-framework/doc/multisig_account.md b/aptos-move/framework/aptos-framework/doc/multisig_account.md index e77924001c3e9..b82be8c9a55b1 100644 --- a/aptos-move/framework/aptos-framework/doc/multisig_account.md +++ b/aptos-move/framework/aptos-framework/doc/multisig_account.md @@ -88,10 +88,10 @@ and implement the governance voting logic on top. - [Function `reject_transaction`](#0x1_multisig_account_reject_transaction) - [Function `vote_transanction`](#0x1_multisig_account_vote_transanction) - [Function `execute_rejected_transaction`](#0x1_multisig_account_execute_rejected_transaction) -- [Function `flush_next_sequence_number_and_owner_schema`](#0x1_multisig_account_flush_next_sequence_number_and_owner_schema) +- [Function `flush_last_resolved_sequence_number_and_owner_schema`](#0x1_multisig_account_flush_last_resolved_sequence_number_and_owner_schema) - [Function `validate_multisig_transaction`](#0x1_multisig_account_validate_multisig_transaction) - [Function `validate_multisig_transaction_with_optional_sequence_number`](#0x1_multisig_account_validate_multisig_transaction_with_optional_sequence_number) -- [Function `flush_next_sequence_number_and_owner_schema_execution`](#0x1_multisig_account_flush_next_sequence_number_and_owner_schema_execution) +- [Function `flush_last_resolved_sequence_number_and_owner_schema_execution`](#0x1_multisig_account_flush_last_resolved_sequence_number_and_owner_schema_execution) - [Function `successful_transaction_execution_cleanup`](#0x1_multisig_account_successful_transaction_execution_cleanup) - [Function `failed_transaction_execution_cleanup`](#0x1_multisig_account_failed_transaction_execution_cleanup) - [Function `remove_executed_transaction`](#0x1_multisig_account_remove_executed_transaction) @@ -781,6 +781,16 @@ Owner list cannot contain the same address more than once. + + +Flush transaction proposal has expired. + + +
const EFLUSH_TXN_EXPIRED: u64 = 19;
+
+
+
+
Payload hash must be exactly 32 bytes (sha3-256).
@@ -2082,9 +2092,9 @@ Remove the next transaction if it has sufficient owner rejections.
-
+
-## Function `flush_next_sequence_number_and_owner_schema`
+## Function `flush_last_resolved_sequence_number_and_owner_schema`
Prototype function signature used for flush proposal payload generation.
@@ -2111,17 +2121,20 @@ corresponds to a valid flush transaction: if the proposal stores the entire payl
on-chain then the payload is deserialized and verified, but if the proposal stores only
a payload hash, then the payload included in the Aptos API MultisigFlush transaction is
instead verified.
-5. The VM calls flush_next_sequence_number_and_owner_schema_execution
, applying owner and
-required signature count updates, effectively bumping the proposal to the head of the
-pending transaction queue such that all other pending transactions are disregarded.
+5. The VM calls flush_last_resolved_sequence_number_and_owner_schema_execution
, applying
+owner and required signature count updates, effectively bumping the proposal to the head
+of the pending transaction queue such that all other pending transactions are
+disregarded.
6. The VM calls successful_transaction_execution_cleanup
.
An optional new number of signatures must be passed as a singleton vector due to entry
function constraints: pass either an empty vector for no update, or a singleton vector with
one element specifying the new number of signatures required.
+An expiry time in UNIX seconds is required to safeguard against untimely execution.
+
-entry fun flush_next_sequence_number_and_owner_schema(_new_owners: vector<address>, _owners_to_remove: vector<address>, _optional_new_num_signatures_required_as_vector: vector<u64>)
+entry fun flush_last_resolved_sequence_number_and_owner_schema(_new_owners: vector<address>, _owners_to_remove: vector<address>, _optional_new_num_signatures_required_as_vector: vector<u64>, _expiry_in_unix_seconds: u64)
@@ -2130,10 +2143,11 @@ one element specifying the new number of signatures required.
Implementation
-entry fun flush_next_sequence_number_and_owner_schema(
+entry fun flush_last_resolved_sequence_number_and_owner_schema(
_new_owners: vector<address>,
_owners_to_remove: vector<address>,
_optional_new_num_signatures_required_as_vector: vector<u64>,
+ _expiry_in_unix_seconds: u64
) {}
@@ -2246,18 +2260,18 @@ Check next sequence number to execute if none specified.
-
+
-## Function `flush_next_sequence_number_and_owner_schema_execution`
+## Function `flush_last_resolved_sequence_number_and_owner_schema_execution`
Flush pending transactions and owner schema in reponse to a DoS attack.
-Bumps a flush transaction proposal to the front of the pending transaction queue, then
-updates the next transaction proposal sequence number such all other pending transactions
-are ignored, to be overwritten by future transaction proposals.
+Bumps a flush transaction proposal to the front of the pending transaction queue, by
+updating the last resolved sequence number such that all pending transactions
+are ignored.
-fun flush_next_sequence_number_and_owner_schema_execution(multisig_address: address, new_owners: vector<address>, owners_to_remove: vector<address>, optional_new_num_signatures_required: option::Option<u64>, flush_transaction_proposal_sequence_number: u64)
+fun flush_last_resolved_sequence_number_and_owner_schema_execution(multisig_address: address, new_owners: vector<address>, owners_to_remove: vector<address>, optional_new_num_signatures_required: option::Option<u64>, expiry_in_unix_seconds: u64, flush_transaction_proposal_sequence_number: u64)
@@ -2266,20 +2280,26 @@ are ignored, to be overwritten by future transaction proposals.
Implementation
-fun flush_next_sequence_number_and_owner_schema_execution(
+fun flush_last_resolved_sequence_number_and_owner_schema_execution(
multisig_address: address,
new_owners: vector<address>,
owners_to_remove: vector<address>,
optional_new_num_signatures_required: Option<u64>,
- flush_transaction_proposal_sequence_number: u64,
+ expiry_in_unix_seconds: u64,
+ flush_transaction_proposal_sequence_number: u64
) acquires MultisigAccount {
+ // Verify that the proposal has not yet expired.
+ assert!(
+ expiry_in_unix_seconds < now_seconds(),
+ error::invalid_state(EFLUSH_TXN_EXPIRED)
+ );
let multisig_account_ref_mut =
borrow_global_mut<MultisigAccount>(multisig_address);
let transactions_table_ref_mut =
&mut multisig_account_ref_mut.transactions;
// Get new sequence number for flush transaction proposal.
let new_flush_transaction_proposal_sequence_number =
- multisig_account_ref_mut.last_executed_sequence_number + 1;
+ multisig_account_ref_mut.next_sequence_number;
// Update flush transaction proposal sequence number.
let flush_transaction_proposal = table::remove(
transactions_table_ref_mut,
@@ -2293,6 +2313,9 @@ are ignored, to be overwritten by future transaction proposals.
// Update sequence number for next transaction proposal.
multisig_account_ref_mut.next_sequence_number =
new_flush_transaction_proposal_sequence_number + 1;
+ // Update sequence number for last resolved transaction proposal.
+ multisig_account_ref_mut.last_executed_sequence_number =
+ new_flush_transaction_proposal_sequence_number - 1;
flush_owner_schema(
multisig_address,
new_owners,
diff --git a/aptos-move/framework/aptos-framework/sources/multisig_account.move b/aptos-move/framework/aptos-framework/sources/multisig_account.move
index 0dd3a23a0432f..04bc02cb90c07 100644
--- a/aptos-move/framework/aptos-framework/sources/multisig_account.move
+++ b/aptos-move/framework/aptos-framework/sources/multisig_account.move
@@ -93,6 +93,8 @@ module aptos_framework::multisig_account {
const EINVALID_SEQUENCE_NUMBER: u64 = 17;
/// Provided owners to remove and new owners overlap.
const EOWNERS_TO_REMOVE_NEW_OWNERS_OVERLAP: u64 = 18;
+ /// Flush transaction proposal has expired.
+ const EFLUSH_TXN_EXPIRED: u64 = 19;
/// Represents a multisig account's configurations and transactions.
/// This will be stored in the multisig account (created as a resource account separate from any owner accounts).
@@ -802,18 +804,22 @@ module aptos_framework::multisig_account {
/// on-chain then the payload is deserialized and verified, but if the proposal stores only
/// a payload hash, then the payload included in the Aptos API MultisigFlush transaction is
/// instead verified.
- /// 5. The VM calls `flush_next_sequence_number_and_owner_schema_execution`, applying owner and
- /// required signature count updates, effectively bumping the proposal to the head of the
- /// pending transaction queue such that all other pending transactions are disregarded.
+ /// 5. The VM calls `flush_last_resolved_sequence_number_and_owner_schema_execution`, applying
+ /// owner and required signature count updates, effectively bumping the proposal to the head
+ /// of the pending transaction queue such that all other pending transactions are
+ /// disregarded.
/// 6. The VM calls `successful_transaction_execution_cleanup`.
///
/// An optional new number of signatures must be passed as a singleton vector due to entry
/// function constraints: pass either an empty vector for no update, or a singleton vector with
/// one element specifying the new number of signatures required.
- entry fun flush_next_sequence_number_and_owner_schema(
+ ///
+ /// An expiry time in UNIX seconds is required to safeguard against untimely execution.
+ entry fun flush_last_resolved_sequence_number_and_owner_schema(
_new_owners: vector,
_owners_to_remove: vector,
_optional_new_num_signatures_required_as_vector: vector,
+ _expiry_in_unix_seconds: u64
) {}
////////////////////////// To be called by VM only ///////////////////////////////
@@ -885,23 +891,29 @@ module aptos_framework::multisig_account {
/// Flush pending transactions and owner schema in reponse to a DoS attack.
///
- /// Bumps a flush transaction proposal to the front of the pending transaction queue, then
- /// updates the next transaction proposal sequence number such all other pending transactions
- /// are ignored, to be overwritten by future transaction proposals.
- fun flush_next_sequence_number_and_owner_schema_execution(
+ /// Bumps a flush transaction proposal to the front of the pending transaction queue, by
+ /// updating the last resolved sequence number such that all pending transactions
+ /// are ignored.
+ fun flush_last_resolved_sequence_number_and_owner_schema_execution(
multisig_address: address,
new_owners: vector,
owners_to_remove: vector,
optional_new_num_signatures_required: Option,
- flush_transaction_proposal_sequence_number: u64,
+ expiry_in_unix_seconds: u64,
+ flush_transaction_proposal_sequence_number: u64
) acquires MultisigAccount {
+ // Verify that the proposal has not yet expired.
+ assert!(
+ expiry_in_unix_seconds < now_seconds(),
+ error::invalid_state(EFLUSH_TXN_EXPIRED)
+ );
let multisig_account_ref_mut =
borrow_global_mut(multisig_address);
let transactions_table_ref_mut =
&mut multisig_account_ref_mut.transactions;
// Get new sequence number for flush transaction proposal.
let new_flush_transaction_proposal_sequence_number =
- multisig_account_ref_mut.last_executed_sequence_number + 1;
+ multisig_account_ref_mut.next_sequence_number;
// Update flush transaction proposal sequence number.
let flush_transaction_proposal = table::remove(
transactions_table_ref_mut,
@@ -915,6 +927,9 @@ module aptos_framework::multisig_account {
// Update sequence number for next transaction proposal.
multisig_account_ref_mut.next_sequence_number =
new_flush_transaction_proposal_sequence_number + 1;
+ // Update sequence number for last resolved transaction proposal.
+ multisig_account_ref_mut.last_executed_sequence_number =
+ new_flush_transaction_proposal_sequence_number - 1;
flush_owner_schema(
multisig_address,
new_owners,
diff --git a/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs b/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs
index b19d03487e4fc..d820886a76033 100644
--- a/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs
+++ b/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs
@@ -429,18 +429,22 @@ pub enum EntryFunctionCall {
/// on-chain then the payload is deserialized and verified, but if the proposal stores only
/// a payload hash, then the payload included in the Aptos API MultisigFlush transaction is
/// instead verified.
- /// 5. The VM calls `flush_next_sequence_number_and_owner_schema_execution`, applying owner and
- /// required signature count updates, effectively bumping the proposal to the head of the
- /// pending transaction queue such that all other pending transactions are disregarded.
+ /// 5. The VM calls `flush_last_resolved_sequence_number_and_owner_schema_execution`, applying
+ /// owner and required signature count updates, effectively bumping the proposal to the head
+ /// of the pending transaction queue such that all other pending transactions are
+ /// disregarded.
/// 6. The VM calls `successful_transaction_execution_cleanup`.
///
/// An optional new number of signatures must be passed as a singleton vector due to entry
/// function constraints: pass either an empty vector for no update, or a singleton vector with
/// one element specifying the new number of signatures required.
- MultisigAccountFlushNextSequenceNumberAndOwnerSchema {
+ ///
+ /// An expiry time in UNIX seconds is required to safeguard against untimely execution.
+ MultisigAccountFlushLastResolvedSequenceNumberAndOwnerSchema {
_new_owners: Vec,
_owners_to_remove: Vec,
_optional_new_num_signatures_required_as_vector: Vec,
+ _expiry_in_unix_seconds: u64,
},
/// Reject a multisig transaction.
@@ -1060,14 +1064,16 @@ impl EntryFunctionCall {
MultisigAccountExecuteRejectedTransaction { multisig_account } => {
multisig_account_execute_rejected_transaction(multisig_account)
},
- MultisigAccountFlushNextSequenceNumberAndOwnerSchema {
+ MultisigAccountFlushLastResolvedSequenceNumberAndOwnerSchema {
_new_owners,
_owners_to_remove,
_optional_new_num_signatures_required_as_vector,
- } => multisig_account_flush_next_sequence_number_and_owner_schema(
+ _expiry_in_unix_seconds,
+ } => multisig_account_flush_last_resolved_sequence_number_and_owner_schema(
_new_owners,
_owners_to_remove,
_optional_new_num_signatures_required_as_vector,
+ _expiry_in_unix_seconds,
),
MultisigAccountRejectTransaction {
multisig_account,
@@ -2367,18 +2373,22 @@ pub fn multisig_account_execute_rejected_transaction(
/// on-chain then the payload is deserialized and verified, but if the proposal stores only
/// a payload hash, then the payload included in the Aptos API MultisigFlush transaction is
/// instead verified.
-/// 5. The VM calls `flush_next_sequence_number_and_owner_schema_execution`, applying owner and
-/// required signature count updates, effectively bumping the proposal to the head of the
-/// pending transaction queue such that all other pending transactions are disregarded.
+/// 5. The VM calls `flush_last_resolved_sequence_number_and_owner_schema_execution`, applying
+/// owner and required signature count updates, effectively bumping the proposal to the head
+/// of the pending transaction queue such that all other pending transactions are
+/// disregarded.
/// 6. The VM calls `successful_transaction_execution_cleanup`.
///
/// An optional new number of signatures must be passed as a singleton vector due to entry
/// function constraints: pass either an empty vector for no update, or a singleton vector with
/// one element specifying the new number of signatures required.
-pub fn multisig_account_flush_next_sequence_number_and_owner_schema(
+///
+/// An expiry time in UNIX seconds is required to safeguard against untimely execution.
+pub fn multisig_account_flush_last_resolved_sequence_number_and_owner_schema(
_new_owners: Vec,
_owners_to_remove: Vec,
_optional_new_num_signatures_required_as_vector: Vec,
+ _expiry_in_unix_seconds: u64,
) -> TransactionPayload {
TransactionPayload::EntryFunction(EntryFunction::new(
ModuleId::new(
@@ -2388,12 +2398,13 @@ pub fn multisig_account_flush_next_sequence_number_and_owner_schema(
]),
ident_str!("multisig_account").to_owned(),
),
- ident_str!("flush_next_sequence_number_and_owner_schema").to_owned(),
+ ident_str!("flush_last_resolved_sequence_number_and_owner_schema").to_owned(),
vec![],
vec![
bcs::to_bytes(&_new_owners).unwrap(),
bcs::to_bytes(&_owners_to_remove).unwrap(),
bcs::to_bytes(&_optional_new_num_signatures_required_as_vector).unwrap(),
+ bcs::to_bytes(&_expiry_in_unix_seconds).unwrap(),
],
))
}
@@ -4219,18 +4230,19 @@ mod decoder {
}
}
- pub fn multisig_account_flush_next_sequence_number_and_owner_schema(
+ pub fn multisig_account_flush_last_resolved_sequence_number_and_owner_schema(
payload: &TransactionPayload,
) -> Option {
if let TransactionPayload::EntryFunction(script) = payload {
Some(
- EntryFunctionCall::MultisigAccountFlushNextSequenceNumberAndOwnerSchema {
+ EntryFunctionCall::MultisigAccountFlushLastResolvedSequenceNumberAndOwnerSchema {
_new_owners: bcs::from_bytes(script.args().get(0)?).ok()?,
_owners_to_remove: bcs::from_bytes(script.args().get(1)?).ok()?,
_optional_new_num_signatures_required_as_vector: bcs::from_bytes(
script.args().get(2)?,
)
.ok()?,
+ _expiry_in_unix_seconds: bcs::from_bytes(script.args().get(3)?).ok()?,
},
)
} else {
@@ -5163,8 +5175,10 @@ static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy