Skip to content

Commit e3f0e92

Browse files
authored
Add methods to set/remove delegations to StackState (#367)
* feat: ✨ add set_delegation and remove_delegation methods to StackState * feat: ✨ add DelegationDesignator struct * refactor: ♻️ make delegation designator more rusty * refactor: 🚨 clippy * refactor: 🔥 remove unused trait impls * test: ✅ add missing assertions * refactor: 🎨 rename authorizer to authority * refactor: 🎨 rename remove_delegation to reset_delegation
1 parent ab119a8 commit e3f0e92

File tree

6 files changed

+293
-172
lines changed

6 files changed

+293
-172
lines changed

core/src/delegation.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
extern crate alloc;
2+
3+
use alloc::vec::Vec;
4+
use core::convert::TryFrom;
5+
use primitive_types::H160;
6+
7+
/// EIP-7702 delegation designator prefix
8+
pub const EIP_7702_DELEGATION_PREFIX: &[u8] = &[0xef, 0x01, 0x00];
9+
10+
/// EIP-7702 delegation designator full length (prefix + address)
11+
pub const EIP_7702_DELEGATION_SIZE: usize = 23;
12+
13+
/// EIP-7702 delegation designator struct for managing delegation addresses
14+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15+
pub struct Delegation {
16+
address: H160,
17+
}
18+
19+
impl Delegation {
20+
/// Create a new delegation designator from an address
21+
pub fn new(address: H160) -> Self {
22+
Self { address }
23+
}
24+
25+
/// Convert the delegation designator to its bytecode representation
26+
pub fn to_bytes(&self) -> Vec<u8> {
27+
let mut designator = Vec::with_capacity(EIP_7702_DELEGATION_SIZE);
28+
designator.extend_from_slice(EIP_7702_DELEGATION_PREFIX);
29+
designator.extend_from_slice(self.address.as_bytes());
30+
designator
31+
}
32+
33+
/// Get the delegated address
34+
pub fn address(&self) -> &H160 {
35+
&self.address
36+
}
37+
38+
/// Consume the designator and return the address
39+
pub fn into_address(self) -> H160 {
40+
self.address
41+
}
42+
}
43+
44+
/// Check if code is an EIP-7702 delegation designator
45+
pub fn is_delegation_designator(code: &[u8]) -> bool {
46+
code.len() == EIP_7702_DELEGATION_SIZE && code.starts_with(EIP_7702_DELEGATION_PREFIX)
47+
}
48+
49+
impl From<H160> for Delegation {
50+
fn from(address: H160) -> Self {
51+
Self::new(address)
52+
}
53+
}
54+
55+
impl TryFrom<&[u8]> for Delegation {
56+
type Error = DelegationError;
57+
58+
fn try_from(code: &[u8]) -> Result<Self, Self::Error> {
59+
if !is_delegation_designator(code) {
60+
return Err(DelegationError::InvalidFormat);
61+
}
62+
63+
let mut address_bytes = [0u8; 20];
64+
address_bytes.copy_from_slice(&code[3..23]);
65+
Ok(Self {
66+
address: H160::from(address_bytes),
67+
})
68+
}
69+
}
70+
71+
/// Error type for delegation operations
72+
#[derive(Debug, Clone, PartialEq, Eq)]
73+
pub enum DelegationError {
74+
/// The provided bytes do not represent a valid delegation designator
75+
InvalidFormat,
76+
}
77+
78+
#[cfg(test)]
79+
mod tests {
80+
use super::*;
81+
82+
#[test]
83+
fn test_delegation_designator_creation() {
84+
let address = H160::from_slice(&[1u8; 20]);
85+
let designator = Delegation::new(address);
86+
let bytes = designator.to_bytes();
87+
88+
assert_eq!(bytes.len(), EIP_7702_DELEGATION_SIZE);
89+
assert_eq!(&bytes[0..3], EIP_7702_DELEGATION_PREFIX);
90+
assert_eq!(&bytes[3..23], address.as_bytes());
91+
assert_eq!(*designator.address(), address);
92+
}
93+
94+
#[test]
95+
fn test_delegation_designator_detection() {
96+
let address = H160::from_slice(&[1u8; 20]);
97+
let designator = Delegation::new(address);
98+
let bytes = designator.to_bytes();
99+
100+
assert!(is_delegation_designator(&bytes));
101+
let extracted = Delegation::try_from(&bytes);
102+
assert_eq!(extracted, Some(designator));
103+
assert_eq!(*extracted.unwrap().address(), address);
104+
}
105+
106+
#[test]
107+
fn test_non_delegation_code() {
108+
let regular_code = vec![0x60, 0x00]; // PUSH1 0
109+
assert!(!is_delegation_designator(&regular_code));
110+
assert_eq!(Delegation::try_from(&regular_code), None);
111+
}
112+
}

core/src/lib.rs

Lines changed: 2 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
extern crate alloc;
88

9+
pub mod delegation;
910
mod error;
1011
mod eval;
1112
mod external;
@@ -26,13 +27,7 @@ use crate::eval::{eval, Control};
2627
use alloc::rc::Rc;
2728
use alloc::vec::Vec;
2829
use core::ops::Range;
29-
use primitive_types::{H160, U256};
30-
31-
/// EIP-7702 delegation designator prefix
32-
pub const EIP_7702_DELEGATION_PREFIX: &[u8] = &[0xef, 0x01, 0x00];
33-
34-
/// EIP-7702 delegation designator full length (prefix + address)
35-
pub const EIP_7702_DELEGATION_SIZE: usize = 23; // 3 bytes prefix + 20 bytes address
30+
use primitive_types::U256;
3631

3732
/// Core execution layer for EVM.
3833
pub struct Machine {
@@ -184,58 +179,3 @@ impl Machine {
184179
}
185180
}
186181
}
187-
188-
/// Check if code is an EIP-7702 delegation designator
189-
pub fn is_delegation_designator(code: &[u8]) -> bool {
190-
code.len() == EIP_7702_DELEGATION_SIZE && code.starts_with(EIP_7702_DELEGATION_PREFIX)
191-
}
192-
193-
/// Extract the delegated address from EIP-7702 delegation designator
194-
pub fn extract_delegation_address(code: &[u8]) -> Option<H160> {
195-
if is_delegation_designator(code) {
196-
let mut address_bytes = [0u8; 20];
197-
address_bytes.copy_from_slice(&code[3..23]);
198-
Some(H160::from(address_bytes))
199-
} else {
200-
None
201-
}
202-
}
203-
204-
/// Create EIP-7702 delegation designator
205-
pub fn create_delegation_designator(address: H160) -> Vec<u8> {
206-
let mut designator = Vec::with_capacity(EIP_7702_DELEGATION_SIZE);
207-
designator.extend_from_slice(EIP_7702_DELEGATION_PREFIX);
208-
designator.extend_from_slice(address.as_bytes());
209-
designator
210-
}
211-
212-
#[cfg(test)]
213-
mod tests {
214-
use super::*;
215-
216-
#[test]
217-
fn test_delegation_designator_creation() {
218-
let address = H160::from_slice(&[1u8; 20]);
219-
let designator = create_delegation_designator(address);
220-
221-
assert_eq!(designator.len(), EIP_7702_DELEGATION_SIZE);
222-
assert_eq!(&designator[0..3], EIP_7702_DELEGATION_PREFIX);
223-
assert_eq!(&designator[3..23], address.as_bytes());
224-
}
225-
226-
#[test]
227-
fn test_delegation_designator_detection() {
228-
let address = H160::from_slice(&[1u8; 20]);
229-
let designator = create_delegation_designator(address);
230-
231-
assert!(is_delegation_designator(&designator));
232-
assert_eq!(extract_delegation_address(&designator), Some(address));
233-
}
234-
235-
#[test]
236-
fn test_non_delegation_code() {
237-
let regular_code = vec![0x60, 0x00]; // PUSH1 0
238-
assert!(!is_delegation_designator(&regular_code));
239-
assert_eq!(extract_delegation_address(&regular_code), None);
240-
}
241-
}

runtime/src/handler.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
use core::convert::TryFrom;
2+
13
use crate::{Capture, Context, CreateScheme, ExitError, ExitReason, Machine, Opcode, Stack};
24
use alloc::vec::Vec;
5+
use evm_core::delegation::Delegation;
36
use primitive_types::{H160, H256, U256};
47

58
/// Transfer from source to target, with given value.
@@ -36,8 +39,9 @@ pub trait Handler {
3639
/// Get code of address, following EIP-7702 delegations if enabled.
3740
fn delegated_code(&self, address: H160) -> Option<Vec<u8>> {
3841
let code = self.code(address);
39-
evm_core::extract_delegation_address(&code)
40-
.map(|delegated_address| self.code(delegated_address))
42+
Delegation::try_from(&code[..])
43+
.map(|delegation| self.code(delegation.into_address()))
44+
.ok()
4145
}
4246
/// Get storage value of address at index.
4347
fn storage(&self, address: H160, index: H256) -> H256;

src/executor/stack/executor.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ use crate::{
1010
Transfer,
1111
};
1212
use alloc::{collections::BTreeSet, rc::Rc, vec::Vec};
13-
use core::{cmp::min, convert::Infallible};
13+
use core::cmp::min;
14+
use core::convert::{Infallible, TryFrom};
15+
use evm_core::delegation::Delegation;
1416
use evm_core::ExitFatal;
1517
use evm_runtime::Resolve;
1618
use primitive_types::{H160, H256, U256};
@@ -218,6 +220,8 @@ pub trait StackState<'config>: Backend {
218220
code: Vec<u8>,
219221
caller: Option<H160>,
220222
) -> Result<(), ExitError>;
223+
fn set_delegation(&mut self, authority: H160, delegation: Delegation) -> Result<(), ExitError>;
224+
fn reset_delegation(&mut self, authority: H160) -> Result<(), ExitError>;
221225
fn transfer(&mut self, transfer: Transfer) -> Result<(), ExitError>;
222226
fn reset_balance(&mut self, address: H160);
223227
fn touch(&mut self, address: H160);
@@ -823,7 +827,9 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet>
823827

824828
// Skip if account has existing non-delegation code
825829
let existing_code = self.state.code(authorizing_address);
826-
if !existing_code.is_empty() && !evm_core::is_delegation_designator(&existing_code) {
830+
if !existing_code.is_empty()
831+
&& !evm_core::delegation::is_delegation_designator(&existing_code)
832+
{
827833
// Skip if account has non-delegation code
828834
continue;
829835
}
@@ -855,12 +861,12 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet>
855861
}
856862

857863
// Set account code: clear if delegating to zero address, otherwise set delegation designator
858-
let code = if delegation_address == H160::zero() {
859-
Vec::new()
864+
if delegation_address == H160::zero() {
865+
self.state.reset_delegation(authorizing_address)?;
860866
} else {
861-
evm_core::create_delegation_designator(delegation_address)
867+
self.state
868+
.set_delegation(authorizing_address, Delegation::new(delegation_address))?;
862869
};
863-
self.state.set_code(authorizing_address, code, None)?;
864870

865871
// Increment the nonce of the authorizing account
866872
self.state.inc_nonce(authorizing_address)?;
@@ -1081,15 +1087,15 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet>
10811087
let code = if self.config.has_eip_7702 {
10821088
// Check for delegation and record external operation if needed
10831089
let original_code = self.code(code_address);
1084-
if let Some(delegated_address) = evm_core::extract_delegation_address(&original_code) {
1090+
if let Ok(delegation) = Delegation::try_from(&original_code[..]) {
10851091
if let Err(e) = self.record_external_operation(
1086-
crate::ExternalOperation::DelegationResolution(delegated_address),
1092+
crate::ExternalOperation::DelegationResolution(*delegation.address()),
10871093
) {
10881094
let _ = self.exit_substate(StackExitKind::Failed);
10891095
return Capture::Exit((ExitReason::Error(e), Vec::new()));
10901096
}
10911097

1092-
self.code(delegated_address)
1098+
self.code(*delegation.address())
10931099
} else {
10941100
original_code
10951101
}

src/executor/stack/memory.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use alloc::{
77
vec::Vec,
88
};
99
use core::mem;
10+
use evm_core::delegation::Delegation;
1011
use primitive_types::{H160, H256, U256};
1112

1213
#[derive(Clone, Debug)]
@@ -383,6 +384,19 @@ impl<'config> MemoryStackSubstate<'config> {
383384
self.account_mut(address, backend).code = Some(code);
384385
}
385386

387+
pub fn set_delegation<B: Backend>(
388+
&mut self,
389+
authority: H160,
390+
delegation: Delegation,
391+
backend: &B,
392+
) {
393+
self.account_mut(authority, backend).code = Some(delegation.to_bytes());
394+
}
395+
396+
pub fn reset_delegation<B: Backend>(&mut self, authority: H160, backend: &B) {
397+
self.account_mut(authority, backend).code = Some(Vec::new());
398+
}
399+
386400
pub fn transfer<B: Backend>(
387401
&mut self,
388402
transfer: Transfer,
@@ -604,6 +618,21 @@ impl<'config, B: Backend> StackState<'config> for MemoryStackState<'_, 'config,
604618
Ok(())
605619
}
606620

621+
fn set_delegation(
622+
&mut self,
623+
authorizing: H160,
624+
delegation: Delegation,
625+
) -> Result<(), ExitError> {
626+
self.substate
627+
.set_delegation(authorizing, delegation, self.backend);
628+
Ok(())
629+
}
630+
631+
fn reset_delegation(&mut self, authority: H160) -> Result<(), ExitError> {
632+
self.substate.reset_delegation(authority, self.backend);
633+
Ok(())
634+
}
635+
607636
fn transfer(&mut self, transfer: Transfer) -> Result<(), ExitError> {
608637
self.substate.transfer(transfer, self.backend)
609638
}

0 commit comments

Comments
 (0)