Skip to content

Commit af6a71e

Browse files
sebtombamusitdev
andauthored
Compare balances for specific ledger versions (#210)
## Description Add state comparison cmd. Co-authored-by: musitdev <[email protected]>
1 parent 20632ef commit af6a71e

File tree

4 files changed

+187
-34
lines changed

4 files changed

+187
-34
lines changed
Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,31 @@
11
// Copyright (c) Aptos Foundation
22
// SPDX-License-Identifier: Apache-2.0
33

4-
use crate::{
5-
checks::node::global_storage_includes::GlobalStorageIncludes,
6-
types::storage::{MovementAptosStorage, MovementStorage},
7-
};
8-
use clap::Parser;
9-
use std::path::PathBuf;
4+
use crate::checks::node::global_storage_includes::CompareDbCmd;
5+
use crate::checks::node::state_diff::CompareStatesCmd;
6+
use clap::Subcommand;
107

118
mod global_storage_includes;
9+
mod state_diff;
1210

13-
#[derive(Parser)]
14-
#[clap(
15-
name = "migration-node-validation",
16-
about = "Validates data conformity after movement migration."
17-
)]
18-
pub struct Command {
19-
#[clap(long = "movement", help = "The path to the movement database.")]
20-
pub movement_db: PathBuf,
21-
#[clap(
22-
long = "movement-aptos",
23-
help = "The path to the movement Aptos database."
24-
)]
25-
pub movement_aptos_db: PathBuf,
11+
#[derive(Subcommand, Debug)]
12+
#[clap(rename_all = "kebab-case", about = "Node database verification tool")]
13+
pub enum NodeValidation {
14+
CompareDb(CompareDbCmd),
15+
CompareStates(CompareStatesCmd),
2616
}
2717

28-
impl Command {
18+
impl NodeValidation {
2919
pub async fn run(self) -> anyhow::Result<()> {
30-
let movement_storage = MovementStorage::open(&self.movement_db)?;
31-
let movement_aptos_storage = MovementAptosStorage::open(&self.movement_aptos_db)?;
32-
33-
GlobalStorageIncludes::satisfies(&movement_storage, &movement_aptos_storage)?;
34-
35-
Ok(())
20+
match self {
21+
NodeValidation::CompareDb(cmd) => cmd.run().await,
22+
NodeValidation::CompareStates(cmd) => cmd.run().await,
23+
}
3624
}
3725
}
3826

3927
#[test]
4028
fn verify_tool() {
4129
use clap::CommandFactory;
42-
Command::command().debug_assert()
30+
NodeValidation::command().debug_assert()
4331
}

movement-migration/validation-tool/src/checks/node/global_storage_includes.rs

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,47 @@ use aptos_types::{
1414
},
1515
};
1616
use bytes::Bytes;
17+
use clap::Parser;
1718
use move_core_types::{account_address::AccountAddress, language_storage::StructTag};
1819
use std::cmp::Ordering;
1920
use std::collections::BTreeSet;
20-
use std::fmt::Display;
21-
use std::fmt::Formatter;
21+
use std::fmt::{Display, Formatter};
22+
use std::path::PathBuf;
2223
use std::str::FromStr;
2324
use tracing::{debug, info};
2425

26+
#[derive(Parser, Debug)]
27+
#[clap(
28+
name = "compare-database",
29+
about = "Validates data conformity after movement migration."
30+
)]
31+
pub struct CompareDbCmd {
32+
#[clap(long = "movement", help = "The path to the movement database.")]
33+
pub movement_db: PathBuf,
34+
#[clap(
35+
long = "movement-aptos",
36+
help = "The path to the movement Aptos database."
37+
)]
38+
pub movement_aptos_db: PathBuf,
39+
}
40+
41+
impl CompareDbCmd {
42+
pub async fn run(self) -> anyhow::Result<()> {
43+
let movement_storage = MovementStorage::open(&self.movement_db)?;
44+
let movement_aptos_storage = MovementAptosStorage::open(&self.movement_aptos_db)?;
45+
46+
GlobalStorageIncludes::satisfies(&movement_storage, &movement_aptos_storage)?;
47+
48+
Ok(())
49+
}
50+
}
51+
52+
#[test]
53+
fn verify_tool() {
54+
use clap::CommandFactory;
55+
CompareDbCmd::command().debug_assert()
56+
}
57+
2558
#[derive(Debug)]
2659
pub enum FailedComparison {
2760
MissingStateValue(StateKey),
@@ -132,16 +165,16 @@ impl PartialOrd for FailedComparison {
132165
impl Display for FailedComparison {
133166
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
134167
match self {
135-
FailedComparison::MissingStateValue(movement_state_key) =>
168+
FailedComparison::MissingStateValue(state_key) =>
136169
write!(f,
137170
"Movement Aptos is missing a value for {:?}",
138-
movement_state_key
171+
state_key
139172
)
140173
,
141-
FailedComparison::NotMissingStateValue(movement_state_key) =>
174+
FailedComparison::NotMissingStateValue(state_key) =>
142175
write!(f,
143176
"Movement Aptos is unexpectedly not missing a value for {:?}",
144-
movement_state_key
177+
state_key
145178
),
146179
FailedComparison::RawStateDiverge {
147180
state_key,
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// Copyright (c) Aptos Foundation
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use crate::checks::node::global_storage_includes::GlobalStorageIncludes;
5+
use crate::types::storage::{MovementAptosStorage, MovementStorage};
6+
use clap::Parser;
7+
use std::path::PathBuf;
8+
use std::str::FromStr;
9+
use tracing::info;
10+
11+
#[derive(Parser, Debug)]
12+
#[clap(
13+
name = "compare-states",
14+
about = "Compares balances for each transaction at specific ledger versions"
15+
)]
16+
pub struct CompareStatesCmd {
17+
#[clap(long = "movement-db", help = "Path to the Movement database.")]
18+
pub movement_db: PathBuf,
19+
#[clap(long = "aptos-db", help = "Path to the Aptos database.")]
20+
pub aptos_db: PathBuf,
21+
#[arg(help = "First hash,version,version tuple")]
22+
first: String,
23+
#[arg(help = "Second hash,version,version tuple")]
24+
second: String,
25+
}
26+
27+
impl CompareStatesCmd {
28+
pub async fn run(&self) -> anyhow::Result<()> {
29+
let movement_storage = MovementStorage::open(&self.movement_db)?;
30+
let aptos_storage = MovementAptosStorage::open(&self.aptos_db)?;
31+
32+
compare_states(&movement_storage, &aptos_storage, &self.first, &self.second).await?;
33+
34+
Ok(())
35+
}
36+
}
37+
38+
#[test]
39+
fn verify_tool() {
40+
use clap::CommandFactory;
41+
CompareStatesCmd::command().debug_assert()
42+
}
43+
44+
async fn compare_states(
45+
movement_storage: &MovementStorage,
46+
aptos_storage: &MovementAptosStorage,
47+
first: &str,
48+
second: &str,
49+
) -> anyhow::Result<()> {
50+
let (hash1, aptos_version1, movement_version1) = parse_line(first)?;
51+
let (hash2, aptos_version2, movement_version2) = parse_line(second)?;
52+
53+
info!(
54+
"Comparing post transaction {}: Movement version: {}, Aptos version: {}",
55+
hash1, movement_version1, aptos_version1
56+
);
57+
58+
let result1 = GlobalStorageIncludes::compare_db(
59+
movement_storage,
60+
movement_version1,
61+
aptos_storage,
62+
aptos_version1,
63+
)?;
64+
65+
info!(
66+
"Comparing post transaction {}: Movement version: {}, Aptos version: {}",
67+
hash2, movement_version2, aptos_version2
68+
);
69+
70+
let result2 = GlobalStorageIncludes::compare_db(
71+
movement_storage,
72+
movement_version2,
73+
aptos_storage,
74+
aptos_version2,
75+
)?;
76+
77+
let diff = result2
78+
.into_iter()
79+
.filter(|c| result1.contains(c))
80+
.collect::<Vec<_>>();
81+
82+
for comparison in diff {
83+
info!("{}", comparison);
84+
}
85+
86+
Ok(())
87+
}
88+
89+
// async fn compare_balances(
90+
// movement_storage: &MovementStorage,
91+
// aptos_storage: &MovementAptosStorage,
92+
// path: &PathBuf,
93+
// ) -> anyhow::Result<()> {
94+
// use tokio::fs::File;
95+
// use tokio::io::{AsyncBufReadExt, BufReader};
96+
// let file = File::open(path).await?;
97+
// let reader = BufReader::new(file);
98+
// let mut lines = reader.lines();
99+
//
100+
// while let Some(line) = lines.next_line().await? {
101+
// let (hash, aptos_version, movement_version) = parse_line(&line)?;
102+
// info!(
103+
// "Processing transaction {}: Aptos version {}, Movement version {}",
104+
// hash, aptos_version, movement_version
105+
// );
106+
// let diff = GlobalStorageIncludes::compare_db(
107+
// movement_storage,
108+
// movement_version,
109+
// aptos_storage,
110+
// aptos_version,
111+
// )?;
112+
//
113+
// for comparison in diff {}
114+
// }
115+
//
116+
// Ok(())
117+
// }
118+
119+
fn parse_line(line: &str) -> anyhow::Result<(&str, u64, u64)> {
120+
let parts = line.split(',').collect::<Vec<_>>();
121+
let parts: [&str; 3] = parts.try_into().map_err(|v: Vec<&str>| {
122+
anyhow::anyhow!(
123+
"Expected 3 parts extracted from the line. Found {}",
124+
v.len()
125+
)
126+
})?;
127+
let [hash, aptos_version, movement_version] = parts;
128+
let aptos_version = u64::from_str(aptos_version)?;
129+
let movement_version = u64::from_str(movement_version)?;
130+
Ok((hash, aptos_version, movement_version))
131+
}

movement-migration/validation-tool/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ mod types;
1414
)]
1515
pub enum ValidationTool {
1616
Api(checks::api::Command),
17-
Node(checks::node::Command),
17+
#[clap(subcommand)]
18+
Node(checks::node::NodeValidation),
1819
}
1920

2021
impl ValidationTool {

0 commit comments

Comments
 (0)