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