From a905f2b966be11c70b0c6091941db2b0482d4c67 Mon Sep 17 00:00:00 2001
From: Anthony Graignic <anthony.graignic@uca.fr>
Date: Fri, 22 Dec 2023 16:24:26 +0100
Subject: [PATCH] Add additional params to send cmd

Add hd_index to select the same address derived from the HD wallet
Add waiting time to sleep between 2 send
---
 src/main.rs | 143 +++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 101 insertions(+), 42 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index cff2cb7..b59a281 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,13 +1,14 @@
 use ecomobicoin_jsonrpc::types::{Behavior, Block};
 use ethereum_types::U64;
+use ethers::prelude::rand::Rng;
+use ethers::types::transaction::ecomobicoin_behavior::EcoMobiCoinBehaviorTransactionRequest;
 use ethers::{prelude::*, signers::coins_bip39::English};
 use futures::executor::block_on;
-use testnet_injector::utils::miner::get_miner_behavior;
-use std::{process, time::Duration};
+use std::str::FromStr;
 use std::time::{SystemTime, UNIX_EPOCH};
-use testnet_injector::{
-    utils::{mobility_data::*, txbx},
-};
+use std::{process, time::Duration};
+use testnet_injector::utils::miner::get_miner_behavior;
+use testnet_injector::utils::{mobility_data::*, txbx};
 use tracing::{debug, error, info, Level};
 
 use ::clap::{Args, Parser, Subcommand};
@@ -39,10 +40,14 @@ struct SendParams {
     txs: u64,
     /// Number of behaviors to send
     bxs: u64,
+    // Index of account in HD wallet
+    hd_index: Option<u32>,
+    // Waiting period between each tx/bx
+    wait: Option<u64>,
     // Node RPC URL
     rpc_url: Option<String>,
     // Chain ID
-    chain_id: Option<u64>
+    chain_id: Option<u64>,
 }
 
 #[derive(Args)]
@@ -54,7 +59,7 @@ struct SimulateBxFromCsv {
     // Node RPC URL
     rpc_url: Option<String>,
     // Chain ID
-    chain_id: Option<u64>
+    chain_id: Option<u64>,
 }
 
 #[derive(Args)]
@@ -62,7 +67,7 @@ struct MineParams {
     // Node RPC URL
     rpc_url: Option<String>,
     // Chain ID
-    chain_id: Option<u64>
+    chain_id: Option<u64>,
 }
 
 async fn init() -> (u64, String) {
@@ -111,51 +116,91 @@ async fn main() -> Result<(), anyhow::Error> {
         Some(Commands::Send(params)) => {
             info!("Sending {:?} tx and {:?} bx ...", params.txs, params.bxs);
             // Override env vars if specified in CLI
-            if params.rpc_url.clone().is_some(){
+            if params.rpc_url.clone().is_some() {
                 rpc_url = params.rpc_url.clone().unwrap();
             }
-            if params.chain_id.clone().is_some(){
+            if params.chain_id.clone().is_some() {
                 chain_id = params.chain_id.clone().unwrap();
             }
 
             let max = std::cmp::max(params.txs, params.bxs);
 
-            for i in 0..max {
-                let mnemonic = std::env::var("MNEMONIC").unwrap_or("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about".to_string());
-                let wallet = MnemonicBuilder::<English>::default()
+            let hd_index: u32 = if params.hd_index.is_some() {
+                params.hd_index.unwrap()
+            } else {
+                let mut rng = rand::thread_rng();
+                rng.gen()
+            };
+
+            let mnemonic = std::env::var("MNEMONIC").unwrap_or("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about".to_string());
+            let wallet = MnemonicBuilder::<English>::default()
                 .phrase(PathOrString::String(mnemonic.clone()))
-                .index(i as u32)
+                .index(hd_index)
                 .unwrap()
                 .build()
                 .unwrap()
                 .with_chain_id(chain_id);
-                let provider = Provider::<Http>::try_from(rpc_url.clone()).unwrap();
-                let client = SignerMiddleware::new(provider.clone(), wallet.clone());
 
+            let provider = Provider::<Http>::try_from(rpc_url.clone()).unwrap();
+            let signer = SignerMiddleware::new(provider.clone(), wallet.clone());
+            let addr = signer.clone().address();
+
+            let nonce_manager = signer.nonce_manager(addr);
+
+            for i in 0..max {
+                //FIXME nonce doesn't update locally
+                let curr_nonce = nonce_manager
+                    .get_transaction_count(addr, None)
+                    .await
+                    .unwrap()
+                    .as_u64();
+
+                info!("Signer: 0x{:02x}, nonce: {:?}", addr, curr_nonce);
 
                 if i < params.bxs {
-                    let bx_hash = txbx::send_default_bx(
-                        client.clone(),
-                        chain_id,
-                    ).await;
+                    let now = SystemTime::now()
+                        .duration_since(SystemTime::UNIX_EPOCH)
+                        .unwrap()
+                        .as_secs();
+                    let data = Bytes::from_str("0x015d8eb90000000000000000000000000000000000000000000000000000000000878c1c00000000000000000000000000000000000000000000000000000000644662bc0000000000000000000000000000000000000000000000000000001ee24fba17b7e19cc10812911dfa8a438e0a81a9933f843aa5b528899b8d9e221b649ae0df00000000000000000000000000000000000000000000000000000000000000060000000000000000000000007431310e026b69bfc676c0013e12a1a11411eec9000000000000000000000000000000000000000000000000000000000000083400000000000000000000000000000000000000000000000000000000000f4240").unwrap();
+
+                    let bx: EcoMobiCoinBehaviorTransactionRequest =
+                        EcoMobiCoinBehaviorTransactionRequest::new(
+                            TransactionRequest::new()
+                                // .to(signer.address())
+                                .value(U256::from(210000))
+                                .chain_id(chain_id)
+                                .data(data.0.clone()),
+                            Some(U64::from(now)),
+                        );
+
+                    let bx_hash = nonce_manager.send_transaction(bx, None).await;
                     info!("Sent default bx {:?}", bx_hash);
                 }
                 if i < params.txs {
-                    let tx_hash = txbx::send_default_tx(
-                        client.clone(),
-                        chain_id,
-                    ).await;
+                    let tx = TransactionRequest::new()
+                        .to(Address::random())
+                        .value(U256::from(210000))
+                        .chain_id(chain_id);
+                    let tx_hash = nonce_manager.send_transaction(tx, None).await;
                     info!("Sent default tx {:?}", tx_hash);
                 }
+                if params.wait.is_some() {
+                    tokio::time::sleep(Duration::from_secs(params.wait.unwrap())).await;
+                }
             }
         }
         Some(Commands::SimulateBxFromCsv(params)) => {
-            info!("Simulating file {:?} for a total time of {:?} secs",params.file.clone(), params.total_simulation_duration.clone());
+            info!(
+                "Simulating file {:?} for a total time of {:?} secs",
+                params.file.clone(),
+                params.total_simulation_duration.clone()
+            );
             // Override env vars if specified in CLI
-            if params.rpc_url.clone().is_some(){
+            if params.rpc_url.clone().is_some() {
                 rpc_url = params.rpc_url.clone().unwrap();
             }
-            if params.chain_id.clone().is_some(){
+            if params.chain_id.clone().is_some() {
                 chain_id = params.chain_id.clone().unwrap();
             }
             // println!("Processing {:?}", params.file);
@@ -188,11 +233,16 @@ async fn main() -> Result<(), anyhow::Error> {
                 Duration::from_millis(dataset_max_relative_time as u64)
             );
 
-            let mobility_records_times: Vec<Duration> = mobility_records.iter().map(|r| compute_stretched_relative_start_time(
-                r.relative_start_time as u64,
-                total_simulation_duration,
-                dataset_max_relative_time as u64,
-            )).collect();
+            let mobility_records_times: Vec<Duration> = mobility_records
+                .iter()
+                .map(|r| {
+                    compute_stretched_relative_start_time(
+                        r.relative_start_time as u64,
+                        total_simulation_duration,
+                        dataset_max_relative_time as u64,
+                    )
+                })
+                .collect();
 
             // ----------------
             // Sending queue
@@ -200,7 +250,10 @@ async fn main() -> Result<(), anyhow::Error> {
             let mut handles = Vec::with_capacity(mobility_records.len());
 
             for i in 0..mobility_records.len() {
-                let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
+                let now = SystemTime::now()
+                    .duration_since(UNIX_EPOCH)
+                    .unwrap()
+                    .as_secs();
                 let simulation_behavior = mobility_records[i].clone();
                 let relative_start_duration = mobility_records_times[i].clone();
                 let rpc_url = rpc_url.clone();
@@ -252,32 +305,38 @@ async fn main() -> Result<(), anyhow::Error> {
             for handle in handles {
                 block_on(handle).unwrap();
             }
-        },
+        }
         Some(Commands::Mine(params)) => {
-
             // Override env vars if specified in CLI
-            if params.rpc_url.clone().is_some(){
+            if params.rpc_url.clone().is_some() {
                 rpc_url = params.rpc_url.clone().unwrap();
             }
-            if params.chain_id.clone().is_some(){
+            if params.chain_id.clone().is_some() {
                 chain_id = params.chain_id.clone().unwrap();
             }
 
             // Wallet is derived from mnemomic with user_id to ensure each user have the same wallet for the simulation.
-            let miner_signing_key = std::env::var("MINER_SIGNING_KEY").expect("Must specify a miner private key");
+            let miner_signing_key =
+                std::env::var("MINER_SIGNING_KEY").expect("Must specify a miner private key");
             let wallet: LocalWallet = miner_signing_key.parse::<LocalWallet>().unwrap();
             let miner_addr = wallet.address();
-            info!("Mining with 0x{:02x} ...",miner_addr);
+            info!("Mining with 0x{:02x} ...", miner_addr);
 
             let behavior = get_miner_behavior(wallet, chain_id, miner_addr);
             // SEND IT
             let provider = Provider::<Http>::try_from(rpc_url.clone()).unwrap();
-            debug!("Miner behavior: {:?}",serde_json::to_string(&behavior.clone()));
-            let block = provider.request::<[Behavior;1], Block>("emc_mine", [behavior]).await.unwrap();
+            debug!(
+                "Miner behavior: {:?}",
+                serde_json::to_string(&behavior.clone())
+            );
+            let block = provider
+                .request::<[Behavior; 1], Block>("emc_mine", [behavior])
+                .await
+                .unwrap();
 
             debug!("Mining response: {:?}", block);
             info!("Mined block {:?}", block.number.unwrap())
-        },
+        }
         None => {}
     }
     Ok(())
-- 
GitLab