cfx_executor/state/overlay_account/
factory.rs

1use std::sync::Arc;
2
3use cfx_types::{Address, AddressSpaceUtil, AddressWithSpace, Space, U256};
4use keccak_hash::KECCAK_EMPTY;
5use parking_lot::lock_api::RwLock;
6use primitives::{Account, SponsorInfo, StorageLayout};
7
8use super::{checkpoints::WriteCheckpointLayer, OverlayAccount};
9
10impl Default for OverlayAccount {
11    fn default() -> Self {
12        OverlayAccount {
13            address: Address::zero().with_native_space(),
14            balance: U256::zero(),
15            nonce: U256::zero(),
16            admin: Address::zero(),
17            sponsor_info: Default::default(),
18            storage_read_cache: Default::default(),
19            storage_committed_cache: Default::default(),
20            storage_write_cache: Default::default(),
21            storage_write_checkpoint: Default::default(),
22            transient_storage_cache: Default::default(),
23            transient_storage_checkpoint: Default::default(),
24            storage_layout_change: None,
25            staking_balance: 0.into(),
26            collateral_for_storage: 0.into(),
27            accumulated_interest_return: 0.into(),
28            deposit_list: None,
29            vote_stake_list: None,
30            code_hash: KECCAK_EMPTY,
31            code: None,
32            is_newly_created_contract: false,
33            pending_db_clear: false,
34            storage_overrided: false,
35            create_transaction_hash: None,
36        }
37    }
38}
39
40impl OverlayAccount {
41    /// Create an OverlayAccount from loaded account.
42    pub fn from_loaded(address: &AddressWithSpace, account: Account) -> Self {
43        let overlay_account = OverlayAccount {
44            address: address.clone(),
45            balance: account.balance,
46            nonce: account.nonce,
47            admin: account.admin,
48            sponsor_info: account.sponsor_info,
49            staking_balance: account.staking_balance,
50            collateral_for_storage: account.collateral_for_storage,
51            accumulated_interest_return: account.accumulated_interest_return,
52            code_hash: account.code_hash,
53            ..Default::default()
54        };
55
56        overlay_account
57    }
58
59    /// Create an OverlayAccount of basic account when the account doesn't exist
60    /// before.
61    pub fn new_basic(address: &AddressWithSpace, balance: U256) -> Self {
62        OverlayAccount {
63            address: address.clone(),
64            balance,
65            ..Default::default()
66        }
67    }
68
69    /// Create an OverlayAccount of basic account when the account doesn't exist
70    /// before.
71    pub fn new_removed(address: &AddressWithSpace) -> Self {
72        OverlayAccount {
73            address: address.clone(),
74            pending_db_clear: true,
75            ..Default::default()
76        }
77    }
78
79    /// Create an OverlayAccount of contract account when the account doesn't
80    /// exist before.
81    pub fn new_contract_with_admin(
82        address: &AddressWithSpace, balance: U256, admin: &Address,
83        pending_db_clear: bool, storage_layout: Option<StorageLayout>,
84        cip107: bool,
85    ) -> Self {
86        let sponsor_info = if cip107 && address.space == Space::Native {
87            SponsorInfo {
88                storage_points: Some(Default::default()),
89                ..Default::default()
90            }
91        } else {
92            Default::default()
93        };
94        OverlayAccount {
95            address: address.clone(),
96            balance,
97            nonce: U256::one(),
98            admin: admin.clone(),
99            sponsor_info,
100            storage_layout_change: storage_layout,
101            is_newly_created_contract: true,
102            pending_db_clear,
103            ..Default::default()
104        }
105    }
106
107    /// Create an OverlayAccount of contract account when the account doesn't
108    /// exist before.
109    #[cfg(test)]
110    pub fn new_contract(
111        address: &AddressWithSpace, balance: U256, pending_db_clear: bool,
112        storage_layout: Option<StorageLayout>,
113    ) -> Self {
114        Self::new_contract_with_admin(
115            &address,
116            balance,
117            &Address::zero(),
118            pending_db_clear,
119            storage_layout,
120            false,
121        )
122    }
123
124    /// This function replicates the behavior of the auto-derived `Clone`
125    /// implementation, but is manually implemented to explicitly invoke the
126    /// `clone` method.
127    ///
128    /// This approach is necessary because a casual clone could lead to
129    /// unintended panic: The `OverlayAccount`s in different checkpoint
130    /// layers for the same address shares an `Arc` pointer to the same storage
131    /// cache object. During commit, it's asserted that each storage cache
132    /// object has only one pointer, meaning each address can only have one
133    /// copy.
134    ///
135    /// Thus, this manual implementation ensures that the cloning of an account
136    /// is traceable and controlled。
137    pub fn clone_account_for_checkpoint(&self, checkpoint_id: usize) -> Self {
138        OverlayAccount {
139            address: self.address,
140            balance: self.balance,
141            nonce: self.nonce,
142            admin: self.admin,
143
144            sponsor_info: self.sponsor_info.clone(),
145            staking_balance: self.staking_balance,
146            collateral_for_storage: self.collateral_for_storage,
147            accumulated_interest_return: self.accumulated_interest_return,
148            deposit_list: self.deposit_list.clone(),
149            vote_stake_list: self.vote_stake_list.clone(),
150            code_hash: self.code_hash,
151            code: self.code.clone(),
152            is_newly_created_contract: self.is_newly_created_contract,
153            pending_db_clear: self.pending_db_clear,
154            storage_write_cache: self.storage_write_cache.clone(),
155            storage_write_checkpoint: Some(RwLock::new(
156                WriteCheckpointLayer::new_empty(checkpoint_id),
157            )),
158            storage_committed_cache: self.storage_committed_cache.clone(),
159            storage_read_cache: self.storage_read_cache.clone(),
160            transient_storage_cache: self.transient_storage_cache.clone(),
161            transient_storage_checkpoint: Some(
162                WriteCheckpointLayer::new_empty(checkpoint_id),
163            ),
164            storage_layout_change: self.storage_layout_change.clone(),
165            storage_overrided: self.storage_overrided,
166            create_transaction_hash: self.create_transaction_hash.clone(),
167        }
168    }
169
170    pub fn clone_from_committed_cache(&self) -> Self {
171        assert!(self.storage_write_checkpoint.is_none());
172        assert!(self.transient_storage_checkpoint.is_none());
173        assert!(self.storage_write_cache.read().is_empty());
174        assert_eq!(Arc::strong_count(&self.storage_read_cache), 1);
175        assert_eq!(Arc::strong_count(&self.storage_committed_cache), 1);
176        assert_eq!(Arc::strong_count(&self.storage_write_cache), 1);
177        assert_eq!(Arc::strong_count(&self.transient_storage_cache), 1);
178
179        // This is a mistake from the early implementation of transient storage,
180        // in which the transient_storage_cache is not cleared.
181        let transient_storage_cache =
182            Arc::new(RwLock::new(self.transient_storage_cache.read().clone()));
183
184        OverlayAccount {
185            address: self.address,
186            balance: self.balance,
187            nonce: self.nonce,
188            admin: self.admin,
189
190            sponsor_info: self.sponsor_info.clone(),
191            staking_balance: self.staking_balance,
192            collateral_for_storage: self.collateral_for_storage,
193            accumulated_interest_return: self.accumulated_interest_return,
194            deposit_list: self.deposit_list.clone(),
195            vote_stake_list: self.vote_stake_list.clone(),
196            code_hash: self.code_hash,
197            code: self.code.clone(),
198            is_newly_created_contract: self.is_newly_created_contract,
199            pending_db_clear: self.pending_db_clear,
200            storage_write_cache: Default::default(),
201            storage_write_checkpoint: None,
202            storage_committed_cache: self.storage_committed_cache.clone(),
203            storage_read_cache: self.storage_read_cache.clone(),
204            transient_storage_cache,
205            transient_storage_checkpoint: None,
206            storage_layout_change: self.storage_layout_change.clone(),
207            storage_overrided: self.storage_overrided,
208            create_transaction_hash: self.create_transaction_hash.clone(),
209        }
210    }
211
212    pub fn clone_account(&self) -> Self {
213        OverlayAccount {
214            address: self.address,
215            balance: self.balance,
216            nonce: self.nonce,
217            admin: self.admin,
218            sponsor_info: self.sponsor_info.clone(),
219            staking_balance: self.staking_balance,
220            collateral_for_storage: self.collateral_for_storage,
221            accumulated_interest_return: self.accumulated_interest_return,
222            deposit_list: self.deposit_list.clone(),
223            vote_stake_list: self.vote_stake_list.clone(),
224            code_hash: self.code_hash,
225            code: self.code.clone(),
226            is_newly_created_contract: self.is_newly_created_contract,
227            pending_db_clear: self.pending_db_clear,
228            storage_write_cache: Arc::new(RwLock::new(
229                self.storage_write_cache.read().clone(),
230            )),
231            storage_write_checkpoint: None,
232            storage_read_cache: Arc::new(RwLock::new(
233                self.storage_read_cache.read().clone(),
234            )),
235            transient_storage_cache: Arc::new(RwLock::new(
236                self.transient_storage_cache.read().clone(),
237            )),
238            storage_committed_cache: Arc::new(RwLock::new(
239                self.storage_committed_cache.read().clone(),
240            )),
241            transient_storage_checkpoint: None,
242            storage_layout_change: self.storage_layout_change.clone(),
243            storage_overrided: self.storage_overrided,
244            create_transaction_hash: self.create_transaction_hash.clone(),
245        }
246    }
247}
248
249impl OverlayAccount {
250    pub fn as_account(&self) -> Account {
251        let mut account = Account::new_empty(self.address());
252
253        account.balance = self.balance;
254        account.nonce = self.nonce;
255        account.code_hash = self.code_hash;
256        account.staking_balance = self.staking_balance;
257        account.collateral_for_storage = self.collateral_for_storage;
258        account.accumulated_interest_return = self.accumulated_interest_return;
259        account.admin = self.admin;
260        account.sponsor_info = self.sponsor_info.clone();
261        account.set_address(self.address);
262        account
263    }
264}