cfx_executor/state/state_object/
staking.rs1use super::{RequireFields, State};
2use crate::{
3 internal_contract::{
4 get_settled_param_vote_count, get_settled_pos_staking_for_votes,
5 settle_current_votes, storage_point_prop,
6 },
7 return_if, try_loaded,
8};
9use cfx_parameters::{
10 consensus::ONE_UCFX_IN_DRIP,
11 consensus_internal::MINING_REWARD_TANZANITE_IN_UCFX,
12};
13use cfx_statedb::{
14 global_params::{
15 AccumulateInterestRate, InterestRate, PowBaseReward, TotalStaking,
16 },
17 Result as DbResult,
18};
19use cfx_types::{Address, AddressSpaceUtil, U256};
20
21impl State {
24 pub fn staking_balance(&self, address: &Address) -> DbResult<U256> {
25 let acc = try_loaded!(self.read_native_account_lock(address));
26 Ok(*acc.staking_balance())
27 }
28
29 pub fn withdrawable_staking_balance(
30 &self, address: &Address, current_block_number: u64,
31 ) -> DbResult<U256> {
32 let acc = try_loaded!(self.read_account_ext_lock(
33 &address.with_native_space(),
34 RequireFields::VoteStakeList,
35 ));
36 Ok(acc.withdrawable_staking_balance(current_block_number))
37 }
38
39 pub fn locked_staking_balance_at_block_number(
40 &self, address: &Address, block_number: u64,
41 ) -> DbResult<U256> {
42 let acc = try_loaded!(self.read_account_ext_lock(
43 &address.with_native_space(),
44 RequireFields::VoteStakeList,
45 ));
46 Ok(acc.staking_balance()
47 - acc.withdrawable_staking_balance(block_number))
48 }
49
50 pub fn vote_stake_list_length(&self, address: &Address) -> DbResult<usize> {
51 let acc = try_loaded!(self.read_account_ext_lock(
52 &address.with_native_space(),
53 RequireFields::VoteStakeList
54 ));
55 Ok(acc.vote_stake_list().len())
56 }
57
58 pub fn vote_lock(
59 &mut self, address: &Address, amount: &U256, unlock_block_number: u64,
60 ) -> DbResult<()> {
61 return_if!(amount.is_zero());
62
63 self.write_account_ext_lock(
64 &address.with_native_space(),
65 RequireFields::VoteStakeList,
66 )?
67 .vote_lock(*amount, unlock_block_number);
68 Ok(())
69 }
70
71 pub fn remove_expired_vote_stake_info(
72 &mut self, address: &Address, current_block_number: u64,
73 ) -> DbResult<()> {
74 let mut account = self.write_native_account_lock(&address)?;
75 account.cache_ext_fields(false, true, &self.db)?;
76 account.remove_expired_vote_stake_info(current_block_number);
77 Ok(())
78 }
79
80 pub fn deposit_list_length(&self, address: &Address) -> DbResult<usize> {
81 let acc = try_loaded!(self.read_account_ext_lock(
82 &address.with_native_space(),
83 RequireFields::DepositList
84 ));
85 Ok(acc.deposit_list().len())
86 }
87
88 pub fn deposit(
89 &mut self, address: &Address, amount: &U256, current_block_number: u64,
90 cip_97: bool,
91 ) -> DbResult<()> {
92 return_if!(amount.is_zero());
93
94 let acc_interest_rate =
95 self.global_stat.get::<AccumulateInterestRate>();
96 self.write_account_ext_lock(
97 &address.with_native_space(),
98 RequireFields::DepositList,
99 )?
100 .deposit(
101 *amount,
102 acc_interest_rate,
103 current_block_number,
104 cip_97,
105 );
106 *self.global_stat.val::<TotalStaking>() += *amount;
107 Ok(())
108 }
109
110 pub fn withdraw(
111 &mut self, address: &Address, amount: &U256, cip_97: bool,
112 ) -> DbResult<U256> {
113 return_if!(amount.is_zero());
114
115 let accumulated_interest_rate =
116 self.global_stat.get::<AccumulateInterestRate>();
117 let interest = self
118 .write_account_ext_lock(
119 &address.with_native_space(),
120 RequireFields::DepositList,
121 )?
122 .withdraw(*amount, accumulated_interest_rate, cip_97);
123
124 self.add_total_issued(interest);
126 *self.global_stat.val::<TotalStaking>() -= *amount;
127 Ok(interest)
128 }
129}
130
131pub fn initialize_or_update_dao_voted_params(
132 state: &mut State, cip105: bool,
133) -> DbResult<()> {
134 let vote_count = get_settled_param_vote_count(state).expect("db error");
135 debug!(
136 "initialize_or_update_dao_voted_params: vote_count={:?}",
137 vote_count
138 );
139 debug!(
140 "before pos interest: {} base_reward:{}",
141 state.global_stat.refr::<InterestRate>(),
142 state.global_stat.refr::<PowBaseReward>(),
143 );
144
145 let pos_staking_for_votes = get_settled_pos_staking_for_votes(state)?;
149 *state.global_stat.val::<InterestRate>() =
152 vote_count.pos_reward_interest.compute_next_params(
153 state.global_stat.get::<InterestRate>(),
154 pos_staking_for_votes,
155 );
156
157 let pow_base_reward = state.global_stat.val::<PowBaseReward>();
159 if !pow_base_reward.is_zero() {
160 *pow_base_reward = vote_count
161 .pow_base_reward
162 .compute_next_params(*pow_base_reward, pos_staking_for_votes);
163 } else {
164 *pow_base_reward =
165 (MINING_REWARD_TANZANITE_IN_UCFX * ONE_UCFX_IN_DRIP).into();
166 }
167
168 let old_storage_point_prop =
172 state.get_system_storage(&storage_point_prop())?;
173 if !old_storage_point_prop.is_zero() {
174 debug!("old_storage_point_prop: {}", old_storage_point_prop);
175 state.set_system_storage(
176 storage_point_prop().to_vec(),
177 vote_count.storage_point_prop.compute_next_params(
178 old_storage_point_prop,
179 pos_staking_for_votes,
180 ),
181 )?;
182 }
183
184 let old_base_fee_prop = state.get_base_price_prop();
185 if !old_base_fee_prop.is_zero() {
186 state.set_base_fee_prop(
187 vote_count
188 .base_fee_prop
189 .compute_next_params(old_base_fee_prop, pos_staking_for_votes),
190 )
191 }
192 debug!(
193 "pos interest: {} base_reward: {}",
194 state.global_stat.refr::<InterestRate>(),
195 state.global_stat.refr::<PowBaseReward>()
196 );
197
198 settle_current_votes(state, cip105)?;
199
200 Ok(())
201}