Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3739316
feat(execution): add invalid_transaction_to_effects
miker83z Oct 16, 2025
eb35746
feat(authority): support failing validation effects commit post-conse…
miker83z Oct 16, 2025
67597f3
refactor(authority): clean move authenticator flow
miker83z Oct 16, 2025
f63f1a7
refactor(execution): rename invalid_tx_to_effects to produce_effects_…
miker83z Oct 16, 2025
bd43347
refactor(execution): make validate_transaction use a generic mode and…
miker83z Oct 16, 2025
1e3c586
fix(execution): handle setup auth PTB error
miker83z Oct 17, 2025
bd06856
chore(execution): add comments to newly introduced methods
miker83z Oct 17, 2025
364aa54
minor comment fix
miker83z Oct 17, 2025
f5e11a9
feat(e2e): add test_abstract_account_post_consensus_failure
miker83z Oct 17, 2025
1df61c1
refactor(gas-model): revert gas init with auth
miker83z Oct 20, 2025
15a69df
feat(execution): add authenticate_then_execute_transaction_to_effects
miker83z Oct 20, 2025
85c10ac
feat(checks,execution): combine inputs checks and reuse IotaGasStatus
miker83z Oct 21, 2025
350aed5
refactor(execution): rename validate to authenticate_transaction
miker83z Oct 21, 2025
c508e9b
feat(e2e): add check for gas and mutated objects
miker83z Oct 22, 2025
c5ef593
fix(execution): remove input objects merge
miker83z Oct 22, 2025
b571171
temp execution refactoring
miker83z Oct 23, 2025
643a51b
second temp execution refactoring
miker83z Oct 23, 2025
e915cb4
feat(tx-checks): merge auth and tx input objects safely
miker83z Oct 23, 2025
b3fad83
refactor(execution): remove inputs clone
miker83z Oct 24, 2025
a5589fc
refactor(tx-checks): checked_input_objects_union
miker83z Oct 24, 2025
6c23f7c
comments
miker83z Oct 24, 2025
53fa2b7
fix(e2e): enhance aa post consensus checks
miker83z Oct 24, 2025
dcf9343
fix comments
miker83z Oct 24, 2025
589136f
Merge remote-tracking branch 'origin/vm-lang/aa-auth/8116-feature-bra…
miker83z Oct 27, 2025
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
239 changes: 103 additions & 136 deletions crates/iota-core/src/authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,7 @@ impl AuthorityState {
)?;

if let Some(move_authenticator) = transaction.move_authenticator() {
// It is supposed that `Move authentication` availability is checked in
// It is supposed that `MoveAuthenticator` availability is checked in
// `SenderSignedData::validity_check`.

// Check the `MoveAuthenticator` input objects.
Expand All @@ -934,7 +934,7 @@ impl AuthorityState {
let (kind, signer, _) = tx_data.execution_parts();

// Execute the Move authenticator.
let validation_result = epoch_store.executor().validate_transaction(
let validation_result = epoch_store.executor().authenticate_transaction(
self.get_backing_store().as_ref(),
protocol_config,
self.metrics.limits_metrics.clone(),
Expand Down Expand Up @@ -1349,7 +1349,7 @@ impl AuthorityState {
.start_timer();

let objects = if let Some(move_authenticator) = certificate.move_authenticator() {
// It is supposed that `Move authentication` availability is checked in
// It is supposed that `MoveAuthenticator` availability is checked in
// `SenderSignedData::validity_check`.

// Load the account object.
Expand Down Expand Up @@ -1746,7 +1746,7 @@ impl AuthorityState {
certificate: &VerifiedExecutableTransaction,
tx_input_objects: InputObjects,
account_object: Option<ObjectReadResult>,
authenticator_input_objects: Option<InputObjects>,
move_authenticator_input_objects: Option<InputObjects>,
epoch_store: &Arc<AuthorityPerEpochStore>,
) -> IotaResult<(
InnerTemporaryStore,
Expand Down Expand Up @@ -1778,116 +1778,109 @@ impl AuthorityState {

let (kind, signer, gas) = tx_data.execution_parts();

let authenticator_computation_cost = if let Some(move_authenticator) =
certificate.move_authenticator()
{
// It is supposed that `Move authentication` availability is checked in
// `SenderSignedData::validity_check`.

// Check basic `object_to_authenticate` preconditions and get its components.
let (
auth_account_object_id,
auth_account_object_seq_number,
auth_account_object_digest,
) = move_authenticator.object_to_authenticate_components()?;

// Since the `object_to_authenticate` components are provided, it is supposed
// that the account object is loaded.
let account_object = account_object.expect("Account object must be provided");

let authenticator_info = self.check_move_account(
auth_account_object_id,
auth_account_object_seq_number,
auth_account_object_digest,
account_object,
&signer,
)?;

let authenticator_input_objects = authenticator_input_objects.expect(
"In case of a `MoveAuthenticator` signature, the authenticator input objects must be provided",
);

// Check the `MoveAuthenticator` input objects.
let (authenticator_gas_status, authenticator_input_objects) =
Self::check_move_authenticator_inputs_for_executing(
protocol_config,
reference_gas_price,
tx_data,
authenticator_input_objects,
&tx_input_objects,
#[cfg_attr(not(any(msim, fail_points)), expect(unused_mut))]
let (inner_temp_store, _, mut effects, execution_error_opt) =
// Check if the sender needs to be authenticated in Move and, if so, execute the
// authentication.
if let Some(move_authenticator) = certificate.move_authenticator() {

// Check basic `object_to_authenticate` preconditions and get its components.
let (auth_account_object_id, auth_account_object_seq_number, auth_account_object_digest) =
move_authenticator.object_to_authenticate_components()?;

// Since the `object_to_authenticate` components are provided, it is supposed
// that the account object is loaded.
let account_object = account_object.expect("Account object must be provided");

let authenticator_info = self.check_move_account(
auth_account_object_id,
auth_account_object_seq_number,
auth_account_object_digest,
account_object,
&signer,
)?;

// Execute the Move authenticator.
let validation_result = epoch_store.executor().validate_transaction(
backing_store,
protocol_config,
self.metrics.limits_metrics.clone(),
&epoch_id,
epoch_start_timestamp,
authenticator_gas_status,
move_authenticator.to_owned(),
authenticator_info,
authenticator_input_objects,
kind.clone(),
signer,
tx_digest,
&mut None,
);

match validation_result {
Ok(authenticator_computation_cost) => authenticator_computation_cost,
Err(validation_error) => {
// If an error occurs during execution, the storage, effects, and the execution
// error itself are returned so that the gas can be charged.
// I case of validation we do not support this, so the only available option
// here is to return an error.
return Err(IotaError::MoveAuthenticatorExecutionFailure {
error: validation_error.to_string(),
});
}
}
} else {
0
};

// The cost of partially re-auditing a transaction before execution is
// tolerated.
//
// TODO: Gas coins should not be double-checked if `GenericSignature` is of
// type `MoveAuthenticator`.
let (tx_gas_status, tx_input_objects) = iota_transaction_checks::check_certificate_input(
certificate,
tx_input_objects,
protocol_config,
reference_gas_price,
authenticator_computation_cost,
)?;
let move_authenticator_input_objects = move_authenticator_input_objects.expect(
"In case of a `MoveAuthenticator` signature, the authenticator input objects must be provided",
);

let owned_object_refs = tx_input_objects.inner().filter_owned_objects();
self.check_owned_locks(&owned_object_refs)?;
// Check the `MoveAuthenticator` input objects.
// The `MoveAuthenticator` receiving objects are checked on the signing step.
// `max_auth_gas` is used here as a Move authenticator gas budget until it is
// not a part of the transaction data.
let authenticator_gas_budget = protocol_config.max_auth_gas();
let (gas_status, authenticator_checked_input_objects, authenticator_and_tx_checked_input_objects) =
iota_transaction_checks::check_certificate_and_move_authenticator_input(
certificate,
tx_input_objects.clone(),
move_authenticator_input_objects,
authenticator_gas_budget,
protocol_config,
reference_gas_price,
)?;

let owned_object_refs = authenticator_and_tx_checked_input_objects.inner().filter_owned_objects();
self.check_owned_locks(&owned_object_refs)?;

#[cfg_attr(not(any(msim, fail_points)), expect(unused_mut))]
let (inner_temp_store, _, mut effects, execution_error_opt) =
epoch_store.executor().execute_transaction_to_effects(
backing_store,
protocol_config,
self.metrics.limits_metrics.clone(),
// TODO: would be nice to pass the whole NodeConfig here, but it creates a
// cyclic dependency w/ iota-adapter
self.config
.expensive_safety_check_config
.enable_deep_per_tx_iota_conservation_check(),
self.config.certificate_deny_config.certificate_deny_set(),
&epoch_id,
epoch_start_timestamp,
tx_input_objects,
gas,
tx_gas_status,
kind,
signer,
tx_digest,
&mut None,
);
epoch_store
.executor()
.authenticate_then_execute_transaction_to_effects(
backing_store,
protocol_config,
self.metrics.limits_metrics.clone(),
self.config
.expensive_safety_check_config
.enable_deep_per_tx_iota_conservation_check(),
self.config.certificate_deny_config.certificate_deny_set(),
&epoch_id,
epoch_start_timestamp,
gas_status,
gas,
move_authenticator.to_owned(),
authenticator_info,
authenticator_checked_input_objects,
authenticator_and_tx_checked_input_objects,
kind,
signer,
tx_digest,
&mut None,
)
} else {
// No Move authentication required, proceed to execute the transaction directly.

// The cost of partially re-auditing a transaction before execution is
// tolerated.
let (tx_gas_status, tx_checked_input_objects) =
iota_transaction_checks::check_certificate_input(
certificate,
tx_input_objects,
protocol_config,
reference_gas_price,
)?;

let owned_object_refs = tx_checked_input_objects.inner().filter_owned_objects();
self.check_owned_locks(&owned_object_refs)?;
epoch_store.executor().execute_transaction_to_effects(
backing_store,
protocol_config,
self.metrics.limits_metrics.clone(),
// TODO: would be nice to pass the whole NodeConfig here, but it creates a
// cyclic dependency w/ iota-adapter
self.config
.expensive_safety_check_config
.enable_deep_per_tx_iota_conservation_check(),
self.config.certificate_deny_config.certificate_deny_set(),
&epoch_id,
epoch_start_timestamp,
tx_checked_input_objects,
gas,
tx_gas_status,
kind,
signer,
tx_digest,
&mut None,
)
};

fail_point_if!("cp_execution_nondeterminism", || {
#[cfg(msim)]
Expand Down Expand Up @@ -5607,32 +5600,6 @@ impl AuthorityState {
Ok((gas_status, checked_input_objects, authenticator_info))
}

/// Checks the `MoveAuthenticator` inputs for executing.
fn check_move_authenticator_inputs_for_executing(
protocol_config: &ProtocolConfig,
reference_gas_price: u64,
transaction: &TransactionData,
authenticator_input_objects: InputObjects,
tx_input_objects: &InputObjects,
) -> IotaResult<(IotaGasStatus, CheckedInputObjects)> {
// The `MoveAuthenticator` receiving objects are checked on the signing step.

// `max_auth_gas` is used here as a Move authenticator gas budget until it is
// not a part of the transaction data.
let authenticator_gas_budget = protocol_config.max_auth_gas();

iota_transaction_checks::check_move_authenticator_input(
protocol_config,
reference_gas_price,
transaction.gas(),
authenticator_gas_budget,
transaction.gas_budget(),
transaction.gas_price(),
authenticator_input_objects,
tx_input_objects,
)
}

#[cfg(test)]
pub(crate) fn iter_live_object_set_for_testing(
&self,
Expand Down
Loading