From cd567d756a15881ea30349606a528c142066c19b Mon Sep 17 00:00:00 2001 From: qima Date: Wed, 1 May 2024 17:39:01 +0800 Subject: [PATCH] feat(client): dump spends creation_reason statistics --- .github/workflows/memcheck.yml | 10 ++++---- sn_cli/src/bin/subcommands/wallet/audit.rs | 7 ++++++ sn_client/src/audit/spend_dag.rs | 27 ++++++++++++++++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/.github/workflows/memcheck.yml b/.github/workflows/memcheck.yml index 5c8f7f5e57..b895dae3e7 100644 --- a/.github/workflows/memcheck.yml +++ b/.github/workflows/memcheck.yml @@ -281,9 +281,9 @@ jobs: - name: Audit from genesis to collect entire spend DAG and dump to a dot file run: | - cargo run --bin safe --release -- --log-output-dest=data-dir wallet audit --dot > spend_dag.dot + cargo run --bin safe --release -- --log-output-dest=data-dir wallet audit --dot > spend_dag_and_statistics.txt echo "==============================================================================" - cat spend_dag.dot + cat spend_dag_and_statistics.txt env: SN_LOG: "all" timeout-minutes: 60 @@ -446,10 +446,10 @@ jobs: continue-on-error: true if: always() - - name: Upload spend DAG + - name: Upload spend DAG and statistics uses: actions/upload-artifact@main with: - name: memory_check_spend_dag - path: spend_dag.dot + name: memory_check_spend_dag_and_statistics + path: spend_dag_and_statistics.txt continue-on-error: true if: always() diff --git a/sn_cli/src/bin/subcommands/wallet/audit.rs b/sn_cli/src/bin/subcommands/wallet/audit.rs index ca6c8adb15..b05d09bc90 100644 --- a/sn_cli/src/bin/subcommands/wallet/audit.rs +++ b/sn_cli/src/bin/subcommands/wallet/audit.rs @@ -40,7 +40,14 @@ async fn gather_spend_dag(client: &Client, root_dir: &Path) -> Result pub async fn audit(client: &Client, to_dot: bool, royalties: bool, root_dir: &Path) -> Result<()> { if to_dot { let dag = gather_spend_dag(client, root_dir).await?; + println!( + "========================== spends DAG diagraph =============================" + ); println!("{}", dag.dump_dot_format()); + println!( + "======================= spends purpose statistics ==========================" + ); + println!("{}", dag.dump_creation_reasons_statistics()); } else if royalties { let dag = gather_spend_dag(client, root_dir).await?; let royalties = dag.all_royalties()?; diff --git a/sn_client/src/audit/spend_dag.rs b/sn_client/src/audit/spend_dag.rs index 33a362726f..ab4246e3cd 100644 --- a/sn_client/src/audit/spend_dag.rs +++ b/sn_client/src/audit/spend_dag.rs @@ -102,6 +102,14 @@ impl DagEntry { DagEntry::NotGatheredYet(_) => vec![], } } + + fn amount(&self) -> NanoTokens { + if let Some(signed_spend) = self.spends().first() { + signed_spend.spend.amount + } else { + NanoTokens::zero() + } + } } /// The result of a get operation on the DAG @@ -338,6 +346,25 @@ impl SpendDag { format!("{:?}", Dot::with_config(&self.dag, &[])) } + pub fn dump_creation_reasons_statistics(&self) -> String { + let mut statistics: BTreeMap> = Default::default(); + for (spend_addr, reason) in self.creation_reasons.iter() { + let holders = statistics.entry(reason.clone()).or_default(); + if let Some(spend_dag_entry) = self.spends.get(spend_addr) { + holders.push(spend_dag_entry.amount()); + } + } + let mut content = "Purpose,Times,Amount".to_string(); + for (purpose, payments) in statistics.iter() { + let total_amount: u64 = payments + .iter() + .map(|nano_tokens| nano_tokens.as_nano()) + .sum(); + content = format!("{content}\n{purpose},{},{total_amount}", payments.len()); + } + content + } + /// Merges the given dag into ours pub fn merge(&mut self, sub_dag: SpendDag) -> Result<(), DagError> { let source = self.source();