Skip to content

Commit 31bc961

Browse files
committed
[all resource export] add content verify
1 parent 5ae9766 commit 31bc961

File tree

7 files changed

+97
-42
lines changed

7 files changed

+97
-42
lines changed

Cargo.lock

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/resource-code-exporter/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ rust-version = { workspace = true }
1111

1212
[dependencies]
1313
anyhow = { workspace = true }
14+
bcs-ext = { workspace = true }
1415
clap = { workspace = true }
1516
csv = { workspace = true }
1617
serde_json = { workspace = true }
@@ -19,6 +20,7 @@ starcoin-statedb = { workspace = true }
1920
starcoin-storage = { workspace = true }
2021
starcoin-types = { workspace = true }
2122
tempfile = "3.19.1"
23+
log = "0.4.27"
2224

2325

2426
[dev-dependencies]

cmd/resource-code-exporter/src/export.rs

+36-11
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use starcoin_statedb::{ChainStateDB, ChainStateReader};
66
use starcoin_storage::{
77
db_storage::DBStorage, storage::StorageInstance, BlockStore, Storage, StorageVersion,
88
};
9-
use std::{io::Write, path::Path, sync::Arc};
9+
use std::{io::Write, path::Path, sync::Arc};
1010

1111
/// Export resources and code from storage for a specific block
1212
pub fn export(db: &str, output: &Path, block_id: HashValue) -> anyhow::Result<()> {
@@ -30,22 +30,23 @@ pub fn export(db: &str, output: &Path, block_id: HashValue) -> anyhow::Result<()
3030

3131
// Create writer and export
3232
let mut csv_writer = csv::WriterBuilder::new().from_path(output)?;
33-
export_from_statedb(&statedb, root, &mut csv_writer)?;
33+
export_from_statedb(&statedb, &mut csv_writer)?;
3434

3535
Ok(())
3636
}
3737

3838
/// Export resources and code from StateDB to a writer
3939
pub fn export_from_statedb<W: Write>(
4040
statedb: &ChainStateDB,
41-
root: HashValue,
4241
writer: &mut csv::Writer<W>,
4342
) -> anyhow::Result<()> {
4443
// write csv header
4544
{
4645
writer.write_field("address")?;
47-
writer.write_field("state_root")?;
48-
writer.write_field("account_state")?;
46+
writer.write_field("code_blob_hash")?;
47+
writer.write_field("code_blob")?;
48+
writer.write_field("resource_blob_hash")?;
49+
writer.write_field("resrouce_blob")?;
4950
writer.write_record(None::<&[u8]>)?;
5051
}
5152

@@ -56,15 +57,39 @@ pub fn export_from_statedb<W: Write>(
5657
let now = Instant::now();
5758
let mut processed = 0;
5859

59-
for (account_address, account_state) in global_states.into_iter() {
60-
// Serialize the entire account state
61-
let account_state_json = serde_json::to_string(&account_state)?;
60+
for (account_address, account_state_set) in global_states.into_iter() {
61+
// Process codes
62+
let (code_state_set_hash, code_state_set) = match account_state_set.code_set() {
63+
Some(state_set) => {
64+
let code_state_set = serde_json::to_string(&state_set).unwrap();
65+
(
66+
HashValue::sha3_256_of(&code_state_set.as_bytes()).to_hex_literal(),
67+
code_state_set,
68+
)
69+
}
70+
None => (String::new(), String::new()),
71+
};
72+
73+
// Process resources
74+
let (resource_state_set_hash, resource_state_set) = match account_state_set.resource_set() {
75+
Some(state_set) => {
76+
let resource_state_set = serde_json::to_string(&state_set).unwrap();
77+
(
78+
HashValue::sha3_256_of(&resource_state_set.as_bytes()).to_hex_literal(),
79+
resource_state_set,
80+
)
81+
}
82+
None => (String::new(), String::new()),
83+
};
6284

6385
// write csv record
6486
let record = vec![
87+
// account address
6588
serde_json::to_string(&account_address)?,
66-
serde_json::to_string(&root)?,
67-
account_state_json,
89+
code_state_set_hash,
90+
code_state_set,
91+
resource_state_set_hash,
92+
resource_state_set,
6893
];
6994

7095
writer.serialize(record)?;
@@ -93,7 +118,7 @@ mod test {
93118
let mut buffer = Cursor::new(Vec::new());
94119
{
95120
let mut csv_writer = csv::WriterBuilder::new().from_writer(&mut buffer);
96-
export_from_statedb(&chain_statedb, chain_statedb.state_root(), &mut csv_writer)?;
121+
export_from_statedb(&chain_statedb, &mut csv_writer)?;
97122
}
98123

99124
// Get the written data

cmd/resource-code-exporter/src/import.rs

+43-28
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
use starcoin_crypto::HashValue;
55
use starcoin_statedb::{ChainStateDB, ChainStateReader, ChainStateWriter};
66
use starcoin_storage::{db_storage::DBStorage, storage::StorageInstance, Storage, StorageVersion};
7+
use starcoin_types::state_set::StateSet;
78
use starcoin_types::{
89
account_address::AccountAddress,
910
state_set::{AccountStateSet, ChainStateSet},
1011
};
1112
use std::path::Path;
1213
use std::sync::Arc;
1314

14-
pub fn import(csv_path: &Path, db_path: &Path) -> anyhow::Result<()> {
15+
pub fn import(csv_path: &Path, db_path: &Path, expect_root_hash: HashValue) -> anyhow::Result<()> {
1516
let db_storage = DBStorage::open_with_cfs(
1617
db_path,
1718
StorageVersion::current_version()
@@ -24,42 +25,63 @@ pub fn import(csv_path: &Path, db_path: &Path) -> anyhow::Result<()> {
2425
let storage = Storage::new(StorageInstance::new_db_instance(db_storage))?;
2526
let storage = Arc::new(storage);
2627
let statedb = ChainStateDB::new(storage.clone(), None);
27-
import_from_statedb(&statedb, csv_path)
28+
import_from_statedb(&statedb, csv_path, expect_root_hash)
2829
}
2930

3031
/// Import resources and code from CSV file to a new statedb
31-
pub fn import_from_statedb(statedb: &ChainStateDB, csv_path: &Path) -> anyhow::Result<()> {
32+
pub fn import_from_statedb(
33+
statedb: &ChainStateDB,
34+
csv_path: &Path,
35+
expect_state_root_hash: HashValue,
36+
) -> anyhow::Result<()> {
3237
// Read CSV file
3338
let mut csv_reader = csv::Reader::from_path(csv_path)?;
34-
let mut expected_state_root = None;
35-
let mut state_sets = Vec::new();
39+
let mut chain_state_set_data = Vec::new();
3640

3741
for result in csv_reader.records() {
3842
let record = result?;
39-
let address: AccountAddress = serde_json::from_str(&record[0])?;
40-
let state_root: HashValue = serde_json::from_str(&record[1])?;
41-
let account_state: AccountStateSet = serde_json::from_str(&record[2])?;
43+
let account_address: AccountAddress = serde_json::from_str(&record[0])?;
44+
println!("record len: {:?}", record.len());
4245

43-
// Store the first state root as expected
44-
if expected_state_root.is_none() {
45-
expected_state_root = Some(state_root);
46-
}
46+
let code_state_set = if !record[1].is_empty() && !record[2].is_empty() {
47+
let code_state_hash: String = serde_json::from_str(&record[1])?;
48+
let code_state_set_str = &record[2];
49+
assert_eq!(
50+
code_state_hash,
51+
HashValue::sha3_256_of(code_state_set_str.as_bytes()).to_hex_literal()
52+
);
53+
Some(serde_json::from_str::<StateSet>(code_state_set_str)?)
54+
} else {
55+
None
56+
};
57+
58+
let resource_state_set = if !record[3].is_empty() && !record[4].is_empty() {
59+
let resrouce_blob_hash: String = serde_json::from_str(&record[3])?;
60+
let resource_state_set_str = &record[4];
61+
assert_eq!(
62+
resrouce_blob_hash,
63+
HashValue::sha3_256_of(resource_state_set_str.as_bytes()).to_hex_literal()
64+
);
65+
Some(serde_json::from_str(resource_state_set_str)?)
66+
} else {
67+
None
68+
};
4769

48-
// Add to state sets
49-
state_sets.push((address, account_state));
70+
chain_state_set_data.push((
71+
account_address,
72+
AccountStateSet::new(vec![code_state_set, resource_state_set]),
73+
));
5074
}
5175

52-
// Create chain state set and apply it
53-
let chain_state_set = ChainStateSet::new(state_sets);
54-
statedb.apply(chain_state_set)?;
76+
statedb.apply(ChainStateSet::new(chain_state_set_data))?;
5577

5678
// Get new state root
5779
let new_state_root = statedb.state_root();
5880

5981
// Verify state root matches
60-
if let Some(expected) = expected_state_root {
82+
{
6183
assert_eq!(
62-
new_state_root, expected,
84+
expect_state_root_hash, new_state_root,
6385
"Imported state root does not match expected state root"
6486
);
6587
println!("Import successful! State root: {}", new_state_root);
@@ -91,7 +113,7 @@ mod test {
91113
// Export data
92114
{
93115
let mut csv_writer = csv::WriterBuilder::new().from_path(&export_path)?;
94-
export_from_statedb(&export_chain_statedb, export_state_root, &mut csv_writer)?;
116+
export_from_statedb(&export_chain_statedb, &mut csv_writer)?;
95117
}
96118

97119
//////////////////////////////////////////////////////
@@ -113,14 +135,7 @@ mod test {
113135
let storage = Storage::new(StorageInstance::new_db_instance(db_storage))?;
114136
let storage = Arc::new(storage);
115137
let imported_statedb = ChainStateDB::new(storage.clone(), None);
116-
import_from_statedb(&imported_statedb, &export_path)?;
117-
118-
// Verify state root matches
119-
assert_eq!(
120-
imported_statedb.state_root(),
121-
export_state_root,
122-
"Imported state root does not match genesis state root"
123-
);
138+
import_from_statedb(&imported_statedb, &export_path, export_state_root)?;
124139

125140
Ok(())
126141
}

cmd/resource-code-exporter/src/main.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ enum Commands {
4242
#[clap(long, short = 'd', parse(from_os_str))]
4343
/// Output database path
4444
db_path: PathBuf,
45+
46+
#[clap(long)]
47+
/// expect state root hash
48+
state_root: starcoin_crypto::HashValue,
4549
},
4650
}
4751

@@ -56,8 +60,12 @@ fn main() -> anyhow::Result<()> {
5660
} => {
5761
export::export(db_path.display().to_string().as_str(), &output, block_id)?;
5862
}
59-
Commands::Import { csv_input, db_path } => {
60-
import::import(&csv_input, &db_path)?;
63+
Commands::Import {
64+
csv_input,
65+
db_path,
66+
state_root,
67+
} => {
68+
import::import(&csv_input, &db_path, state_root)?;
6169
}
6270
}
6371

state/statedb/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ starcoin-types = { workspace = true }
1313
starcoin-vm-types = { workspace = true }
1414
thiserror = { workspace = true }
1515
once_cell = "1.17.1"
16+
rayon = "1.8"
1617

1718
[package]
1819
authors = { workspace = true }

state/statedb/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use starcoin_types::{
2222
access_path::{AccessPath, DataType},
2323
account_address::AccountAddress,
2424
account_state::AccountState,
25-
state_set::{AccountStateSet, ChainStateSet},
25+
state_set::{AccountStateSet, ChainStateSet, StateSet},
2626
};
2727
use starcoin_vm_types::access_path::{DataPath, ModuleName};
2828
#[cfg(test)]
@@ -789,5 +789,6 @@ impl TableHandleStateObject {
789789
}
790790
}
791791

792+
mod parallel_state_set;
792793
#[cfg(test)]
793794
mod tests;

0 commit comments

Comments
 (0)