Skip to content

Commit 113efeb

Browse files
tac0turtleclaude
andauthored
strict v2 account identity: registry-only address resolution (#17)
* Add Docker Compose stack for evd and update branch changes * Use ev-node-grpc image as default in compose * Remove EV_NODE_IMAGE override from compose setup * fix: resolve clap grpc_addr name collision in testapp CLI The duplicate grpc_addr field in TestappRunCustom clashed with the same field in NativeRunConfigArgs, causing a runtime panic. Use the existing --grpc-addr from NativeRunConfigArgs wired through NodeConfig. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * strict v2 account identity: registry-only address resolution * include remaining chain-index and node changes * Address review feedback and stabilize node/rpc flows * Clarify recipient-required policy and cover auto-mapping * Track AccountId numeric-compat cleanup * Fix unresolved PR issues in evd and custom genesis --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 398dffd commit 113efeb

36 files changed

Lines changed: 2091 additions & 879 deletions

File tree

bin/evd/src/main.rs

Lines changed: 526 additions & 250 deletions
Large diffs are not rendered by default.

bin/testapp/src/eth_eoa.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ pub mod eth_eoa_account {
2222
use evolve_collections::item::Item;
2323
use evolve_core::{AccountId, Environment, Message, SdkResult};
2424
use evolve_macros::{exec, init, query};
25-
use evolve_tx_eth::address_to_account_id;
2625
use evolve_tx_eth::TxContext;
2726

2827
/// An Ethereum-compatible externally owned account.
@@ -93,18 +92,20 @@ pub mod eth_eoa_account {
9392
/// - Just increments nonce (test mode, no signature verification)
9493
#[exec]
9594
fn authenticate(&self, tx: Message, env: &mut dyn Environment) -> SdkResult<()> {
95+
let expected_address = self.eth_address.may_get(env)?.unwrap_or([0u8; 20]);
96+
97+
if let Ok(sender_address) = tx.get::<[u8; 20]>() {
98+
if sender_address != expected_address {
99+
return Err(evolve_core::ErrorCode::new(0x51)); // Sender mismatch
100+
}
96101
// Fast path: validator passes sender AccountId directly.
97-
if let Ok(sender_id) = tx.get::<AccountId>() {
98-
let expected_address = self.eth_address.may_get(env)?.unwrap_or([0u8; 20]);
99-
let expected_id =
100-
address_to_account_id(alloy_primitives::Address::from(expected_address));
101-
if sender_id != expected_id {
102+
} else if let Ok(sender_id) = tx.get::<AccountId>() {
103+
if sender_id != env.whoami() {
102104
return Err(evolve_core::ErrorCode::new(0x51)); // Sender mismatch
103105
}
104106
// Backward-compatible fallback for older validator payloads.
105107
} else if let Ok(mempool_tx) = tx.get::<TxContext>() {
106108
let sender_bytes: [u8; 20] = mempool_tx.sender_address().into();
107-
let expected_address = self.eth_address.may_get(env)?.unwrap_or([0u8; 20]);
108109
if sender_bytes != expected_address {
109110
return Err(evolve_core::ErrorCode::new(0x51)); // Sender mismatch
110111
}

bin/testapp/src/genesis_config.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use alloy_primitives::Address;
22
use borsh::{BorshDeserialize, BorshSerialize};
33
use evolve_core::AccountId;
44
use evolve_fungible_asset::FungibleAssetMetadata;
5+
use evolve_node::HasTokenAccountId;
56
use serde::Deserialize;
67
use std::collections::BTreeSet;
78

@@ -37,6 +38,12 @@ pub struct EvdGenesisResult {
3738
pub scheduler: AccountId,
3839
}
3940

41+
impl HasTokenAccountId for EvdGenesisResult {
42+
fn token_account_id(&self) -> AccountId {
43+
self.token
44+
}
45+
}
46+
4047
impl EvdGenesisConfig {
4148
/// Load genesis config from a JSON file.
4249
pub fn load(path: &str) -> Result<Self, String> {

bin/testapp/src/lib.rs

Lines changed: 12 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@ use crate::eth_eoa::eth_eoa_account::{EthEoaAccount, EthEoaAccountRef};
66
use evolve_authentication::AuthenticationTxValidator;
77
use evolve_core::{AccountId, BlockContext, Environment, InvokeResponse, ReadonlyKV, SdkResult};
88
use evolve_fungible_asset::FungibleAssetMetadata;
9+
use evolve_node::HasTokenAccountId;
910
use evolve_scheduler::scheduler_account::{Scheduler, SchedulerRef};
1011
use evolve_scheduler::server::{SchedulerBeginBlocker, SchedulerEndBlocker};
1112
use evolve_server::Block;
1213
use evolve_stf::execution_state::ExecutionState;
1314
use evolve_stf::{Stf, StorageGasConfig};
1415
use evolve_stf_traits::{AccountsCodeStorage, PostTxExecution, WritableAccountsCodeStorage};
1516
use evolve_token::account::{Token, TokenRef};
16-
use evolve_tx_eth::address_to_account_id;
1717
use evolve_tx_eth::TxContext;
18+
use evolve_tx_eth::{register_runtime_contract_account, resolve_or_create_eoa_account};
1819

1920
pub const MINTER: AccountId = AccountId::new(100_002);
2021

@@ -78,55 +79,11 @@ pub struct GenesisAccounts {
7879
pub scheduler: AccountId,
7980
}
8081

81-
/// Shared custom-genesis resources used by evd and testapp binaries.
82-
#[derive(Clone, Copy, Debug)]
83-
pub struct CustomGenesisResources {
84-
pub alice: Option<AccountId>,
85-
pub bob: Option<AccountId>,
86-
pub token: AccountId,
87-
pub scheduler: AccountId,
88-
}
89-
90-
/// Initialize funded EOAs, token, and scheduler for custom genesis.
91-
pub fn initialize_custom_genesis_resources(
92-
funded_accounts: &[([u8; 20], u128)],
93-
metadata: FungibleAssetMetadata,
94-
minter: AccountId,
95-
env: &mut dyn Environment,
96-
) -> SdkResult<CustomGenesisResources> {
97-
for (eth_addr, _) in funded_accounts {
98-
EthEoaAccountRef::initialize(*eth_addr, env)?;
82+
impl HasTokenAccountId for GenesisAccounts {
83+
fn token_account_id(&self) -> AccountId {
84+
self.atom
9985
}
100-
101-
let balances: Vec<(AccountId, u128)> = funded_accounts
102-
.iter()
103-
.map(|(eth_addr, balance)| {
104-
let addr = alloy_primitives::Address::from(*eth_addr);
105-
(address_to_account_id(addr), *balance)
106-
})
107-
.collect();
108-
109-
let token = TokenRef::initialize(metadata, balances, Some(minter), env)?.0;
110-
111-
let scheduler_acc = SchedulerRef::initialize(vec![], vec![], env)?.0;
112-
scheduler_acc.update_begin_blockers(vec![], env)?;
113-
114-
let alice = funded_accounts
115-
.first()
116-
.map(|(eth_addr, _)| address_to_account_id(alloy_primitives::Address::from(*eth_addr)));
117-
let bob = funded_accounts
118-
.get(1)
119-
.map(|(eth_addr, _)| address_to_account_id(alloy_primitives::Address::from(*eth_addr)))
120-
.or(alice);
121-
122-
Ok(CustomGenesisResources {
123-
alice,
124-
bob,
125-
token: token.0,
126-
scheduler: scheduler_acc.0,
127-
})
12886
}
129-
13087
fn parse_genesis_address_env(var: &str) -> Option<[u8; 20]> {
13188
use alloy_primitives::Address;
13289
use std::str::FromStr;
@@ -166,9 +123,11 @@ pub fn do_genesis_with_addresses(
166123
env,
167124
)?
168125
.0;
126+
let _atom_eth_addr = register_runtime_contract_account(atom.0, env)?;
169127

170128
// Create scheduler (no begin blockers needed for block info anymore)
171129
let scheduler_acc = SchedulerRef::initialize(vec![], vec![], env)?.0;
130+
let _scheduler_eth_addr = register_runtime_contract_account(scheduler_acc.0, env)?;
172131

173132
// Update scheduler's account's list.
174133
scheduler_acc.update_begin_blockers(vec![], env)?;
@@ -226,10 +185,9 @@ pub fn do_eth_genesis_inner(
226185
use alloy_primitives::Address;
227186
use std::str::FromStr;
228187

229-
// Convert Ethereum addresses to AccountIds
230-
// (accounts should already be registered in storage)
231-
let alice_id = address_to_account_id(Address::from(alice_eth_address));
232-
let bob_id = address_to_account_id(Address::from(bob_eth_address));
188+
// Resolve/create canonical EOA accounts from full 20-byte ETH addresses.
189+
let alice_id = resolve_or_create_eoa_account(Address::from(alice_eth_address), env)?;
190+
let bob_id = resolve_or_create_eoa_account(Address::from(bob_eth_address), env)?;
233191
let alice_balance = std::env::var("GENESIS_ALICE_TOKEN_BALANCE")
234192
.ok()
235193
.and_then(|v| u128::from_str(v.trim()).ok())
@@ -253,9 +211,11 @@ pub fn do_eth_genesis_inner(
253211
env,
254212
)?
255213
.0;
214+
let _evolve_eth_addr = register_runtime_contract_account(evolve.0, env)?;
256215

257216
// Create scheduler
258217
let scheduler_acc = SchedulerRef::initialize(vec![], vec![], env)?.0;
218+
let _scheduler_eth_addr = register_runtime_contract_account(scheduler_acc.0, env)?;
259219
scheduler_acc.update_begin_blockers(vec![], env)?;
260220

261221
Ok(EthGenesisAccounts {

0 commit comments

Comments
 (0)