Skip to content
Draft
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/contracts/src/precompiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,5 @@ pub const SYSTEM_PRECOMPILES: &[(Address, TempoHardfork)] = &[
(STORAGE_CREDITS_ADDRESS, TempoHardfork::T7),
(CURRENT_COMMITTEE_ADDRESS, TempoHardfork::T8),
(ZONE_FACTORY_ADDRESS, TempoHardfork::T10),
(NATIVE_MULTISIG_ADDRESS, TempoHardfork::T12),
];
117 changes: 110 additions & 7 deletions crates/evm/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ use std::collections::{HashMap, HashSet};
use tempo_chainspec::{TempoChainSpec, hardfork::TempoHardforks};
use tempo_contracts::precompiles::{
ADDRESS_REGISTRY_ADDRESS, CURRENT_COMMITTEE_ADDRESS, ICurrentCommittee, INITIAL_FACTORY_OWNER,
InitialZoneFactoryAccount, RECEIVE_POLICY_GUARD_ADDRESS, SIGNATURE_VERIFIER_ADDRESS,
STORAGE_CREDITS_ADDRESS, TIP20_CHANNEL_RESERVE_ADDRESS, VALIDATOR_CONFIG_V2_ADDRESS,
initial_zone_factory_state, t12_zone_factory_state,
InitialZoneFactoryAccount, NATIVE_MULTISIG_ADDRESS, RECEIVE_POLICY_GUARD_ADDRESS,
SIGNATURE_VERIFIER_ADDRESS, STORAGE_CREDITS_ADDRESS, TIP20_CHANNEL_RESERVE_ADDRESS,
VALIDATOR_CONFIG_V2_ADDRESS, initial_zone_factory_state, t12_zone_factory_state,
};
use tempo_primitives::{
SubBlock, SubBlockMetadata, TempoReceipt, TempoTxEnvelope, TempoTxType,
subblock::PartialValidatorKey,
subblock::PartialValidatorKey, transaction::MULTISIG_RECOVERY_FACTORY,
};
use tempo_revm::{TempoHaltReason, evm::TempoContext};
use tracing::trace;
Expand Down Expand Up @@ -249,6 +249,30 @@ where
Ok(())
}

/// Reserves the recovery-factory address without installing its EVM runtime.
/// Keeps recovery cross-chain-only by preventing the canonical factory from being deployed on Tempo.
/// Replaces code, raises the nonce to one, and preserves balance, storage, and higher nonces.
fn reserve_multisig_recovery_factory_at_boundary(&mut self) -> Result<(), BlockExecutionError> {
let db = self.inner.evm.db_mut();
let info = db
.basic(MULTISIG_RECOVERY_FACTORY)
.map_err(BlockExecutionError::other)?
.unwrap_or_default();
let marker = Bytecode::new_legacy([0xef].into());
let marker_hash = marker.hash_slow();
if info.code_hash == marker_hash && info.nonce >= 1 {
return Ok(());
}

let mut account = Account::from(info);
account.info.code_hash = marker_hash;
account.info.code = Some(marker);
account.info.nonce = account.info.nonce.max(1);
account.mark_touch();
db.commit(EvmState::from_iter([(MULTISIG_RECOVERY_FACTORY, account)]));
Ok(())
}

/// Installs and initializes the complete TIP-1091 state when T10 first becomes active.
fn deploy_zone_factory_at_boundary(&mut self) -> Result<(), BlockExecutionError> {
let [factory, portal, verifier, messenger] =
Expand Down Expand Up @@ -647,6 +671,10 @@ where
if self.inner.spec.is_t8_active_at_timestamp(timestamp) {
self.deploy_precompile_at_boundary(CURRENT_COMMITTEE_ADDRESS, &[])?;
}
if self.inner.spec.is_t12_active_at_timestamp(timestamp) {
self.reserve_multisig_recovery_factory_at_boundary()?;
self.deploy_precompile_at_boundary(NATIVE_MULTISIG_ADDRESS, &[])?;
}
if self.inner.spec.is_t10_active_at_timestamp(timestamp) {
self.deploy_zone_factory_at_boundary()?;
}
Expand Down Expand Up @@ -867,6 +895,7 @@ mod tests {
use reth_chainspec::EthChainSpec;
use reth_revm::{State, state::AccountInfo};
use revm::{
Database,
context::result::{ExecutionResult, ResultGas},
database::EmptyDB,
};
Expand Down Expand Up @@ -1989,22 +2018,96 @@ mod tests {
}

#[test]
fn test_apply_pre_execution_deploys_guard_code() {
// Dev chainspec has t6Time: 0, so T6 is active at any timestamp.
let chainspec = Arc::new(TempoChainSpec::from_genesis(DEV.genesis().clone()));
fn test_apply_pre_execution_pre_t12_does_not_deploy_native_multisig_code() {
let chainspec = test_chainspec();
let mut db = State::builder().with_bundle_update().build();
let mut executor = TestExecutorBuilder::default()
.with_parent_beacon_block_root(B256::ZERO)
.build(&mut db, &chainspec);
executor.evm_mut().ctx_mut().block.inner.timestamp = U256::from(u64::MAX);

executor.apply_pre_execution_changes().unwrap();
drop(executor);

let acc = db.load_cache_account(NATIVE_MULTISIG_ADDRESS).unwrap();
let info = acc.account_info();
assert!(
info.is_none() || info.unwrap().is_empty_code_hash(),
"NativeMultisig code should not be deployed before T12"
);
let factory = db.load_cache_account(MULTISIG_RECOVERY_FACTORY).unwrap();
let info = factory.account_info();
assert!(
info.is_none() || info.unwrap().is_empty_code_hash(),
"recovery factory should not be reserved before T12"
);

let acc = db.load_cache_account(RECEIVE_POLICY_GUARD_ADDRESS).unwrap();
let info = acc.account_info().unwrap();
assert!(!info.is_empty_code_hash());
}

#[test]
fn test_apply_pre_execution_deploys_t12_native_multisig_code_and_reserves_factory() {
let chainspec = Arc::new(TempoChainSpec::from_genesis(DEV.genesis().clone()));
let mut db = State::builder().with_bundle_update().build();
let mut executor = TestExecutorBuilder::default()
.with_parent_beacon_block_root(B256::ZERO)
.build(&mut db, &chainspec);

executor.apply_pre_execution_changes().unwrap();
drop(executor);

let acc = db.load_cache_account(NATIVE_MULTISIG_ADDRESS).unwrap();
let info = acc.account_info().unwrap();
assert!(!info.is_empty_code_hash());

let factory = db.load_cache_account(MULTISIG_RECOVERY_FACTORY).unwrap();
let info = factory.account_info().unwrap();
assert_eq!(info.nonce, 1);
assert_eq!(
info.code.as_ref().unwrap().original_byte_slice(),
[0xef],
"Tempo reserves the address with only the marker, not the recovery runtime"
);
}

#[test]
fn test_t12_recovery_factory_reservation_preserves_account_state() {
let chainspec = Arc::new(TempoChainSpec::from_genesis(DEV.genesis().clone()));
let mut db = State::builder().with_bundle_update().build();
let storage_slot = U256::from(7);
let storage_value = U256::from(11);
let old_code = Bytecode::new_legacy([0x60, 0x00].into());
db.insert_account_with_storage(
MULTISIG_RECOVERY_FACTORY,
AccountInfo {
balance: U256::from(42),
nonce: 7,
code_hash: old_code.hash_slow(),
code: Some(old_code),
..Default::default()
},
[(storage_slot, storage_value)].into_iter().collect(),
);

let mut executor = TestExecutorBuilder::default()
.with_parent_beacon_block_root(B256::ZERO)
.build(&mut db, &chainspec);
executor.apply_pre_execution_changes().unwrap();
drop(executor);

let factory = db.load_cache_account(MULTISIG_RECOVERY_FACTORY).unwrap();
let info = factory.account_info().unwrap();
assert_eq!(info.balance, U256::from(42));
assert_eq!(info.nonce, 7);
assert_eq!(info.code.as_ref().unwrap().original_byte_slice(), [0xef]);
assert_eq!(
db.storage(MULTISIG_RECOVERY_FACTORY, storage_slot).unwrap(),
storage_value
);
}

#[test]
fn test_pre_t3_does_not_deploy_signature_verifier_code() {
// Moderato does not have T4 active (no t3Time set), so the code should NOT be deployed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,74 +21,74 @@ baseline: 274318
"webauthn::batch_5_transfers": 574475
"webauthn::batch_10_transfers": 603776
"webauthn::contract_creation": 785926
"key_auth_p256_0_limits::noop": 538498
"key_auth_secp256k1_0_limits::noop": 538498
"key_auth_webauthn_0_limits::noop": 538498
"key_auth_secp256k1_witness::noop": 542127
"key_auth_p256_0_limits::transfer": 808740
"key_auth_secp256k1_0_limits::transfer": 808740
"key_auth_webauthn_0_limits::transfer": 808740
"key_auth_secp256k1_witness::transfer": 812369
"key_auth_p256_0_limits::batch_2_transfers": 814600
"key_auth_secp256k1_0_limits::batch_2_transfers": 814600
"key_auth_webauthn_0_limits::batch_2_transfers": 814600
"key_auth_secp256k1_witness::batch_2_transfers": 818229
"key_auth_p256_0_limits::batch_5_transfers": 832181
"key_auth_secp256k1_0_limits::batch_5_transfers": 832181
"key_auth_webauthn_0_limits::batch_5_transfers": 832181
"key_auth_secp256k1_witness::batch_5_transfers": 835809
"key_auth_p256_0_limits::batch_10_transfers": 861481
"key_auth_secp256k1_0_limits::batch_10_transfers": 861481
"key_auth_webauthn_0_limits::batch_10_transfers": 861481
"key_auth_secp256k1_witness::batch_10_transfers": 865110
"key_auth_p256_1_limit::noop": 1042466
"key_auth_secp256k1_1_limit::noop": 1042466
"key_auth_webauthn_1_limit::noop": 1042466
"key_auth_secp256k1_witness_1_limit::noop": 1046095
"key_auth_p256_1_limit::transfer": 1312708
"key_auth_secp256k1_1_limit::transfer": 1312708
"key_auth_webauthn_1_limit::transfer": 1312708
"key_auth_secp256k1_witness_1_limit::transfer": 1316337
"key_auth_p256_1_limit::batch_2_transfers": 1318568
"key_auth_secp256k1_1_limit::batch_2_transfers": 1318568
"key_auth_webauthn_1_limit::batch_2_transfers": 1318568
"key_auth_secp256k1_witness_1_limit::batch_2_transfers": 1322197
"key_auth_p256_1_limit::batch_5_transfers": 1336149
"key_auth_secp256k1_1_limit::batch_5_transfers": 1336149
"key_auth_webauthn_1_limit::batch_5_transfers": 1336149
"key_auth_secp256k1_witness_1_limit::batch_5_transfers": 1339777
"key_auth_p256_1_limit::batch_10_transfers": 1365450
"key_auth_secp256k1_1_limit::batch_10_transfers": 1365450
"key_auth_webauthn_1_limit::batch_10_transfers": 1365450
"key_auth_secp256k1_witness_1_limit::batch_10_transfers": 1369078
"key_auth_secp256k1_target_any_selector::transfer": 1823732
"key_auth_p256_3_limits::noop": 2050403
"key_auth_secp256k1_3_limits::noop": 2050403
"key_auth_webauthn_3_limits::noop": 2050403
"key_auth_p256_3_limits::transfer": 2320645
"key_auth_secp256k1_3_limits::transfer": 2320645
"key_auth_webauthn_3_limits::transfer": 2320645
"key_auth_p256_3_limits::batch_2_transfers": 2326505
"key_auth_secp256k1_3_limits::batch_2_transfers": 2326505
"key_auth_webauthn_3_limits::batch_2_transfers": 2326505
"key_auth_p256_3_limits::batch_5_transfers": 2344085
"key_auth_secp256k1_3_limits::batch_5_transfers": 2344085
"key_auth_webauthn_3_limits::batch_5_transfers": 2344085
"key_auth_p256_3_limits::batch_10_transfers": 2373386
"key_auth_secp256k1_3_limits::batch_10_transfers": 2373386
"key_auth_webauthn_3_limits::batch_10_transfers": 2373386
"key_auth_secp256k1_selector_any_recipient::transfer": 2586740
"key_auth_secp256k1_selector_recipient::transfer": 3347732
"keychain_secp256k1::noop": 541623
"keychain_secp256k1::transfer": 812066
"keychain_secp256k1::batch_2_transfers": 818229
"keychain_secp256k1::batch_5_transfers": 836716
"keychain_secp256k1::batch_10_transfers": 867529
"keychain_p256::noop": 546662
"keychain_p256::transfer": 817106
"keychain_p256::batch_2_transfers": 823268
"keychain_p256::batch_5_transfers": 841756
"keychain_p256::batch_10_transfers": 872569
"keychain_secp256k1_selector_any_recipient::transfer": 2592485
"keychain_secp256k1_selector_recipient::transfer": 3351562
"keychain_secp256k1_target_any_selector::transfer": 1827260
"key_auth_p256_0_limits::noop": 540716
"key_auth_secp256k1_0_limits::noop": 540716
"key_auth_webauthn_0_limits::noop": 540716
"key_auth_secp256k1_witness::noop": 544344
"key_auth_p256_0_limits::transfer": 810958
"key_auth_secp256k1_0_limits::transfer": 810958
"key_auth_webauthn_0_limits::transfer": 810958
"key_auth_secp256k1_witness::transfer": 814586
"key_auth_p256_0_limits::batch_2_transfers": 816818
"key_auth_secp256k1_0_limits::batch_2_transfers": 816818
"key_auth_webauthn_0_limits::batch_2_transfers": 816818
"key_auth_secp256k1_witness::batch_2_transfers": 820446
"key_auth_p256_0_limits::batch_5_transfers": 834398
"key_auth_secp256k1_0_limits::batch_5_transfers": 834398
"key_auth_webauthn_0_limits::batch_5_transfers": 834398
"key_auth_secp256k1_witness::batch_5_transfers": 838027
"key_auth_p256_0_limits::batch_10_transfers": 863699
"key_auth_secp256k1_0_limits::batch_10_transfers": 863699
"key_auth_webauthn_0_limits::batch_10_transfers": 863699
"key_auth_secp256k1_witness::batch_10_transfers": 867327
"key_auth_p256_1_limit::noop": 1044684
"key_auth_secp256k1_1_limit::noop": 1044684
"key_auth_webauthn_1_limit::noop": 1044684
"key_auth_secp256k1_witness_1_limit::noop": 1048312
"key_auth_p256_1_limit::transfer": 1314926
"key_auth_secp256k1_1_limit::transfer": 1314926
"key_auth_webauthn_1_limit::transfer": 1314926
"key_auth_secp256k1_witness_1_limit::transfer": 1318554
"key_auth_p256_1_limit::batch_2_transfers": 1320786
"key_auth_secp256k1_1_limit::batch_2_transfers": 1320786
"key_auth_webauthn_1_limit::batch_2_transfers": 1320786
"key_auth_secp256k1_witness_1_limit::batch_2_transfers": 1324415
"key_auth_p256_1_limit::batch_5_transfers": 1338366
"key_auth_secp256k1_1_limit::batch_5_transfers": 1338366
"key_auth_webauthn_1_limit::batch_5_transfers": 1338366
"key_auth_secp256k1_witness_1_limit::batch_5_transfers": 1341995
"key_auth_p256_1_limit::batch_10_transfers": 1367667
"key_auth_secp256k1_1_limit::batch_10_transfers": 1367667
"key_auth_webauthn_1_limit::batch_10_transfers": 1367667
"key_auth_secp256k1_witness_1_limit::batch_10_transfers": 1371296
"key_auth_secp256k1_target_any_selector::transfer": 1825950
"key_auth_p256_3_limits::noop": 2052620
"key_auth_secp256k1_3_limits::noop": 2052620
"key_auth_webauthn_3_limits::noop": 2052620
"key_auth_p256_3_limits::transfer": 2322862
"key_auth_secp256k1_3_limits::transfer": 2322862
"key_auth_webauthn_3_limits::transfer": 2322862
"key_auth_p256_3_limits::batch_2_transfers": 2328722
"key_auth_secp256k1_3_limits::batch_2_transfers": 2328722
"key_auth_webauthn_3_limits::batch_2_transfers": 2328722
"key_auth_p256_3_limits::batch_5_transfers": 2346303
"key_auth_secp256k1_3_limits::batch_5_transfers": 2346303
"key_auth_webauthn_3_limits::batch_5_transfers": 2346303
"key_auth_p256_3_limits::batch_10_transfers": 2375604
"key_auth_secp256k1_3_limits::batch_10_transfers": 2375604
"key_auth_webauthn_3_limits::batch_10_transfers": 2375604
"key_auth_secp256k1_selector_any_recipient::transfer": 2588958
"key_auth_secp256k1_selector_recipient::transfer": 3349950
"keychain_secp256k1::noop": 543840
"keychain_secp256k1::transfer": 814284
"keychain_secp256k1::batch_2_transfers": 820446
"keychain_secp256k1::batch_5_transfers": 838934
"keychain_secp256k1::batch_10_transfers": 869746
"keychain_p256::noop": 548880
"keychain_p256::transfer": 819323
"keychain_p256::batch_2_transfers": 825486
"keychain_p256::batch_5_transfers": 843974
"keychain_p256::batch_10_transfers": 874786
"keychain_secp256k1_selector_any_recipient::transfer": 2594703
"keychain_secp256k1_selector_recipient::transfer": 3353780
"keychain_secp256k1_target_any_selector::transfer": 1829477
1 change: 1 addition & 0 deletions crates/payload/builder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ crossbeam-channel.workspace = true
tokio.workspace = true

[dev-dependencies]
alloy-sol-types.workspace = true
proptest.workspace = true

[features]
Expand Down
Loading
Loading