1use cfx_types::{Address, AddressWithSpace};
6
7use primitives::{
8 receipt::{SortedStorageChanges, StorageChange},
9 LogEntry,
10};
11use std::collections::{HashMap, HashSet};
12
13#[derive(Debug, Default)]
17pub struct Substate {
18 pub suicides: HashSet<AddressWithSpace>,
20 pub storage_collateralized: HashMap<Address, u64>,
22 pub storage_released: HashMap<Address, u64>,
24 pub logs: Vec<LogEntry>,
26 pub refund_gas: i128,
28 contracts_created: Vec<AddressWithSpace>,
30}
31
32impl Substate {
33 pub fn accrue(&mut self, s: Self) {
34 self.suicides.extend(s.suicides);
35 self.logs.extend(s.logs);
36 self.contracts_created.extend(s.contracts_created);
37 for (address, amount) in s.storage_collateralized {
38 *self.storage_collateralized.entry(address).or_insert(0) += amount;
39 }
40 for (address, amount) in s.storage_released {
41 *self.storage_released.entry(address).or_insert(0) += amount;
42 }
43 self.refund_gas += s.refund_gas;
44 }
45
46 pub fn new() -> Self { Substate::default() }
47}
48
49impl Substate {
50 pub fn get_collateral_change(&self, address: &Address) -> (u64, u64) {
51 let inc = self
52 .storage_collateralized
53 .get(address)
54 .cloned()
55 .unwrap_or(0);
56 let sub = self.storage_released.get(address).cloned().unwrap_or(0);
57 if inc > sub {
58 (inc - sub, 0)
59 } else {
60 (0, sub - inc)
61 }
62 }
63
64 pub fn compute_storage_changes(&self) -> SortedStorageChanges {
65 let mut storage_collateralized = vec![];
66 let mut storage_released = vec![];
67
68 let mut affected_address: Vec<_> =
69 self.keys_for_collateral_changed().iter().cloned().collect();
70 affected_address.sort();
71 for address in affected_address {
72 let (inc, sub) = self.get_collateral_change(&address);
73 if inc > 0 {
74 storage_collateralized.push(StorageChange {
75 address: *address,
76 collaterals: inc.into(),
77 });
78 } else if sub > 0 {
79 storage_released.push(StorageChange {
80 address: *address,
81 collaterals: sub.into(),
82 });
83 }
84 }
85 SortedStorageChanges {
86 storage_collateralized,
87 storage_released,
88 }
89 }
90
91 pub fn contracts_created(&self) -> &Vec<AddressWithSpace> {
92 &self.contracts_created
93 }
94
95 pub fn record_contract_create(&mut self, address: AddressWithSpace) {
96 self.contracts_created.push(address);
97 }
98
99 pub fn record_storage_occupy(
100 &mut self, address: &Address, collaterals: u64,
101 ) {
102 *self.storage_collateralized.entry(*address).or_insert(0) +=
103 collaterals;
104 }
105
106 pub fn record_storage_release(
107 &mut self, address: &Address, collaterals: u64,
108 ) {
109 *self.storage_released.entry(*address).or_insert(0) += collaterals;
110 }
111
112 pub fn keys_for_collateral_changed(&self) -> HashSet<&Address> {
113 let affected_address1: HashSet<_> =
114 self.storage_collateralized.keys().collect();
115 let affected_address2: HashSet<_> =
116 self.storage_released.keys().collect();
117 affected_address1
118 .union(&affected_address2)
119 .cloned()
120 .collect()
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::Substate;
127 use cfx_types::{Address, AddressSpaceUtil, Space};
128 use primitives::LogEntry;
129
130 #[test]
131 fn created() {
132 let sub_state = Substate::new();
133 assert_eq!(sub_state.suicides.len(), 0);
134 }
135
136 #[test]
137 fn accrue() {
138 let mut sub_state = Substate::new();
139 sub_state
140 .contracts_created
141 .push(Address::from_low_u64_be(1).with_native_space());
142 sub_state.logs.push(LogEntry {
143 address: Address::from_low_u64_be(1),
144 topics: vec![],
145 data: vec![],
146 space: Space::Native,
147 });
148 sub_state
149 .suicides
150 .insert(Address::from_low_u64_be(10).with_native_space());
151
152 let mut sub_state_2 = Substate::new();
153 sub_state_2
154 .contracts_created
155 .push(Address::from_low_u64_be(2).with_native_space());
156 sub_state_2.logs.push(LogEntry {
157 address: Address::from_low_u64_be(1),
158 topics: vec![],
159 data: vec![],
160 space: Space::Native,
161 });
162
163 sub_state.accrue(sub_state_2);
164 assert_eq!(sub_state.contracts_created.len(), 2);
165 assert_eq!(sub_state.suicides.len(), 1);
166 }
167}