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 if let TransGenState::Stop = *txgen.state.read() {
135 return;
136 }
137
138 if txgen.sync.catch_up_mode() {
140 thread::sleep(Duration::from_millis(100));
141 continue;
142 }
143 break;
144 }
145
146 debug!("Setup Usable Genesis Accounts");
147 for i in 0..tx_config.account_count {
148 let key_pair =
149 txgen.secret_store.get_keypair(account_start_index + i);
150 let address = key_pair.address();
151 let secret = key_pair.secret().clone();
152 addresses.push(address);
153 nonce_map.insert(address, 0.into());
154
155 let balance = genesis_accounts.get(&address).cloned();
156
157 balance_map.insert(address, balance.unwrap_or(U256::zero()));
158 address_secret_pair.insert(address, secret);
159 }
160
161 info!("Start Generating Workload");
162 let start_time = Instant::now();
163 let account_count = address_secret_pair.len();
166 loop {
167 if let TransGenState::Stop = *txgen.state.read() {
168 return;
169 }
170
171 let mut receiver_index: usize = random_range(0..usize::MAX);
174 receiver_index %= account_count;
175 let receiver_address = addresses[receiver_index];
176
177 let mut sender_index: usize = random_range(0..usize::MAX);
178 sender_index %= account_count;
179 let sender_address = addresses[sender_index];
180
181 let balance_to_transfer = U256::from(0);
183
184 let sender_nonce = nonce_map.get_mut(&sender_address).unwrap();
186
187 let (nonce, balance) = txgen
190 .txpool
191 .get_state_account_info(&sender_address.with_native_space())
192 .unwrap();
193 if nonce.cmp(sender_nonce) != Ordering::Equal {
194 *sender_nonce = nonce;
195 balance_map.insert(sender_address, balance);
196 }
197 trace!(
198 "receiver={:?} value={:?} nonce={:?}",
199 receiver_address,
200 balance_to_transfer,
201 sender_nonce
202 );
203 let tx: Transaction = NativeTransaction {
206 nonce: *sender_nonce,
207 gas_price: U256::from(1u64),
208 gas: U256::from(21000u64),
209 value: balance_to_transfer,
210 action: Action::Call(receiver_address),
211 storage_limit: 0,
212 chain_id: txgen.consensus.best_chain_id().in_native_space(),
213 epoch_height: txgen.consensus.best_epoch_number(),
214 data: Bytes::new(),
215 }
216 .into();
217
218 let signed_tx = tx.sign(&address_secret_pair[&sender_address]);
219 let tx_to_insert = vec![signed_tx.transaction];
220 let (txs, fail) =
221 txgen.txpool.insert_new_transactions(tx_to_insert);
222 if fail.is_empty() {
223 txgen.sync.append_received_transactions(txs);
224 {
228 let sender_balance =
229 balance_map.get_mut(&sender_address).unwrap();
230 *sender_balance -= balance_to_transfer + 21000;
231 if *sender_balance < 42000.into() {
232 addresses.remove(sender_index);
233 if addresses.is_empty() {
234 break;
235 }
236 }
237 }
238 *sender_nonce += U256::one();
239 *balance_map.entry(receiver_address).or_insert(0.into()) +=
240 balance_to_transfer;
241 tx_n += 1;
242 TX_GEN_METER.mark(1);
243 } else {
244 thread::sleep(tx_config.period);
249 }
250
251 let now = Instant::now();
252 let time_elapsed = now.duration_since(start_time);
253 if let Some(time_left) =
254 (tx_config.period * tx_n).checked_sub(time_elapsed)
255 {
256 thread::sleep(time_left);
257 } else {
258 debug!(
259 "Elapsed time larger than the time needed for sleep: \
260 time_elapsed={:?} tx_n={}",
261 time_elapsed, tx_n
262 );
263 }
264 }
265 }
266}
267
268pub struct DirectTransactionGenerator {
271 accounts: HashMap<Address, (KeyPair, Account, U256)>,
273 address_by_index: Vec<Address>,
274 erc20_address: Address,
275}
276
277#[allow(deprecated)]
278impl DirectTransactionGenerator {
279 const MAX_TOTAL_ACCOUNTS: usize = 100_000;
280
281 pub fn new(
282 start_key_pair: KeyPair, contract_creator: &Address,
283 start_balance: U256, start_erc20_balance: U256,
284 ) -> DirectTransactionGenerator {
285 let start_address = public_to_address(start_key_pair.public(), true);
286 let info = (
287 start_key_pair,
288 Account::new_empty_with_balance(
289 &start_address.with_native_space(),
290 &start_balance,
291 &0.into(), ),
293 start_erc20_balance,
294 );
295 let mut accounts = HashMap::<Address, (KeyPair, Account, U256)>::new();
296 accounts.insert(start_address, info);
297 let address_by_index = vec![start_address];
298
299 let mut erc20_address = cal_contract_address(
300 CreateContractAddressType::FromSenderNonceAndCodeHash,
301 contract_creator,
304 &0.into(),
305 &[],
307 )
308 .0;
309 erc20_address.set_contract_type_bits();
310
311 debug!(
312 "Special Transaction Generator: erc20 contract address: {:?}",
313 erc20_address
314 );
315
316 DirectTransactionGenerator {
317 accounts,
318 address_by_index,
319 erc20_address,
320 }
321 }
322
323 pub fn generate_transactions(
324 &mut self, block_size_limit: &mut usize, mut num_txs_simple: usize,
325 mut num_txs_erc20: usize, chain_id: u32,
326 ) -> Vec<Arc<SignedTransaction>> {
327 let mut result = vec![];
328 while num_txs_simple > 0 {
330 let number_of_accounts = self.address_by_index.len();
331
332 let sender_index: usize = random_range(0..number_of_accounts);
333 let sender_address =
334 *self.address_by_index.get(sender_index).unwrap();
335 let sender_kp;
336 let sender_balance;
337 let sender_nonce;
338 {
339 let sender_info = self.accounts.get(&sender_address).unwrap();
340 sender_kp = sender_info.0.clone();
341 sender_balance = sender_info.1.balance;
342 sender_nonce = sender_info.1.nonce;
343 }
344
345 let gas = U256::from(100_000u64);
346 let gas_price = U256::from(1u64);
347 let transaction_fee = U256::from(100_000u64);
348
349 if sender_balance <= transaction_fee {
350 self.accounts.remove(&sender_address);
351 self.address_by_index.swap_remove(sender_index);
352 continue;
353 }
354
355 let balance_to_transfer = U256::try_from(
356 H512::random().into_uint() % U512::from(sender_balance),
357 )
358 .unwrap();
359
360 let is_send_to_new_address = (number_of_accounts
361 <= Self::MAX_TOTAL_ACCOUNTS)
362 && ((number_of_accounts < 10)
363 || (rand::thread_rng().random_range(0..10) == 0));
364
365 let receiver_address = match is_send_to_new_address {
366 false => {
367 let index: usize = random_range(0..number_of_accounts);
368 *self.address_by_index.get(index).unwrap()
369 }
370 true => loop {
371 let kp =
372 Random.generate().expect("Fail to generate KeyPair.");
373 let address = public_to_address(kp.public(), true);
374 if let std::collections::hash_map::Entry::Vacant(e) =
375 self.accounts.entry(address)
376 {
377 e.insert((
378 kp,
379 Account::new_empty_with_balance(
380 &address.with_native_space(),
381 &0.into(), &0.into(), ),
384 0.into(),
385 ));
386 self.address_by_index.push(address);
387
388 break address;
389 }
390 },
391 };
392
393 let tx: Transaction = NativeTransaction {
394 nonce: sender_nonce,
395 gas_price,
396 gas,
397 value: balance_to_transfer,
398 action: Action::Call(receiver_address),
399 storage_limit: 0,
400 epoch_height: 0,
404 chain_id,
405 data: vec![0u8; 128],
406 }
407 .into();
408 let signed_transaction = tx.sign(sender_kp.secret());
409 let rlp_size = signed_transaction.transaction.rlp_bytes().len();
410 if *block_size_limit <= rlp_size {
411 break;
412 }
413 *block_size_limit -= rlp_size;
414
415 self.accounts.get_mut(&sender_address).unwrap().1.balance -=
416 balance_to_transfer;
417 self.accounts.get_mut(&sender_address).unwrap().1.nonce += 1.into();
418 self.accounts.get_mut(&receiver_address).unwrap().1.balance +=
419 balance_to_transfer;
420
421 result.push(Arc::new(signed_transaction));
422
423 num_txs_simple -= 1;
424 }
425
426 while num_txs_erc20 > 0 {
427 let number_of_accounts = self.address_by_index.len();
428
429 let sender_index: usize = random_range(0..number_of_accounts);
430 let sender_address =
431 *self.address_by_index.get(sender_index).unwrap();
432 let sender_kp;
433 let sender_balance;
434 let sender_erc20_balance;
435 let sender_nonce;
436 {
437 let sender_info = self.accounts.get(&sender_address).unwrap();
438 sender_kp = sender_info.0.clone();
439 sender_balance = sender_info.1.balance;
440 sender_erc20_balance = sender_info.2;
441 sender_nonce = sender_info.1.nonce;
442 }
443
444 let gas = U256::from(100_000u64);
445 let gas_price = U256::from(1u64);
446 let transaction_fee = U256::from(100_000u64);
447
448 if sender_balance <= transaction_fee {
449 self.accounts.remove(&sender_address);
450 self.address_by_index.swap_remove(sender_index);
451 continue;
452 }
453
454 let balance_to_transfer = if sender_erc20_balance == 0.into() {
455 continue;
456 } else {
457 U256::try_from(
458 H512::random().into_uint()
459 % U512::from(sender_erc20_balance),
460 )
461 .unwrap()
462 };
463
464 let receiver_index = random_range(0..number_of_accounts);
465 let receiver_address =
466 *self.address_by_index.get(receiver_index).unwrap();
467
468 if receiver_index == sender_index {
469 continue;
470 }
471
472 let tx_data = (String::new()
474 + "a9059cbb000000000000000000000000"
475 + &receiver_address.0.to_hex::<String>()[2..]
476 + {
477 let h: H256 =
478 BigEndianHash::from_uint(&balance_to_transfer);
479 &h.0.to_hex::<String>()[2..]
480 })
481 .from_hex()
482 .unwrap();
483
484 let tx: Transaction = NativeTransaction {
485 nonce: sender_nonce,
486 gas_price,
487 gas,
488 value: 0.into(),
489 action: Action::Call(self.erc20_address),
490 storage_limit: 0,
491 epoch_height: 0,
495 chain_id,
496 data: tx_data,
497 }
498 .into();
499 let signed_transaction = tx.sign(sender_kp.secret());
500 let rlp_size = signed_transaction.transaction.rlp_bytes().len();
501 if *block_size_limit <= rlp_size {
502 break;
503 }
504 *block_size_limit -= rlp_size;
505
506 self.accounts.get_mut(&sender_address).unwrap().2 -=
507 balance_to_transfer;
508 self.accounts.get_mut(&sender_address).unwrap().1.nonce += 1.into();
509 self.accounts.get_mut(&receiver_address).unwrap().2 +=
510 balance_to_transfer;
511
512 result.push(Arc::new(signed_transaction));
513
514 num_txs_erc20 -= 1;
515 }
516
517 result
518 }
519}