@@ -16,7 +16,9 @@ use crate::{
1616 hash:: keccak,
1717 machine:: Machine ,
1818 parameters:: staking:: * ,
19- state:: { CallStackInfo , CleanupMode , State , Substate } ,
19+ state:: {
20+ CallStackInfo , CleanupMode , CollateralCheckResult , State , Substate ,
21+ } ,
2022 statedb:: Result as DbResult ,
2123 verification:: VerificationConfig ,
2224 vm:: {
@@ -1321,7 +1323,7 @@ impl<'a> Executive<'a> {
13211323 ) ) ;
13221324 }
13231325
1324- let mut substate = Substate :: new ( ) ;
1326+ let mut tx_substate = Substate :: new ( ) ;
13251327 if balance512 < sender_intended_cost {
13261328 // Sender is responsible for the insufficient balance.
13271329 // Sub tx fee if not enough cash, and substitute all remaining
@@ -1347,7 +1349,7 @@ impl<'a> Executive<'a> {
13471349 self . state . sub_balance (
13481350 & sender,
13491351 & actual_gas_cost,
1350- & mut substate . to_cleanup_mode ( & spec) ,
1352+ & mut tx_substate . to_cleanup_mode ( & spec) ,
13511353 ) ?;
13521354
13531355 return Ok ( ExecutionOutcome :: ExecutionErrorBumpNonce (
@@ -1372,7 +1374,7 @@ impl<'a> Executive<'a> {
13721374 self . state . sub_balance (
13731375 & sender,
13741376 & U256 :: try_from ( gas_cost) . unwrap ( ) ,
1375- & mut substate . to_cleanup_mode ( & spec) ,
1377+ & mut tx_substate . to_cleanup_mode ( & spec) ,
13761378 ) ?;
13771379 } else {
13781380 self . state . sub_sponsor_balance_for_gas (
@@ -1382,6 +1384,7 @@ impl<'a> Executive<'a> {
13821384 }
13831385
13841386 self . state . checkpoint ( ) ;
1387+ let mut substate = Substate :: new ( ) ;
13851388
13861389 let res = match tx. action {
13871390 Action :: Create => {
@@ -1461,6 +1464,7 @@ impl<'a> Executive<'a> {
14611464 let out = match & res {
14621465 Ok ( res) => {
14631466 self . state . discard_checkpoint ( ) ;
1467+ tx_substate. accrue ( substate) ;
14641468 res. return_data . to_vec ( )
14651469 }
14661470 Err ( vm:: Error :: StateDbError ( _) ) => {
@@ -1483,14 +1487,81 @@ impl<'a> Executive<'a> {
14831487
14841488 Ok ( self . finalize (
14851489 tx,
1486- substate ,
1490+ tx_substate ,
14871491 result,
14881492 output,
14891493 refund_receiver,
14901494 storage_sponsored,
14911495 ) ?)
14921496 }
14931497
1498+ fn kill_process (
1499+ & mut self , suicides : & HashSet < Address > ,
1500+ ) -> DbResult < Substate > {
1501+ let mut substate = Substate :: new ( ) ;
1502+ for address in suicides {
1503+ if let Some ( code_size) = self . state . code_size ( address) ? {
1504+ // Only refund the code collateral when code exists.
1505+ // If a contract suicides during creation, the code will be
1506+ // empty.
1507+ let code_owner =
1508+ self . state . code_owner ( address) ?. expect ( "code owner exists" ) ;
1509+ substate. record_storage_release ( & code_owner, code_size as u64 ) ;
1510+ }
1511+
1512+ self . state
1513+ . record_storage_entries_release ( address, & mut substate) ?;
1514+ }
1515+
1516+ let res = self . state . settle_collateral_for_all ( & substate) ?;
1517+ // The storage recycling process should never occupy new collateral.
1518+ assert_eq ! ( res, CollateralCheckResult :: Valid ) ;
1519+
1520+ for contract_address in suicides {
1521+ let sponsor_for_gas =
1522+ self . state . sponsor_for_gas ( contract_address) ?;
1523+ let sponsor_for_collateral =
1524+ self . state . sponsor_for_collateral ( contract_address) ?;
1525+ let sponsor_balance_for_gas =
1526+ self . state . sponsor_balance_for_gas ( contract_address) ?;
1527+ let sponsor_balance_for_collateral = self
1528+ . state
1529+ . sponsor_balance_for_collateral ( contract_address) ?;
1530+
1531+ if sponsor_for_gas. is_some ( ) {
1532+ self . state . add_balance (
1533+ sponsor_for_gas. as_ref ( ) . unwrap ( ) ,
1534+ & sponsor_balance_for_gas,
1535+ substate. to_cleanup_mode ( self . spec ) ,
1536+ ) ?;
1537+ self . state . sub_sponsor_balance_for_gas (
1538+ contract_address,
1539+ & sponsor_balance_for_gas,
1540+ ) ?;
1541+ }
1542+ if sponsor_for_collateral. is_some ( ) {
1543+ self . state . add_balance (
1544+ sponsor_for_collateral. as_ref ( ) . unwrap ( ) ,
1545+ & sponsor_balance_for_collateral,
1546+ substate. to_cleanup_mode ( self . spec ) ,
1547+ ) ?;
1548+ self . state . sub_sponsor_balance_for_collateral (
1549+ contract_address,
1550+ & sponsor_balance_for_collateral,
1551+ ) ?;
1552+ }
1553+ }
1554+
1555+ for contract_address in suicides {
1556+ let burnt_balance = self . state . balance ( contract_address) ?
1557+ + self . state . staking_balance ( contract_address) ?;
1558+ self . state . remove_contract ( contract_address) ?;
1559+ self . state . subtract_total_issued ( burnt_balance) ;
1560+ }
1561+
1562+ Ok ( substate)
1563+ }
1564+
14941565 /// Finalizes the transaction (does refunds and suicides).
14951566 fn finalize (
14961567 & mut self , tx : & SignedTransaction , mut substate : Substate ,
@@ -1531,9 +1602,9 @@ impl<'a> Executive<'a> {
15311602 } ;
15321603
15331604 // perform suicides
1534- for address in & substate . suicides {
1535- self . state . kill_account ( address ) ?;
1536- }
1605+
1606+ let subsubstate = self . kill_process ( & substate . suicides ) ?;
1607+ substate . accrue ( subsubstate ) ;
15371608
15381609 // TODO should be added back after enabling dust collection
15391610 // Should be executed once per block, instead of per transaction?
@@ -1567,36 +1638,24 @@ impl<'a> Executive<'a> {
15671638 let mut storage_released = Vec :: new ( ) ;
15681639
15691640 if r. apply_state {
1570- let affected_address1 : HashSet < _ > = substate
1571- . storage_collateralized
1572- . keys ( )
1641+ let mut affected_address : Vec < _ > = substate
1642+ . keys_for_collateral_changed ( )
1643+ . iter ( )
15731644 . cloned ( )
15741645 . collect ( ) ;
1575- let affected_address2: HashSet < _ > =
1576- substate. storage_released . keys ( ) . cloned ( ) . collect ( ) ;
1577- let mut affected_address: Vec < _ > =
1578- affected_address1. union ( & affected_address2) . collect ( ) ;
15791646 affected_address. sort ( ) ;
15801647 for address in affected_address {
1581- let inc = substate
1582- . storage_collateralized
1583- . get ( address)
1584- . cloned ( )
1585- . unwrap_or ( 0 ) ;
1586- let sub = substate
1587- . storage_released
1588- . get ( address)
1589- . cloned ( )
1590- . unwrap_or ( 0 ) ;
1591- if inc > sub {
1648+ let ( inc, sub) =
1649+ substate. get_collateral_change ( address) ;
1650+ if inc > 0 {
15921651 storage_collateralized. push ( StorageChange {
15931652 address : * address,
1594- amount : inc - sub ,
1653+ amount : inc,
15951654 } ) ;
1596- } else if inc < sub {
1655+ } else if sub > 0 {
15971656 storage_released. push ( StorageChange {
15981657 address : * address,
1599- amount : sub - inc ,
1658+ amount : sub,
16001659 } ) ;
16011660 }
16021661 }
0 commit comments