cfx_executor/state/state_object/
sponsor.rs

1use cfx_parameters::internal_contract_addresses::SPONSOR_WHITELIST_CONTROL_CONTRACT_ADDRESS;
2use cfx_statedb::{
3    access_mode,
4    global_params::{ConvertedStoragePoints, TotalIssued},
5    Result as DbResult,
6};
7use cfx_types::{
8    maybe_address, Address, AddressSpaceUtil, AddressWithSpace, U256,
9};
10use primitives::{SponsorInfo, StorageKey};
11
12use super::{State, Substate};
13use crate::{return_if, try_loaded};
14
15lazy_static! {
16    static ref COMMISSION_PRIVILEGE_STORAGE_VALUE: U256 = U256::one();
17    /// If we set this key, it means every account has commission privilege.
18    pub static ref COMMISSION_PRIVILEGE_SPECIAL_KEY: Address = Address::zero();
19}
20
21impl State {
22    pub fn sponsor_info(
23        &self, address: &Address,
24    ) -> DbResult<Option<SponsorInfo>> {
25        let acc = try_loaded!(self.read_native_account_lock(address));
26        Ok(Some(acc.sponsor_info().clone()))
27    }
28
29    // Sponsor for gas
30
31    pub fn sponsor_for_gas(
32        &self, address: &Address,
33    ) -> DbResult<Option<Address>> {
34        let acc = try_loaded!(self.read_native_account_lock(address));
35        Ok(maybe_address(&acc.sponsor_info().sponsor_for_gas))
36    }
37
38    pub fn set_sponsor_for_gas(
39        &self, address: &Address, sponsor: &Address, sponsor_balance: &U256,
40        upper_bound: &U256,
41    ) -> DbResult<()> {
42        let sponsor_not_change =
43            *sponsor == self.sponsor_for_gas(address)?.unwrap_or_default();
44        let balance_not_change =
45            *sponsor_balance == self.sponsor_balance_for_gas(address)?;
46        return_if!(sponsor_not_change && balance_not_change);
47
48        self.write_native_account_lock(&address)?
49            .set_sponsor_for_gas(sponsor, sponsor_balance, upper_bound);
50        Ok(())
51    }
52
53    // Sponsor balance for gas
54
55    pub fn sponsor_balance_for_gas(&self, address: &Address) -> DbResult<U256> {
56        let acc = try_loaded!(self.read_native_account_lock(address));
57        Ok(acc.sponsor_info().sponsor_balance_for_gas)
58    }
59
60    pub fn add_sponsor_balance_for_gas(
61        &mut self, address: &Address, by: &U256,
62    ) -> DbResult<()> {
63        return_if!(by.is_zero());
64
65        self.write_native_account_lock(&address)?
66            .add_sponsor_balance_for_gas(by);
67        Ok(())
68    }
69
70    pub fn sub_sponsor_balance_for_gas(
71        &mut self, address: &Address, by: &U256,
72    ) -> DbResult<()> {
73        return_if!(by.is_zero());
74
75        self.write_native_account_lock(&address)?
76            .sub_sponsor_balance_for_gas(by);
77        Ok(())
78    }
79
80    // Sponsor gas bound
81
82    pub fn sponsor_gas_bound(&self, address: &Address) -> DbResult<U256> {
83        let acc = try_loaded!(self.read_native_account_lock(address));
84        Ok(acc.sponsor_info().sponsor_gas_bound)
85    }
86
87    // Sponsor for collateral
88
89    pub fn sponsor_for_collateral(
90        &self, address: &Address,
91    ) -> DbResult<Option<Address>> {
92        let acc = try_loaded!(self.read_native_account_lock(address));
93        Ok(maybe_address(&acc.sponsor_info().sponsor_for_collateral))
94    }
95
96    pub fn set_sponsor_for_collateral(
97        &mut self, address: &Address, sponsor: &Address,
98        sponsor_balance: &U256, is_cip107: bool,
99    ) -> DbResult<U256> {
100        let sponsor_not_change = *sponsor
101            == self.sponsor_for_collateral(address)?.unwrap_or_default();
102        let balance_not_change =
103            *sponsor_balance == self.sponsor_balance_for_collateral(address)?;
104        return_if!(sponsor_not_change && balance_not_change);
105
106        let prop = if is_cip107 {
107            self.storage_point_prop()?
108        } else {
109            U256::zero()
110        };
111
112        let converted_storage_points = self
113            .write_native_account_lock(&address)?
114            .set_sponsor_for_collateral(sponsor, sponsor_balance, prop);
115
116        *self.global_stat.val::<TotalIssued>() -= converted_storage_points;
117        *self.global_stat.val::<ConvertedStoragePoints>() +=
118            converted_storage_points;
119        Ok(converted_storage_points)
120    }
121
122    // Sponsor balance for collateral
123
124    pub fn sponsor_balance_for_collateral(
125        &self, address: &Address,
126    ) -> DbResult<U256> {
127        let acc = try_loaded!(self.read_native_account_lock(address));
128        Ok(acc.sponsor_info().sponsor_balance_for_collateral)
129    }
130
131    pub fn add_sponsor_balance_for_collateral(
132        &mut self, address: &Address, by: &U256,
133    ) -> DbResult<()> {
134        return_if!(by.is_zero());
135
136        self.write_native_account_lock(&address)?
137            .add_sponsor_balance_for_collateral(by);
138        Ok(())
139    }
140
141    pub fn sub_sponsor_balance_for_collateral(
142        &mut self, address: &Address, by: &U256,
143    ) -> DbResult<()> {
144        return_if!(by.is_zero());
145
146        self.write_native_account_lock(&address)?
147            .sub_sponsor_balance_for_collateral(by);
148
149        Ok(())
150    }
151
152    // Whitelist
153
154    pub fn check_contract_whitelist(
155        &self, contract_address: &Address, user: &Address,
156    ) -> DbResult<bool> {
157        let special_value = self.storage_at(
158            &sponsor_address(),
159            &special_sponsor_key(&contract_address),
160        )?;
161        if !special_value.is_zero() {
162            Ok(true)
163        } else {
164            self.storage_at(
165                &sponsor_address(),
166                &sponsor_key(contract_address, user),
167            )
168            .map(|x| !x.is_zero())
169        }
170    }
171
172    pub fn add_to_contract_whitelist(
173        &mut self, contract_address: Address, storage_owner: Address,
174        user: Address, substate: &mut Substate,
175    ) -> DbResult<()> {
176        info!(
177            "add_commission_privilege contract_address: {:?}, user: {:?}",
178            contract_address, user
179        );
180
181        self.set_storage(
182            &sponsor_address(),
183            sponsor_key(&contract_address, &user),
184            COMMISSION_PRIVILEGE_STORAGE_VALUE.clone(),
185            storage_owner,
186            substate,
187        )?;
188
189        Ok(())
190    }
191
192    pub fn remove_from_contract_whitelist(
193        &mut self, contract_address: Address, storage_owner: Address,
194        user: Address, substate: &mut Substate,
195    ) -> DbResult<()> {
196        self.set_storage(
197            &sponsor_address(),
198            sponsor_key(&contract_address, &user),
199            U256::zero(),
200            storage_owner,
201            substate,
202        )?;
203
204        Ok(())
205    }
206
207    pub fn record_storage_and_whitelist_entries_release(
208        &mut self, address: &Address, substate: &mut Substate, cip131: bool,
209    ) -> DbResult<()> {
210        if !cip131 {
211            storage_range_deletion_for_account(
212                self,
213                &SPONSOR_WHITELIST_CONTROL_CONTRACT_ADDRESS,
214                address.as_ref(),
215                substate,
216            )?;
217        }
218        storage_range_deletion_for_account(self, address, &vec![], substate)?;
219        Ok(())
220    }
221
222    #[cfg(test)]
223    pub fn clear_contract_whitelist(
224        &mut self, address: &Address, substate: &mut Substate,
225    ) -> DbResult<()> {
226        storage_range_deletion_for_account(
227            self,
228            &SPONSOR_WHITELIST_CONTROL_CONTRACT_ADDRESS,
229            address.as_ref(),
230            substate,
231        )?;
232        Ok(())
233    }
234}
235
236#[inline]
237fn sponsor_address() -> AddressWithSpace {
238    SPONSOR_WHITELIST_CONTROL_CONTRACT_ADDRESS.with_native_space()
239}
240
241#[inline]
242fn sponsor_key(contract: &Address, user: &Address) -> Vec<u8> {
243    let mut key = Vec::with_capacity(Address::len_bytes() * 2);
244    key.extend_from_slice(contract.as_bytes());
245    key.extend_from_slice(user.as_bytes());
246    key
247}
248
249fn special_sponsor_key(contract: &Address) -> Vec<u8> {
250    let mut key = Vec::with_capacity(Address::len_bytes() * 2);
251    key.extend_from_slice(contract.as_bytes());
252    key.extend_from_slice(COMMISSION_PRIVILEGE_SPECIAL_KEY.as_bytes());
253    key
254}
255
256fn storage_range_deletion_for_account(
257    state: &mut State, address: &Address, key_prefix: &[u8],
258    substate: &mut Substate,
259) -> DbResult<()> {
260    let delete_all = key_prefix.is_empty();
261
262    let storage_key_prefix = if delete_all {
263        StorageKey::new_storage_root_key(&address)
264    } else {
265        StorageKey::new_storage_key(&address, key_prefix)
266    }
267    .with_native_space();
268    let db_deletion_log = state
269        .db
270        .delete_all::<access_mode::Read>(storage_key_prefix, None)?
271        .into_iter();
272    state
273        .write_native_account_lock(address)?
274        .delete_storage_range(db_deletion_log, key_prefix, substate)?;
275    Ok(())
276}