@@ -9,7 +9,10 @@ use std::{
99 sync:: { Arc , Mutex } ,
1010} ;
1111
12- use linera_base:: vm:: VmRuntime ;
12+ use linera_base:: {
13+ identifiers:: { Account , AccountOwner } ,
14+ vm:: VmRuntime ,
15+ } ;
1316use linera_views:: common:: from_bytes_option;
1417use revm:: { primitives:: keccak256, Database , DatabaseCommit , DatabaseRef } ;
1518use revm_context:: BlockEnv ;
@@ -18,7 +21,11 @@ use revm_database::{AccountState, DBErrorMarker};
1821use revm_primitives:: { address, Address , B256 , U256 } ;
1922use revm_state:: { AccountInfo , Bytecode , EvmState } ;
2023
21- use crate :: { ApplicationId , BaseRuntime , Batch , ContractRuntime , ExecutionError , ServiceRuntime } ;
24+ use crate :: {
25+ evm:: { read_amount, inputs:: ZERO_ADDRESS } ,
26+ BaseRuntime , Batch , ContractRuntime , EvmExecutionError , ExecutionError ,
27+ ServiceRuntime ,
28+ } ;
2229
2330// The runtime costs are not available in service operations.
2431// We need to set a limit to gas usage in order to avoid blocking
@@ -74,19 +81,28 @@ pub(crate) struct DatabaseRuntime<Runtime> {
7481 /// This is the EVM address of the contract.
7582 /// At the creation, it is set to `Address::ZERO` and then later set to the correct value.
7683 pub contract_address : Address ,
84+ /// The caller to the smart contract
85+ pub caller : Address ,
86+ /// The value of the smart contract
87+ pub value : U256 ,
7788 /// The runtime of the contract.
7889 pub runtime : Arc < Mutex < Runtime > > ,
7990 /// The uncommitted changes to the contract.
8091 pub changes : EvmState ,
92+ /// The error that can occur during runtime.
93+ pub error : Arc < Mutex < Option < String > > > ,
8194}
8295
8396impl < Runtime > Clone for DatabaseRuntime < Runtime > {
8497 fn clone ( & self ) -> Self {
8598 Self {
8699 storage_stats : self . storage_stats . clone ( ) ,
87100 contract_address : self . contract_address ,
101+ caller : self . caller ,
102+ value : self . value ,
88103 runtime : self . runtime . clone ( ) ,
89104 changes : self . changes . clone ( ) ,
105+ error : self . error . clone ( ) ,
90106 }
91107 }
92108}
@@ -98,23 +114,17 @@ pub enum KeyCategory {
98114 Storage ,
99115}
100116
101- fn application_id_to_address ( application_id : ApplicationId ) -> Address {
102- let application_id: [ u64 ; 4 ] = <[ u64 ; 4 ] >:: from ( application_id. application_description_hash ) ;
103- let application_id: [ u8 ; 32 ] = linera_base:: crypto:: u64_array_to_be_bytes ( application_id) ;
104- Address :: from_slice ( & application_id[ 0 ..20 ] )
105- }
106-
107117impl < Runtime : BaseRuntime > DatabaseRuntime < Runtime > {
108118 /// Encode the `index` of the EVM storage associated to the smart contract
109119 /// in a linera key.
110- fn get_linera_key ( key_prefix : & [ u8 ] , index : U256 ) -> Result < Vec < u8 > , ExecutionError > {
120+ fn get_linera_key ( key_prefix : & [ u8 ] , index : U256 ) -> Vec < u8 > {
111121 let mut key = key_prefix. to_vec ( ) ;
112- bcs :: serialize_into ( & mut key, & index) ? ;
113- Ok ( key)
122+ key. extend ( index. as_le_slice ( ) ) ;
123+ key
114124 }
115125
116126 /// Returns the tag associated to the contract.
117- fn get_address_key ( & self , prefix : u8 , address : Address ) -> Vec < u8 > {
127+ fn get_address_key ( prefix : u8 , address : Address ) -> Vec < u8 > {
118128 let mut key = vec ! [ prefix] ;
119129 key. extend ( address) ;
120130 key
@@ -129,8 +139,11 @@ impl<Runtime: BaseRuntime> DatabaseRuntime<Runtime> {
129139 Self {
130140 storage_stats : Arc :: new ( Mutex :: new ( storage_stats) ) ,
131141 contract_address : Address :: ZERO ,
142+ caller : Address :: ZERO ,
143+ value : U256 :: ZERO ,
132144 runtime : Arc :: new ( Mutex :: new ( runtime) ) ,
133145 changes : HashMap :: new ( ) ,
146+ error : Arc :: new ( Mutex :: new ( None ) ) ,
134147 }
135148 }
136149
@@ -144,6 +157,23 @@ impl<Runtime: BaseRuntime> DatabaseRuntime<Runtime> {
144157 * storage_stats_read = StorageStats :: default ( ) ;
145158 storage_stats
146159 }
160+
161+ /// Insert error into the database
162+ pub fn insert_error ( & self , exec_error : ExecutionError ) {
163+ let mut error = self . error . lock ( ) . expect ( "The lock should be possible" ) ;
164+ * error = Some ( format ! ( "Runtime error {:?}" , exec_error) ) ;
165+ }
166+
167+ /// Process the error.
168+ pub fn process_any_error ( & self ) -> Result < ( ) , EvmExecutionError > {
169+ let error = self . error . lock ( ) . expect ( "The lock should be possible" ) ;
170+ if error. is_some ( ) {
171+ if let Some ( error) = error. clone ( ) {
172+ return Err ( EvmExecutionError :: RuntimeError ( error) ) ;
173+ }
174+ }
175+ Ok ( ( ) )
176+ }
147177}
148178
149179impl DBErrorMarker for ExecutionError { }
@@ -192,11 +222,42 @@ where
192222 return Ok ( Some ( account. info . clone ( ) ) ) ;
193223 }
194224 let mut runtime = self . runtime . lock ( ) . expect ( "The lock should be possible" ) ;
195- let key_info = self . get_address_key ( KeyCategory :: AccountInfo as u8 , address) ;
225+ let account_owner = if address == self . contract_address {
226+ let application_id = runtime. application_id ( ) ?;
227+ application_id. into ( )
228+ } else {
229+ address. into ( )
230+ } ;
231+ // The balances being used are the ones of Linera. So, we need to
232+ // access them at first.
233+ let balance = runtime. read_owner_balance ( account_owner) ?;
234+
235+ let balance: U256 = balance. into ( ) ;
236+ let key_info = Self :: get_address_key ( KeyCategory :: AccountInfo as u8 , address) ;
196237 let promise = runtime. read_value_bytes_new ( key_info) ?;
197238 let result = runtime. read_value_bytes_wait ( & promise) ?;
198- let account_info = from_bytes_option :: < AccountInfo > ( & result) ?;
199- Ok ( account_info)
239+ let mut account_info = match result {
240+ None => AccountInfo :: default ( ) ,
241+ Some ( bytes) => bcs:: from_bytes ( & bytes) ?,
242+ } ;
243+ // The funds have been immediately deposited in deposit_funds.
244+ // The EVM will do the same before even the execution of
245+ // the constructor or function.
246+ // Therefore, we need to adjust the values.
247+ // This will ensure that at any time the balances in EVM
248+ // and Linera are exactly matching during the execution.
249+ let start_balance = if self . caller == address {
250+ balance + self . value
251+ } else if self . contract_address == address {
252+ balance - self . value
253+ } else {
254+ balance
255+ } ;
256+ account_info. balance = start_balance;
257+ // The balance is non-zero. Therefore, the account exists.đ
258+ // However, the state is None. Therefore, we need to create
259+ // a default account first.
260+ Ok ( Some ( account_info) )
200261 }
201262
202263 fn code_by_hash_ref ( & self , _code_hash : B256 ) -> Result < Bytecode , ExecutionError > {
@@ -211,8 +272,8 @@ where
211272 Some ( slot) => slot. present_value ( ) ,
212273 } ) ;
213274 }
214- let key_prefix = self . get_address_key ( KeyCategory :: Storage as u8 , address) ;
215- let key = Self :: get_linera_key ( & key_prefix, index) ? ;
275+ let key_prefix = Self :: get_address_key ( KeyCategory :: Storage as u8 , address) ;
276+ let key = Self :: get_linera_key ( & key_prefix, index) ;
216277 {
217278 let mut storage_stats = self
218279 . storage_stats
@@ -249,9 +310,9 @@ where
249310 if !account. is_touched ( ) {
250311 continue ;
251312 }
252- let key_prefix = self . get_address_key ( KeyCategory :: Storage as u8 , * address) ;
253- let key_info = self . get_address_key ( KeyCategory :: AccountInfo as u8 , * address) ;
254- let key_state = self . get_address_key ( KeyCategory :: AccountState as u8 , * address) ;
313+ let key_prefix = Self :: get_address_key ( KeyCategory :: Storage as u8 , * address) ;
314+ let key_info = Self :: get_address_key ( KeyCategory :: AccountInfo as u8 , * address) ;
315+ let key_state = Self :: get_address_key ( KeyCategory :: AccountState as u8 , * address) ;
255316 if account. is_selfdestructed ( ) {
256317 batch. delete_key_prefix ( key_prefix) ;
257318 batch. put_key_value ( key_info, & AccountInfo :: default ( ) ) ?;
@@ -278,7 +339,7 @@ where
278339 if value. present_value ( ) == value. original_value ( ) {
279340 storage_stats. key_no_operation += 1 ;
280341 } else {
281- let key = Self :: get_linera_key ( & key_prefix, * index) ? ;
342+ let key = Self :: get_linera_key ( & key_prefix, * index) ;
282343 if value. original_value ( ) == U256 :: ZERO {
283344 batch. put_key_value ( key, & value. present_value ( ) ) ?;
284345 storage_stats. key_set += 1 ;
@@ -317,7 +378,7 @@ where
317378 pub fn set_contract_address ( & mut self ) -> Result < ( ) , ExecutionError > {
318379 let mut runtime = self . runtime . lock ( ) . expect ( "The lock should be possible" ) ;
319380 let application_id = runtime. application_id ( ) ?;
320- self . contract_address = application_id_to_address ( application_id) ;
381+ self . contract_address = application_id. evm_address ( ) ;
321382 Ok ( ( ) )
322383 }
323384
@@ -326,7 +387,7 @@ where
326387 pub fn is_initialized ( & self ) -> Result < bool , ExecutionError > {
327388 let mut runtime = self . runtime . lock ( ) . expect ( "The lock should be possible" ) ;
328389 let evm_address = runtime. application_id ( ) ?. evm_address ( ) ;
329- let key_info = self . get_address_key ( KeyCategory :: AccountInfo as u8 , evm_address) ;
390+ let key_info = Self :: get_address_key ( KeyCategory :: AccountInfo as u8 , evm_address) ;
330391 let promise = runtime. contains_key_new ( key_info) ?;
331392 let result = runtime. contains_key_wait ( & promise) ?;
332393 Ok ( result)
@@ -394,6 +455,25 @@ where
394455 block_env. gas_limit = gas_limit;
395456 Ok ( block_env)
396457 }
458+
459+ pub fn deposit_funds ( & self ) -> Result < ( ) , ExecutionError > {
460+ if self . value != U256 :: ZERO {
461+ let mut runtime = self . runtime . lock ( ) . expect ( "The lock should be possible" ) ;
462+ if self . caller == ZERO_ADDRESS {
463+ let error = EvmExecutionError :: UnknownSigner ;
464+ return Err ( error. into ( ) ) ;
465+ }
466+ let source: AccountOwner = self . caller . into ( ) ;
467+ let chain_id = runtime. chain_id ( ) ?;
468+ let application_id = runtime. application_id ( ) ?;
469+ let owner: AccountOwner = application_id. into ( ) ;
470+ let destination = Account { chain_id, owner } ;
471+ let amount = read_amount ( self . value ) ?;
472+
473+ runtime. transfer ( source, destination, amount) ?;
474+ }
475+ Ok ( ( ) )
476+ }
397477}
398478
399479impl < Runtime > DatabaseRuntime < Runtime >
0 commit comments