1use cfx_bytes as bytes;
6use cfxkey as keylib;
7use log::{debug, info, trace};
8
9use crate::bytes::Bytes;
10use cfx_types::{
11 address_util::AddressUtil, cal_contract_address, Address, AddressSpaceUtil,
12 BigEndianHash, CreateContractAddressType, H256, H512, U256, U512,
13};
14use cfxcore::{
15 SharedConsensusGraph, SharedSynchronizationService, SharedTransactionPool,
16};
17use keylib::{public_to_address, Generator, KeyPair, Random, Secret};
18use lazy_static::lazy_static;
19use metrics::{register_meter_with_group, Meter};
20use parking_lot::RwLock;
21use primitives::{
22 transaction::{native_transaction::NativeTransaction, Action},
23 Account, SignedTransaction, Transaction,
24};
25use rand::{prelude::*, random_range};
26use rlp::Encodable;
27use rustc_hex::{FromHex, ToHex};
28use secret_store::SharedSecretStore;
29use std::{
30 cmp::Ordering,
31 collections::HashMap,
32 convert::TryFrom,
33 sync::Arc,
34 thread,
35 time::{self, Instant},
36};
37use time::Duration;
38
39lazy_static! {
40 static ref TX_GEN_METER: Arc<dyn Meter> =
41 register_meter_with_group("system_metrics", "tx_gen");
42}
43
44enum TransGenState {
45 Start,
46 Stop,
47}
48
49pub struct TransactionGeneratorConfig {
50 pub generate_tx: bool,
51 pub period: time::Duration,
52 pub account_count: usize,
53}
54
55impl TransactionGeneratorConfig {
56 pub fn new(
57 generate_tx: bool, period_ms: u64, account_count: usize,
58 ) -> Self {
59 TransactionGeneratorConfig {
60 generate_tx,
61 period: time::Duration::from_micros(period_ms),
62 account_count,
63 }
64 }
65}
66
67pub struct TransactionGenerator {
68 consensus: SharedConsensusGraph,
69 sync: SharedSynchronizationService,
70 txpool: SharedTransactionPool,
71 secret_store: SharedSecretStore,
72 state: RwLock<TransGenState>,
73 account_start_index: RwLock<Option<usize>>,
74 join_handle: RwLock<Option<thread::JoinHandle<()>>>,
75}
76
77pub type SharedTransactionGenerator = Arc<TransactionGenerator>;
78
79impl TransactionGenerator {
80 pub fn new(
82 consensus: SharedConsensusGraph, txpool: SharedTransactionPool,
83 sync: SharedSynchronizationService, secret_store: SharedSecretStore,
84 ) -> Self {
85 TransactionGenerator {
86 consensus,
87 txpool,
88 sync,
89 secret_store,
90 state: RwLock::new(TransGenState::Start),
91 account_start_index: RwLock::new(Option::None),
92 join_handle: RwLock::new(None),
93 }
94 }
95
96 pub fn stop(&self) {
97 *self.state.write() = TransGenState::Stop;
98 if let Some(join_handle) = self.join_handle.write().take() {
99 join_handle.join().ok();
100 }
101 }
102
103 pub fn set_genesis_accounts_start_index(&self, index: usize) {
104 let mut account_start = self.account_start_index.write();
105 *account_start = Some(index);
106 }
107
108 pub fn set_join_handle(&self, join_handle: thread::JoinHandle<()>) {
109 self.join_handle.write().replace(join_handle);
110 }
111
112 pub fn generate_transactions_with_multiple_genesis_accounts(
113 txgen: Arc<TransactionGenerator>,
114 tx_config: TransactionGeneratorConfig,
115 genesis_accounts: HashMap<Address, U256>,
116 ) {
117 loop {
118 let account_start = txgen.account_start_index.read();
119 if account_start.is_some() {
120 break;
121 }
122 }
123 let account_start_index = txgen.account_start_index.read().unwrap();
124 let mut nonce_map: HashMap<Address, U256> = HashMap::new();
125 let mut balance_map: HashMap<Address, U256> = HashMap::new();
126 let mut address_secret_pair: HashMap<Address, Secret> = HashMap::new();
127 let mut addresses: Vec<Address> = Vec::new();
128
129 debug!("Tx Generation Config {:?}", tx_config.generate_tx);
130
131 let mut tx_n = 0;
132 loop {
134 match *txgen.state.read() {
135 TransGenState::Stop => return,
136 _ => {}
137 }
138
139 if txgen.sync.catch_up_mode() {
141 thread::sleep(Duration::from_millis(100));
142 continue;
143 }
144 break;
145 }
146
147 debug!("Setup Usable Genesis Accounts");
148 for i in 0..tx_config.account_count {
149 let key_pair =
150 txgen.secret_store.get_keypair(account_start_index + i);
151 let address = key_pair.address();
152 let secret = key_pair.secret().clone();
153 addresses.push(address);
154 nonce_map.insert(address.clone(), 0.into());
155
156 let balance = genesis_accounts.get(&address).cloned();
157
158 balance_map
159 .insert(address.clone(), balance.unwrap_or(U256::zero()));
160 address_secret_pair.insert(address, secret);
161 }
162
163 info!("Start Generating Workload");
164 let start_time = Instant::now();
165 let account_count = address_secret_pair.len();
168 loop {
169 match *txgen.state.read() {
170 TransGenState::Stop => return,
171 _ => {}
172 }
173
174 let mut receiver_index: usize = random_range(0..usize::MAX);
177 receiver_index %= account_count;
178 let receiver_address = addresses[receiver_index];
179
180 let mut sender_index: usize = random_range(0..usize::MAX);
181 sender_index %= account_count;
182 let sender_address = addresses[sender_index];
183
184 let balance_to_transfer = U256::from(0);
186
187 let sender_nonce = nonce_map.get_mut(&sender_address).unwrap();
189
190 let (nonce, balance) = txgen
193 .txpool
194 .get_state_account_info(&sender_address.with_native_space())
195 .unwrap();
196 if nonce.cmp(sender_nonce) != Ordering::Equal {
197 *sender_nonce = nonce.clone();
198 balance_map.insert(sender_address.clone(), balance.clone());
199 }
200 trace!(
201 "receiver={:?} value={:?} nonce={:?}",
202 receiver_address,
203 balance_to_transfer,
204 sender_nonce
205 );
206 let tx: Transaction = NativeTransaction {
209 nonce: *sender_nonce,
210 gas_price: U256::from(1u64),
211 gas: U256::from(21000u64),
212 value: balance_to_transfer,
213 action: Action::Call(receiver_address),
214 storage_limit: 0,
215 chain_id: txgen.consensus.best_chain_id().in_native_space(),
216 epoch_height: txgen.consensus.best_epoch_number(),
217 data: Bytes::new(),
218 }
219 .into();
220
221 let signed_tx = tx.sign(&address_secret_pair[&sender_address]);
222 let mut tx_to_insert = Vec::new();
223 tx_to_insert.push(signed_tx.transaction);
224 let (txs, fail) =
225 txgen.txpool.insert_new_transactions(tx_to_insert);
226 if fail.is_empty() {
227 txgen.sync.append_received_transactions(txs);
228 {
232 let sender_balance =
233 balance_map.get_mut(&sender_address).unwrap();
234 *sender_balance -= balance_to_transfer + 21000;
235 if *sender_balance < 42000.into() {
236 addresses.remove(sender_index);
237 if addresses.is_empty() {
238 break;
239 }
240 }
241 }
242 *sender_nonce += U256::one();
243 *balance_map.entry(receiver_address).or_insert(0.into()) +=
244 balance_to_transfer;
245 tx_n += 1;
246 TX_GEN_METER.mark(1);
247 } else {
248 thread::sleep(tx_config.period);
253 }
254
255 let now = Instant::now();
256 let time_elapsed = now.duration_since(start_time);
257 if let Some(time_left) =
258 (tx_config.period * tx_n).checked_sub(time_elapsed)
259 {
260 thread::sleep(time_left);
261 } else {
262 debug!(
263 "Elapsed time larger than the time needed for sleep: \
264 time_elapsed={:?} tx_n={}",
265 time_elapsed, tx_n
266 );
267 }
268 }
269 }
270}
271
272pub struct DirectTransactionGenerator {
275 accounts: HashMap<Address, (KeyPair, Account, U256)>,
277 address_by_index: Vec<Address>,
278 erc20_address: Address,
279}
280
281#[allow(deprecated)]
282impl DirectTransactionGenerator {
283 const MAX_TOTAL_ACCOUNTS: usize = 100_000;
284
285 pub fn new(
286 start_key_pair: KeyPair, contract_creator: &Address,
287 start_balance: U256, start_erc20_balance: U256,
288 ) -> DirectTransactionGenerator {
289 let start_address = public_to_address(start_key_pair.public(), true);
290 let info = (
291 start_key_pair,
292 Account::new_empty_with_balance(
293 &start_address.with_native_space(),
294 &start_balance,
295 &0.into(), ),
297 start_erc20_balance,
298 );
299 let mut accounts = HashMap::<Address, (KeyPair, Account, U256)>::new();
300 accounts.insert(start_address.clone(), info);
301 let address_by_index = vec![start_address.clone()];
302
303 let mut erc20_address = cal_contract_address(
304 CreateContractAddressType::FromSenderNonceAndCodeHash,
305 &contract_creator,
308 &0.into(),
309 &[],
311 )
312 .0;
313 erc20_address.set_contract_type_bits();
314
315 debug!(
316 "Special Transaction Generator: erc20 contract address: {:?}",
317 erc20_address
318 );
319
320 DirectTransactionGenerator {
321 accounts,
322 address_by_index,
323 erc20_address,
324 }
325 }
326
327 pub fn generate_transactions(
328 &mut self, block_size_limit: &mut usize, mut num_txs_simple: usize,
329 mut num_txs_erc20: usize, chain_id: u32,
330 ) -> Vec<Arc<SignedTransaction>> {
331 let mut result = vec![];
332 while num_txs_simple > 0 {
334 let number_of_accounts = self.address_by_index.len();
335
336 let sender_index: usize = random_range(0..number_of_accounts);
337 let sender_address =
338 self.address_by_index.get(sender_index).unwrap().clone();
339 let sender_kp;
340 let sender_balance;
341 let sender_nonce;
342 {
343 let sender_info = self.accounts.get(&sender_address).unwrap();
344 sender_kp = sender_info.0.clone();
345 sender_balance = sender_info.1.balance;
346 sender_nonce = sender_info.1.nonce;
347 }
348
349 let gas = U256::from(100_000u64);
350 let gas_price = U256::from(1u64);
351 let transaction_fee = U256::from(100_000u64);
352
353 if sender_balance <= transaction_fee {
354 self.accounts.remove(&sender_address);
355 self.address_by_index.swap_remove(sender_index);
356 continue;
357 }
358
359 let balance_to_transfer = U256::try_from(
360 H512::random().into_uint() % U512::from(sender_balance),
361 )
362 .unwrap();
363
364 let is_send_to_new_address = (number_of_accounts
365 <= Self::MAX_TOTAL_ACCOUNTS)
366 && ((number_of_accounts < 10)
367 || (rand::thread_rng().random_range(0..10) == 0));
368
369 let receiver_address = match is_send_to_new_address {
370 false => {
371 let index: usize = random_range(0..number_of_accounts);
372 self.address_by_index.get(index).unwrap().clone()
373 }
374 true => loop {
375 let kp =
376 Random.generate().expect("Fail to generate KeyPair.");
377 let address = public_to_address(kp.public(), true);
378 if self.accounts.get(&address).is_none() {
379 self.accounts.insert(
380 address,
381 (
382 kp,
383 Account::new_empty_with_balance(
384 &address.with_native_space(),
385 &0.into(), &0.into(), ),
388 0.into(),
389 ),
390 );
391 self.address_by_index.push(address.clone());
392
393 break address;
394 }
395 },
396 };
397
398 let tx: Transaction = NativeTransaction {
399 nonce: sender_nonce,
400 gas_price,
401 gas,
402 value: balance_to_transfer,
403 action: Action::Call(receiver_address),
404 storage_limit: 0,
405 epoch_height: 0,
409 chain_id,
410 data: vec![0u8; 128],
411 }
412 .into();
413 let signed_transaction = tx.sign(sender_kp.secret());
414 let rlp_size = signed_transaction.transaction.rlp_bytes().len();
415 if *block_size_limit <= rlp_size {
416 break;
417 }
418 *block_size_limit -= rlp_size;
419
420 self.accounts.get_mut(&sender_address).unwrap().1.balance -=
421 balance_to_transfer;
422 self.accounts.get_mut(&sender_address).unwrap().1.nonce += 1.into();
423 self.accounts.get_mut(&receiver_address).unwrap().1.balance +=
424 balance_to_transfer;
425
426 result.push(Arc::new(signed_transaction));
427
428 num_txs_simple -= 1;
429 }
430
431 while num_txs_erc20 > 0 {
432 let number_of_accounts = self.address_by_index.len();
433
434 let sender_index: usize = random_range(0..number_of_accounts);
435 let sender_address =
436 self.address_by_index.get(sender_index).unwrap().clone();
437 let sender_kp;
438 let sender_balance;
439 let sender_erc20_balance;
440 let sender_nonce;
441 {
442 let sender_info = self.accounts.get(&sender_address).unwrap();
443 sender_kp = sender_info.0.clone();
444 sender_balance = sender_info.1.balance;
445 sender_erc20_balance = sender_info.2.clone();
446 sender_nonce = sender_info.1.nonce;
447 }
448
449 let gas = U256::from(100_000u64);
450 let gas_price = U256::from(1u64);
451 let transaction_fee = U256::from(100_000u64);
452
453 if sender_balance <= transaction_fee {
454 self.accounts.remove(&sender_address);
455 self.address_by_index.swap_remove(sender_index);
456 continue;
457 }
458
459 let balance_to_transfer = if sender_erc20_balance == 0.into() {
460 continue;
461 } else {
462 U256::try_from(
463 H512::random().into_uint()
464 % U512::from(sender_erc20_balance),
465 )
466 .unwrap()
467 };
468
469 let receiver_index = random_range(0..number_of_accounts);
470 let receiver_address =
471 self.address_by_index.get(receiver_index).unwrap().clone();
472
473 if receiver_index == sender_index {
474 continue;
475 }
476
477 let tx_data = (String::new()
479 + "a9059cbb000000000000000000000000"
480 + &receiver_address.0.to_hex::<String>()[2..]
481 + {
482 let h: H256 =
483 BigEndianHash::from_uint(&balance_to_transfer);
484 &h.0.to_hex::<String>()[2..]
485 })
486 .from_hex()
487 .unwrap();
488
489 let tx: Transaction = NativeTransaction {
490 nonce: sender_nonce,
491 gas_price,
492 gas,
493 value: 0.into(),
494 action: Action::Call(self.erc20_address.clone()),
495 storage_limit: 0,
496 epoch_height: 0,
500 chain_id,
501 data: tx_data,
502 }
503 .into();
504 let signed_transaction = tx.sign(sender_kp.secret());
505 let rlp_size = signed_transaction.transaction.rlp_bytes().len();
506 if *block_size_limit <= rlp_size {
507 break;
508 }
509 *block_size_limit -= rlp_size;
510
511 self.accounts.get_mut(&sender_address).unwrap().2 -=
512 balance_to_transfer;
513 self.accounts.get_mut(&sender_address).unwrap().1.nonce += 1.into();
514 self.accounts.get_mut(&receiver_address).unwrap().2 +=
515 balance_to_transfer;
516
517 result.push(Arc::new(signed_transaction));
518
519 num_txs_erc20 -= 1;
520 }
521
522 result
523 }
524}