1010
1111logger = logging .getLogger (__name__ )
1212
13+ class StateJournal :
14+ """
15+ An in-memory proxy dictionary that caches reads and writes to avoid
16+ expensive deep copies of the entire state dictionary during transactions.
17+ """
18+ def __init__ (self , backing_dict ):
19+ self .backing = backing_dict
20+ self .cache = {}
21+
22+ def __getitem__ (self , key ):
23+ if key not in self .cache :
24+ if key in self .backing :
25+ import copy
26+ self .cache [key ] = copy .deepcopy (self .backing [key ])
27+ else :
28+ raise KeyError (key )
29+ return self .cache [key ]
30+
31+ def __setitem__ (self , key , value ):
32+ self .cache [key ] = value
33+
34+ def __delitem__ (self , key ):
35+ raise NotImplementedError ("Account deletion not supported in StateJournal" )
36+
37+ def __contains__ (self , key ):
38+ return key in self .cache or key in self .backing
39+
40+ def get (self , key , default = None ):
41+ try :
42+ return self .__getitem__ (key )
43+ except KeyError :
44+ return default
45+
46+ def items (self ):
47+ res = self .backing .copy ()
48+ res .update (self .cache )
49+ return res .items ()
50+
51+ def update (self , other_dict ):
52+ if hasattr (other_dict , 'items' ):
53+ for k , v in other_dict .items ():
54+ self [k ] = v
55+ else :
56+ for k , v in other_dict :
57+ self [k ] = v
58+
59+ def copy (self ):
60+ res = self .backing .copy ()
61+ res .update (self .cache )
62+ return res
63+
64+ def commit (self ):
65+ """Flushes cached modifications to the backing dictionary."""
66+ self .backing .update (self .cache )
67+ self .cache .clear ()
68+
69+ def rollback (self ):
70+ """Discards modifications."""
71+ self .cache .clear ()
72+
1373
1474class State :
1575 def __init__ (self ):
@@ -69,9 +129,11 @@ def verify_transaction_logic(self, tx):
69129 def copy (self ):
70130 """
71131 Return an independent copy of state for transactional validation.
132+ Uses StateJournal for O(1) cloning instead of deepcopy.
72133 """
73- new_state = copy .deepcopy (self )
74- new_state .contract_machine = ContractMachine (new_state ) # Reinitialize contract_machine
134+ new_state = State ()
135+ new_state .accounts = StateJournal (self .accounts )
136+ new_state .contract_machine = ContractMachine (new_state )
75137 new_state .chain_id = self .chain_id
76138 return new_state
77139
@@ -124,22 +186,22 @@ def apply_transaction(self, tx):
124186
125187
126188 def _apply_validated_tx (self , tx ):
189+ original_accounts = self .accounts
190+ journal = StateJournal (original_accounts )
191+ self .accounts = journal
192+
127193 sender = self .accounts [tx .sender ]
128194 total_cost = tx .amount + (getattr (tx , 'gas_limit' , 0 ) * getattr (tx , 'fee_per_gas' , 0 ))
129195
130196 sender ['balance' ] -= total_cost
131197 sender ['nonce' ] += 1
132198
133- import copy
134- state_snapshot = copy .deepcopy (self .accounts )
135-
136199 def rollback_and_refund (error_message , gas_used ):
137- self .accounts = copy .deepcopy (state_snapshot )
200+ journal .rollback ()
201+ self .accounts = original_accounts
138202 refund_acc = self .accounts [tx .sender ]
139- refund_acc ['balance' ] += tx .amount
140- gas_refund = getattr (tx , 'gas_limit' , 0 ) - gas_used
141- if gas_refund > 0 :
142- refund_acc ['balance' ] += (gas_refund * getattr (tx , 'fee_per_gas' , 0 ))
203+ refund_acc ['balance' ] -= (gas_used * getattr (tx , 'fee_per_gas' , 0 ))
204+ refund_acc ['nonce' ] += 1
143205 return Receipt (tx .tx_id , status = 0 , error_message = error_message , gas_used = gas_used )
144206
145207 # LOGIC BRANCH 1: Contract Deployment
@@ -162,6 +224,9 @@ def rollback_and_refund(error_message, gas_used):
162224 gas_refund = gas_used - code_gas
163225 if gas_refund > 0 :
164226 self .accounts [tx .sender ]['balance' ] += (gas_refund * getattr (tx , 'fee_per_gas' , 0 ))
227+
228+ journal .commit ()
229+ self .accounts = original_accounts
165230 return Receipt (tx .tx_id , status = 1 , contract_address = contract_address , gas_used = code_gas )
166231
167232 # LOGIC BRANCH 2: Contract Call
@@ -187,12 +252,17 @@ def rollback_and_refund(error_message, gas_used):
187252 if gas_refund > 0 :
188253 self .accounts [tx .sender ]['balance' ] += (gas_refund * getattr (tx , 'fee_per_gas' , 0 ))
189254
255+ journal .commit ()
256+ self .accounts = original_accounts
190257 return Receipt (tx .tx_id , status = 1 , gas_used = gas_used )
191258
192259 # LOGIC BRANCH 3: Regular Transfer
193260 receiver = self .get_account (tx .receiver )
194261 receiver ['balance' ] += tx .amount
195262 gas_used = getattr (tx , 'gas_limit' , 0 )
263+
264+ journal .commit ()
265+ self .accounts = original_accounts
196266 return Receipt (tx .tx_id , status = 1 , gas_used = gas_used )
197267
198268 def execute_internal_call (self , sender , receiver_address , amount , payload , gas_limit , depth , is_top_level = False ):
0 commit comments