primitives/
account.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5use 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    /// This is the number of tokens in this deposit.
49    pub amount: U256,
50    /// This is the timestamp when this deposit happened, measured in the
51    /// number of past blocks. It will be used to calculate
52    /// the service charge.
53    pub deposit_time: U256,
54    /// This is the accumulated interest rate when this deposit happened.
55    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    /// This is the number of tokens should be locked before
73    /// `unlock_block_number`.
74    pub amount: U256,
75    /// This is the timestamp when the vote right will be invalid, measured in
76    /// the number of past blocks.
77    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            // Find first index whose `unlock_block_number` is greater than
135            // timestamp and all entries before the index could be
136            // ignored.
137            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            // Find first index whose `unlock_block_number` is greater than
156            // timestamp and all entries before the index could be
157            // removed.
158            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    /// This is the address of the sponsor for gas cost of the contract.
252    pub sponsor_for_gas: Address,
253    /// This is the address of the sponsor for collateral of the contract.
254    pub sponsor_for_collateral: Address,
255    /// This is the upper bound of sponsor gas cost per tx.
256    pub sponsor_gas_bound: U256,
257    /// This is the amount of tokens sponsor for gas cost to the contract.
258    pub sponsor_balance_for_gas: U256,
259    /// This is the amount of tokens sponsor for collateral to the contract.
260    pub sponsor_balance_for_collateral: U256,
261    /// This is the storage point introduced in CIP-107
262    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    /// This field is not part of Account data, but kept for convenience. It
324    /// should be rarely used except for debugging.
325    address_local_info: AddressWithSpace,
326    pub balance: U256,
327    pub nonce: U256,
328    pub code_hash: H256,
329    /// This is the number of tokens used in staking.
330    pub staking_balance: U256,
331    /// This is the number of tokens used as collateral for storage, which will
332    /// be returned to balance if the storage is released.
333    pub collateral_for_storage: U256,
334    /// This is the accumulated interest return.
335    pub accumulated_interest_return: U256,
336    /// This is the address of the administrator of the contract.
337    pub admin: Address,
338    /// This is the sponsor information of the contract.
339    pub sponsor_info: SponsorInfo,
340}
341
342/// Defined for Rlp serialization/deserialization.
343#[derive(RlpEncodable, RlpDecodable)]
344pub struct BasicAccount {
345    pub balance: U256,
346    pub nonce: U256,
347    /// This is the number of tokens used in staking.
348    pub staking_balance: U256,
349    /// This is the number of tokens used as collateral for storage, which will
350    /// be returned to balance if the storage is released.
351    pub collateral_for_storage: U256,
352    /// This is the accumulated interest return.
353    pub accumulated_interest_return: U256,
354}
355
356/// Defined for Rlp serialization/deserialization.
357#[derive(RlpEncodable, RlpDecodable)]
358pub struct ContractAccount {
359    pub balance: U256,
360    pub nonce: U256,
361    pub code_hash: H256,
362    /// This is the number of tokens used in staking.
363    pub staking_balance: U256,
364    /// This is the number of tokens used as collateral for storage, which will
365    /// be returned to balance if the storage is released.
366    pub collateral_for_storage: U256,
367    /// This is the accumulated interest return.
368    pub accumulated_interest_return: U256,
369    /// This is the address of the administrator of the contract.
370    pub admin: Address,
371    /// This is the sponsor information of the contract.
372    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        // After CIP-80, an address started by 0x8 is still stored as
518        // contract format in underlying db, even if it may be a normal address.
519        // In order to achieve backward compatible.
520        //
521        // It is impossible to have an all-zero hash value. But some previous
522        // bug make one of the genesis accounts has all zero genesis hash.
523        if self.code_hash != KECCAK_EMPTY && !self.code_hash.is_zero()
524            || self.address_local_info.address.is_contract_address()
525        {
526            // A contract address can hold balance before its initialization
527            // as a recipient of a simple transaction.
528            // So we always determine how to serialize by the address type bits.
529            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    // Original normal address
627    test_random_account(Some(0x10), false, false);
628    // Original contract address
629    test_random_account(Some(0x80), true, true);
630    // Uninitialized contract address && new normal address
631    test_random_account(Some(0x80), false, true);
632
633    // New normal address
634    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}