1use crate::{bytes::Bytes, hash::KECCAK_EMPTY};
6use cfx_types::{
7 address_util::AddressUtil, Address, AddressSpaceUtil, AddressWithSpace,
8 Space, H256, U256,
9};
10use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream};
11use rlp_derive::{RlpDecodable, RlpEncodable};
12use serde_derive::{Deserialize, Serialize};
13
14use std::{
15 fmt,
16 ops::{Deref, DerefMut},
17 sync::Arc,
18};
19
20#[derive(Debug, PartialEq, Clone)]
21pub enum AddressSpace {
22 Builtin,
23 User,
24 Contract,
25}
26
27#[derive(Debug, PartialEq, Clone)]
28pub enum AccountError {
29 ReservedAddressSpace(Address),
30 AddressSpaceMismatch(Address, AddressSpace),
31 InvalidRlp(DecoderError),
32}
33
34#[derive(
35 Clone,
36 Debug,
37 RlpDecodable,
38 RlpEncodable,
39 Ord,
40 PartialOrd,
41 Eq,
42 PartialEq,
43 Serialize,
44 Deserialize,
45)]
46#[serde(rename_all = "camelCase")]
47pub struct DepositInfo {
48 pub amount: U256,
50 pub deposit_time: U256,
54 pub accumulated_interest_rate: U256,
56}
57
58#[derive(
59 Clone,
60 Debug,
61 RlpDecodable,
62 RlpEncodable,
63 Ord,
64 PartialOrd,
65 Eq,
66 PartialEq,
67 Serialize,
68 Deserialize,
69)]
70#[serde(rename_all = "camelCase")]
71pub struct VoteStakeInfo {
72 pub amount: U256,
75 pub unlock_block_number: U256,
78}
79
80#[derive(Clone, Debug, Default, Ord, PartialOrd, Eq, PartialEq)]
81pub struct DepositList(pub Vec<DepositInfo>);
82
83impl Encodable for DepositList {
84 fn rlp_append(&self, s: &mut RlpStream) { s.append_list(&self.0); }
85}
86
87impl Decodable for DepositList {
88 fn decode(d: &Rlp) -> Result<Self, DecoderError> {
89 let deposit_vec = d.as_list()?;
90 Ok(DepositList(deposit_vec))
91 }
92}
93
94impl Deref for DepositList {
95 type Target = Vec<DepositInfo>;
96
97 fn deref(&self) -> &Self::Target { &self.0 }
98}
99
100impl DerefMut for DepositList {
101 fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
102}
103
104#[derive(Clone, Debug, Default, Ord, PartialOrd, Eq, PartialEq)]
105pub struct VoteStakeList(pub Vec<VoteStakeInfo>);
106
107impl Encodable for VoteStakeList {
108 fn rlp_append(&self, s: &mut RlpStream) { s.append_list(&self.0); }
109}
110
111impl Decodable for VoteStakeList {
112 fn decode(d: &Rlp) -> Result<Self, DecoderError> {
113 let vote_vec = d.as_list()?;
114 Ok(VoteStakeList(vote_vec))
115 }
116}
117
118impl Deref for VoteStakeList {
119 type Target = Vec<VoteStakeInfo>;
120
121 fn deref(&self) -> &Self::Target { &self.0 }
122}
123
124impl DerefMut for VoteStakeList {
125 fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
126}
127
128impl VoteStakeList {
129 pub fn withdrawable_staking_balance(
130 &self, staking_balance: U256, block_number: u64,
131 ) -> U256 {
132 let block_number: U256 = block_number.into();
133 if !self.is_empty() {
134 let idx = self
138 .binary_search_by(|vote_info| {
139 vote_info.unlock_block_number.cmp(&(block_number + 1))
140 })
141 .unwrap_or_else(|x| x);
142 if idx == self.len() {
143 staking_balance
144 } else {
145 staking_balance - self[idx].amount
146 }
147 } else {
148 staking_balance
149 }
150 }
151
152 pub fn remove_expired_vote_stake_info(&mut self, block_number: u64) {
153 let block_number: U256 = block_number.into();
154 if !self.is_empty() && self[0].unlock_block_number <= block_number {
155 let idx = self
159 .binary_search_by(|vote_info| {
160 vote_info.unlock_block_number.cmp(&(block_number + 1))
161 })
162 .unwrap_or_else(|x| x);
163 self.0 = self.split_off(idx)
164 }
165 }
166
167 pub fn vote_lock(&mut self, amount: U256, unlock_block_number: u64) {
168 let unlock_block_number: U256 = unlock_block_number.into();
169 let mut updated = false;
170 let mut updated_index = 0;
171 match self.binary_search_by(|vote_info| {
172 vote_info.unlock_block_number.cmp(&unlock_block_number)
173 }) {
174 Ok(index) => {
175 if amount > self[index].amount {
176 self[index].amount = amount;
177 updated = true;
178 updated_index = index;
179 }
180 }
181 Err(index) => {
182 if index >= self.len() || self[index].amount < amount {
183 self.insert(
184 index,
185 VoteStakeInfo {
186 amount,
187 unlock_block_number,
188 },
189 );
190 updated = true;
191 updated_index = index;
192 }
193 }
194 }
195 if updated {
196 let rest = self.split_off(updated_index);
197 while !self.is_empty()
198 && self.last().unwrap().amount <= rest[0].amount
199 {
200 self.pop();
201 }
202 self.extend_from_slice(&rest);
203 }
204 }
205}
206
207#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
208pub struct CodeInfo {
209 pub code: Arc<Bytes>,
210 pub owner: Address,
211}
212
213impl CodeInfo {
214 #[inline]
215 pub fn code_size(&self) -> usize { self.code.len() }
216}
217
218impl Encodable for CodeInfo {
219 fn rlp_append(&self, stream: &mut RlpStream) {
220 stream.begin_list(2).append(&*self.code).append(&self.owner);
221 }
222}
223
224impl Decodable for CodeInfo {
225 fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
226 Ok(Self {
227 code: Arc::new(rlp.val_at(0)?),
228 owner: rlp.val_at(1)?,
229 })
230 }
231}
232
233#[derive(
234 Clone,
235 Debug,
236 Ord,
237 PartialOrd,
238 Eq,
239 PartialEq,
240 Default,
241 RlpDecodable,
242 RlpEncodable,
243)]
244pub struct StoragePoints {
245 pub unused: U256,
246 pub used: U256,
247}
248
249#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Default)]
250pub struct SponsorInfo {
251 pub sponsor_for_gas: Address,
253 pub sponsor_for_collateral: Address,
255 pub sponsor_gas_bound: U256,
257 pub sponsor_balance_for_gas: U256,
259 pub sponsor_balance_for_collateral: U256,
261 pub storage_points: Option<StoragePoints>,
263}
264
265impl SponsorInfo {
266 pub fn unused_storage_points(&self) -> U256 {
267 self.storage_points
268 .as_ref()
269 .map_or(U256::zero(), |x| x.unused)
270 }
271}
272
273impl Encodable for SponsorInfo {
274 fn rlp_append(&self, s: &mut RlpStream) {
275 match &self.storage_points {
276 None => {
277 s.begin_list(5);
278 s.append(&self.sponsor_for_gas);
279 s.append(&self.sponsor_for_collateral);
280 s.append(&self.sponsor_gas_bound);
281 s.append(&self.sponsor_balance_for_gas);
282 s.append(&self.sponsor_balance_for_collateral);
283 }
284 Some(points) => {
285 s.begin_list(6);
286 s.append(&self.sponsor_for_gas);
287 s.append(&self.sponsor_for_collateral);
288 s.append(&self.sponsor_gas_bound);
289 s.append(&self.sponsor_balance_for_gas);
290 s.append(&self.sponsor_balance_for_collateral);
291 s.append(points);
292 }
293 }
294 }
295}
296
297impl Decodable for SponsorInfo {
298 fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
299 match rlp.item_count()? {
300 5 => Ok(SponsorInfo {
301 sponsor_for_gas: rlp.val_at(0)?,
302 sponsor_for_collateral: rlp.val_at(1)?,
303 sponsor_gas_bound: rlp.val_at(2)?,
304 sponsor_balance_for_gas: rlp.val_at(3)?,
305 sponsor_balance_for_collateral: rlp.val_at(4)?,
306 storage_points: None,
307 }),
308 6 => Ok(SponsorInfo {
309 sponsor_for_gas: rlp.val_at(0)?,
310 sponsor_for_collateral: rlp.val_at(1)?,
311 sponsor_gas_bound: rlp.val_at(2)?,
312 sponsor_balance_for_gas: rlp.val_at(3)?,
313 sponsor_balance_for_collateral: rlp.val_at(4)?,
314 storage_points: Some(rlp.val_at(5)?),
315 }),
316 _ => Err(DecoderError::RlpInvalidLength),
317 }
318 }
319}
320
321#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
322pub struct Account {
323 address_local_info: AddressWithSpace,
326 pub balance: U256,
327 pub nonce: U256,
328 pub code_hash: H256,
329 pub staking_balance: U256,
331 pub collateral_for_storage: U256,
334 pub accumulated_interest_return: U256,
336 pub admin: Address,
338 pub sponsor_info: SponsorInfo,
340}
341
342#[derive(RlpEncodable, RlpDecodable)]
344pub struct BasicAccount {
345 pub balance: U256,
346 pub nonce: U256,
347 pub staking_balance: U256,
349 pub collateral_for_storage: U256,
352 pub accumulated_interest_return: U256,
354}
355
356#[derive(RlpEncodable, RlpDecodable)]
358pub struct ContractAccount {
359 pub balance: U256,
360 pub nonce: U256,
361 pub code_hash: H256,
362 pub staking_balance: U256,
364 pub collateral_for_storage: U256,
367 pub accumulated_interest_return: U256,
369 pub admin: Address,
371 pub sponsor_info: SponsorInfo,
373}
374
375#[derive(RlpEncodable, RlpDecodable)]
376pub struct EthereumAccount {
377 pub balance: U256,
378 pub nonce: U256,
379 pub code_hash: H256,
380}
381
382impl Account {
383 pub fn address(&self) -> &AddressWithSpace { &self.address_local_info }
384
385 pub fn set_address(&mut self, address: AddressWithSpace) {
386 self.address_local_info = address;
387 }
388
389 pub fn new_empty(address: &AddressWithSpace) -> Account {
390 Self::new_empty_with_balance(address, &U256::from(0), &U256::from(0))
391 }
392
393 pub fn new_empty_with_balance(
394 address: &AddressWithSpace, balance: &U256, nonce: &U256,
395 ) -> Account {
396 Self {
397 address_local_info: *address,
398 balance: *balance,
399 nonce: *nonce,
400 code_hash: KECCAK_EMPTY,
401 staking_balance: 0.into(),
402 collateral_for_storage: 0.into(),
403 accumulated_interest_return: 0.into(),
404 admin: Address::zero(),
405 sponsor_info: Default::default(),
406 }
407 }
408
409 fn from_basic_account(address: Address, a: BasicAccount) -> Self {
410 Self {
411 address_local_info: address.with_native_space(),
412 balance: a.balance,
413 nonce: a.nonce,
414 code_hash: KECCAK_EMPTY,
415 staking_balance: a.staking_balance,
416 collateral_for_storage: a.collateral_for_storage,
417 accumulated_interest_return: a.accumulated_interest_return,
418 admin: Address::zero(),
419 sponsor_info: Default::default(),
420 }
421 }
422
423 pub fn from_contract_account(address: Address, a: ContractAccount) -> Self {
424 Self {
425 address_local_info: address.with_native_space(),
426 balance: a.balance,
427 nonce: a.nonce,
428 code_hash: a.code_hash,
429 staking_balance: a.staking_balance,
430 collateral_for_storage: a.collateral_for_storage,
431 accumulated_interest_return: a.accumulated_interest_return,
432 admin: a.admin,
433 sponsor_info: a.sponsor_info,
434 }
435 }
436
437 fn from_ethereum_account(address: Address, a: EthereumAccount) -> Self {
438 let address = address.with_evm_space();
439 Self {
440 address_local_info: address,
441 balance: a.balance,
442 nonce: a.nonce,
443 code_hash: a.code_hash,
444 ..Self::new_empty(&address)
445 }
446 }
447
448 pub fn to_basic_account(&self) -> BasicAccount {
449 assert_eq!(self.address_local_info.space, Space::Native);
450 BasicAccount {
451 balance: self.balance,
452 nonce: self.nonce,
453 staking_balance: self.staking_balance,
454 collateral_for_storage: self.collateral_for_storage,
455 accumulated_interest_return: self.accumulated_interest_return,
456 }
457 }
458
459 pub fn to_contract_account(&self) -> ContractAccount {
460 assert_eq!(self.address_local_info.space, Space::Native);
461 ContractAccount {
462 balance: self.balance,
463 nonce: self.nonce,
464 code_hash: self.code_hash,
465 staking_balance: self.staking_balance,
466 collateral_for_storage: self.collateral_for_storage,
467 accumulated_interest_return: self.accumulated_interest_return,
468 admin: self.admin,
469 sponsor_info: self.sponsor_info.clone(),
470 }
471 }
472
473 pub fn to_evm_account(&self) -> EthereumAccount {
474 assert_eq!(self.address_local_info.space, Space::Ethereum);
475 assert!(self.staking_balance.is_zero());
476 assert!(self.collateral_for_storage.is_zero());
477 assert!(self.accumulated_interest_return.is_zero());
478 assert!(self.admin.is_zero());
479 assert_eq!(self.sponsor_info, Default::default());
480 EthereumAccount {
481 balance: self.balance,
482 nonce: self.nonce,
483 code_hash: self.code_hash,
484 }
485 }
486
487 pub fn new_from_rlp(
488 address: Address, rlp: &Rlp,
489 ) -> Result<Self, AccountError> {
490 let account = match rlp.item_count()? {
491 8 => Self::from_contract_account(
492 address,
493 ContractAccount::decode(rlp)?,
494 ),
495 5 => Self::from_basic_account(address, BasicAccount::decode(rlp)?),
496 3 => Self::from_ethereum_account(
497 address,
498 EthereumAccount::decode(rlp)?,
499 ),
500 _ => {
501 return Err(AccountError::InvalidRlp(
502 DecoderError::RlpIncorrectListLen,
503 ));
504 }
505 };
506 Ok(account)
507 }
508}
509
510impl Encodable for Account {
511 fn rlp_append(&self, stream: &mut RlpStream) {
512 if self.address_local_info.space == Space::Ethereum {
513 stream.append_internal(&self.to_evm_account());
514 return;
515 }
516
517 if self.code_hash != KECCAK_EMPTY && !self.code_hash.is_zero()
524 || self.address_local_info.address.is_contract_address()
525 {
526 stream.append_internal(&self.to_contract_account());
530 } else {
531 stream.append_internal(&self.to_basic_account());
532 }
533 }
534}
535
536impl From<DecoderError> for AccountError {
537 fn from(err: DecoderError) -> Self { AccountError::InvalidRlp(err) }
538}
539
540impl fmt::Display for AccountError {
541 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
542 let msg = match self {
543 AccountError::ReservedAddressSpace(address) => {
544 format!("Address space is reserved for {:?}", address)
545 }
546 AccountError::AddressSpaceMismatch(address, address_space) => {
547 format!(
548 "Address {:?} not in address space {:?}",
549 address, address_space
550 )
551 }
552 AccountError::InvalidRlp(err) => {
553 format!("Transaction has invalid RLP structure: {}.", err)
554 }
555 };
556
557 f.write_fmt(format_args!("Account error ({})", msg))
558 }
559}
560
561impl std::error::Error for AccountError {
562 fn description(&self) -> &str { "Account error" }
563}
564
565#[cfg(test)]
566fn test_random_account(
567 type_bit: Option<u8>, non_empty_hash: bool, contract_type: bool,
568) {
569 let mut address = Address::random();
570 address.set_address_type_bits(type_bit.unwrap_or(0x40));
571
572 let admin = Address::random();
573 let sponsor_info = SponsorInfo {
574 sponsor_for_gas: Address::random(),
575 sponsor_for_collateral: Address::random(),
576 sponsor_balance_for_gas: U256::from(123),
577 sponsor_balance_for_collateral: U256::from(124),
578 sponsor_gas_bound: U256::from(2),
579 storage_points: None,
580 };
581
582 let code_hash = if non_empty_hash {
583 H256::random()
584 } else {
585 KECCAK_EMPTY
586 };
587
588 let account = if contract_type {
589 Account::from_contract_account(
590 address,
591 ContractAccount {
592 balance: 1000.into(),
593 nonce: 123.into(),
594 code_hash,
595 staking_balance: 10000000.into(),
596 collateral_for_storage: 23.into(),
597 accumulated_interest_return: 456.into(),
598 admin,
599 sponsor_info,
600 },
601 )
602 } else {
603 Account::from_basic_account(
604 address,
605 BasicAccount {
606 balance: 1000.into(),
607 nonce: 123.into(),
608 staking_balance: 10000000.into(),
609 collateral_for_storage: 23.into(),
610 accumulated_interest_return: 456.into(),
611 },
612 )
613 };
614 assert_eq!(
615 account,
616 Account::new_from_rlp(
617 account.address_local_info.address,
618 &Rlp::new(&account.rlp_bytes()),
619 )
620 .unwrap()
621 );
622}
623
624#[test]
625fn test_account_serde() {
626 test_random_account(Some(0x10), false, false);
628 test_random_account(Some(0x80), true, true);
630 test_random_account(Some(0x80), false, true);
632
633 test_random_account(None, false, false);
635 test_random_account(Some(0x80), false, false);
636
637 test_random_account(None, true, true);
638 test_random_account(Some(0x80), true, true);
639}