diff --git a/Cargo.lock b/Cargo.lock index d7dd4bcdb78ba89763b3e6d2eb67a6b15238d29c..fdcb2707b948b3aff4a9c16de31eeba7c39cb7c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -110,7 +110,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytes" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -717,12 +717,12 @@ dependencies = [ "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.30 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl-sys" -version = "0.9.30" +version = "0.9.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1132,7 +1132,7 @@ dependencies = [ [[package]] name = "tokio" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1142,8 +1142,8 @@ dependencies = [ "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1152,17 +1152,17 @@ name = "tokio-core" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1180,7 +1180,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1188,7 +1188,7 @@ name = "tokio-io" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1211,7 +1211,7 @@ name = "tokio-tcp" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1221,7 +1221,7 @@ dependencies = [ [[package]] name = "tokio-threadpool" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1234,7 +1234,7 @@ dependencies = [ [[package]] name = "tokio-timer" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1257,7 +1257,7 @@ name = "tokio-udp" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1367,7 +1367,7 @@ dependencies = [ "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1438,7 +1438,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" "checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" -"checksum bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "2f1d50c876fb7545f5f289cd8b2aee3f359d073ae819eed5d6373638e2c61e59" +"checksum bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd32989a66957d3f0cba6588f15d4281a733f4e9ffc43fcd2385f57d3bf99ff" "checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba" "checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18" "checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6" @@ -1488,7 +1488,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "a3605c298474a3aa69de92d21139fb5e2a81688d308262359d85cdd0d12a7985" -"checksum openssl-sys 0.9.30 (registry+https://github.com/rust-lang/crates.io-index)" = "73ae718c3562989cd3a0a5c26610feca02f8116822f6f195e6cf4887481e57f5" +"checksum openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)" = "d8abc04833dcedef24221a91852931df2f63e3369ae003134e70aff3645775cc" "checksum pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "deb73390ab68d81992bd994d145f697451bb0b54fd39738e72eef32458ad6907" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f" @@ -1537,15 +1537,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" -"checksum tokio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d00555353b013e170ed8bc4e13f648a317d1fd12157dbcae13f7013f6cf29f5" +"checksum tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ee337e5f4e501fc32966fec6fe0ca0cc1c237b0b1b14a335f8bfe3c5f06e286" "checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" "checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113" "checksum tokio-fs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76766830bbf9a2d5bfb50c95350d56a2e79e2c80f675967fff448bc615899708" "checksum tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af9eb326f64b2d6b68438e1953341e00ab3cf54de7e35d92bfc73af8555313a" "checksum tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3cedc8e5af5131dc3423ffa4f877cce78ad25259a9a62de0613735a13ebc64b" "checksum tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec9b094851aadd2caf83ba3ad8e8c4ce65a42104f7b94d9e6550023f0407853f" -"checksum tokio-threadpool 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5783254b10c7c84a56f62c74766ef7e5b83d1f13053218c7cab8d3f2c826fa0e" -"checksum tokio-timer 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535fed0ccee189f3d48447587697ba3fd234b3dbbb091f0ec4613ddfec0a7c4c" +"checksum tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c3873a6d8d0b636e024e77b9a82eaab6739578a06189ecd0e731c7308fbc5d" +"checksum tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "028b94314065b90f026a21826cffd62a4e40a92cda3e5c069cc7b02e5945f5e9" "checksum tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "772f4b04e560117fe3b0a53e490c16ddc8ba6ec437015d91fa385564996ed913" "checksum tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "137bda266504893ac4774e0ec4c2108f7ccdbcb7ac8dced6305fe9e4e0b5041a" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" diff --git a/Cargo.toml b/Cargo.toml index 7d75866bbfb4f61d01bba1f07212141590110912..d718f4841291111a7ce8bbedf80889222c7c0a59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,15 @@ license = "AGPL-3.0" [dependencies] duniter-core = { path = "./core" } duniter-tui = { path = "./tui" } -duniter-ws2p = { path = "./ws2p" } +duniter-ws2p = { path = "./ws2p", optional = true } [features] +default = ["ws2p"] +ws2p = ["duniter-ws2p"] # Treat warnings as a build error. strict = [] + [workspace] members = [ "blockchain", @@ -27,5 +30,5 @@ members = [ "network", "tui", "wotb", - "ws2p", + "ws2p" ] diff --git a/blockchain/apply_valid_block.rs b/blockchain/apply_valid_block.rs index 26b31cbcde6fb39f54f73a7a701dbc3926443d23..c395d2fcf598f12fbfefc1782dcf6b896ffb23cd 100644 --- a/blockchain/apply_valid_block.rs +++ b/blockchain/apply_valid_block.rs @@ -147,6 +147,7 @@ pub fn apply_valid_block<W: WebOfTrust, B: Backend + Debug>( wot_dbs_requests.push(WotsDBsWriteQuery::RevokeIdentity( compact_revoc.issuer, block.blockstamp(), + true, )); } for certification in block.certifications.clone() { diff --git a/blockchain/check_and_apply_block.rs b/blockchain/check_and_apply_block.rs index 21f4e567fa561a9850164e43b389645e1d5a8580..2981adefdd099d1a85ca3f6e4c961a17a5310a89 100644 --- a/blockchain/check_and_apply_block.rs +++ b/blockchain/check_and_apply_block.rs @@ -156,6 +156,7 @@ pub fn check_and_apply_block<W: WebOfTrust, B: Backend + Debug>( &dal_block, None, false, + false, ).expect("duniter_dal::writers::block::write() : DALError") } Block::LocalBlock(block_doc) => { @@ -173,6 +174,7 @@ pub fn check_and_apply_block<W: WebOfTrust, B: Backend + Debug>( &dal_block, old_fork_id, false, + false, ).expect("duniter_dal::writers::block::write() : DALError") } }; diff --git a/blockchain/clippy.toml b/blockchain/clippy.toml index 1c6d687e2556b27948a8036e154546fcebec87eb..16934920c7fa627dc091b94ed08687bea1afe437 100644 --- a/blockchain/clippy.toml +++ b/blockchain/clippy.toml @@ -1 +1 @@ -cyclomatic-complexity-threshold = 37 \ No newline at end of file +cyclomatic-complexity-threshold = 38 \ No newline at end of file diff --git a/blockchain/dbex.rs b/blockchain/dbex.rs index 9999f311c2c37e3c1ff977632b21dfc898f140c2..6da2fa3096de5961b992ee7b513c6f573610698d 100644 --- a/blockchain/dbex.rs +++ b/blockchain/dbex.rs @@ -18,12 +18,19 @@ use duniter_dal::identity::DALIdentity; use duniter_documents::blockchain::v10::documents::transaction::*; use duniter_module::DuniterConf; use duniter_wotb::data::rusty::RustyWebOfTrust; +use duniter_wotb::operations::distance::{DistanceCalculator, WotDistance, WotDistanceParameters}; use std::time::*; use *; #[derive(Debug, Clone)] /// Query for wot databases explorer pub enum DBExWotQuery { + /// Ask distance of all members + AllDistances(bool), + /// Show members expire date + ExpireMembers(bool, bool), + /// Show members list + ListMembers(bool), /// Ask member datas MemberDatas(String), } @@ -69,7 +76,6 @@ pub fn dbex_tx(conf: &DuniterConf, query: &DBExTxQuery) { load_dbs_duration.subsec_nanos() / 1_000_000 ); let req_process_begin = SystemTime::now(); - match *query { DBExTxQuery::Balance(ref address_str) => { let pubkey = if let Ok(ed25519_pubkey) = ed25519::PublicKey::from_base58(address_str) { @@ -115,7 +121,8 @@ pub fn dbex_wot(conf: &DuniterConf, query: &DBExWotQuery) { // Open databases let load_dbs_begin = SystemTime::now(); - //let blocks_databases = BlocksV10DBs::open(&db_path, false); + let currency_params_db = + open_db::<CurrencyParamsV10Datas>(&db_path, "params.db").expect("Fail to open params db"); let wot_databases = WotsV10DBs::open(&db_path, false); let load_dbs_duration = SystemTime::now() .duration_since(load_dbs_begin) @@ -125,7 +132,11 @@ pub fn dbex_wot(conf: &DuniterConf, query: &DBExWotQuery) { load_dbs_duration.as_secs(), load_dbs_duration.subsec_nanos() / 1_000_000 ); - let req_process_begin = SystemTime::now(); + + // Get currency parameters + let currency_params = currency_params_db + .read(|db| CurrencyParameters::from(db.clone())) + .expect("Fail to parse currency params !"); // get wot_index let wot_index = DALIdentity::get_wotb_index(&wot_databases.identities_db).expect("DALError"); @@ -134,21 +145,126 @@ pub fn dbex_wot(conf: &DuniterConf, query: &DBExWotQuery) { let wot_reverse_index: HashMap<NodeId, &PubKey> = wot_index.iter().map(|(p, id)| (*id, p)).collect(); + // get wot uid index + let wot_uid_index: HashMap<NodeId, String> = wot_databases + .identities_db + .read(|db| { + db.iter() + .map(|(_, idty)| (idty.wot_id, String::from(idty.idty_doc.username()))) + .collect() + }) + .expect("Fail to read IdentitiesDB !"); + // Open wot db let wot_db = open_wot_db::<RustyWebOfTrust>(&db_path).expect("Fail to open WotDB !"); // Print wot blockstamp //println!("Wot : Current blockstamp = {}.", wot_blockstamp); - // Print members count + // Get members count let members_count = wot_db .read(|db| db.get_enabled()) .expect("Fail to read WotDB") .len(); - println!(" Members count = {}.", members_count); match *query { + DBExWotQuery::AllDistances(ref reverse) => { + println!("compute distances..."); + let compute_distances_begin = SystemTime::now(); + let mut distances_datas: Vec<(NodeId, WotDistance)> = wot_db + .read(|db| { + db.get_enabled() + .iter() + .map(|wot_id| { + ( + *wot_id, + DISTANCE_CALCULATOR + .compute_distance( + db, + WotDistanceParameters { + node: *wot_id, + sentry_requirement: 5, + step_max: currency_params.step_max as u32, + x_percent: currency_params.x_percent, + }, + ) + .expect("Fail to get distance !"), + ) + }) + .collect() + }) + .expect("Fail to read WotDB"); + let compute_distances_duration = SystemTime::now() + .duration_since(compute_distances_begin) + .expect("duration_since error"); + if *reverse { + distances_datas.sort_unstable_by(|(_, d1), (_, d2)| d1.success.cmp(&d2.success)); + } else { + distances_datas.sort_unstable_by(|(_, d1), (_, d2)| d2.success.cmp(&d1.success)); + } + for (wot_id, distance_datas) in distances_datas { + let distance_percent: f64 = + f64::from(distance_datas.success) / f64::from(distance_datas.sentries) * 100.0; + println!( + "{} -> distance: {:.2}% ({}/{})", + wot_uid_index[&wot_id], + distance_percent, + distance_datas.success, + distance_datas.sentries + ); + } + println!( + "compute_distances_duration = {},{:03}.", + compute_distances_duration.as_secs(), + compute_distances_duration.subsec_nanos() / 1_000_000 + ); + } + DBExWotQuery::ExpireMembers(ref reverse, ref _csv) => { + // Open blockchain database + let blockchain_db = open_db::<LocalBlockchainV10Datas>(&db_path, "blockchain.db") + .expect("Fail to open blockchain db"); + // Get blocks_times + let (current_bc_time, blocks_times): (u64, HashMap<BlockId, u64>) = blockchain_db + .read(|db| { + ( + db[&BlockId(db.len() as u32 - 1)].block.median_time, + db.iter() + .map(|(block_id, dal_block)| (*block_id, dal_block.block.median_time)) + .collect(), + ) + }) + .expect("Fail to read blockchain db"); + // Get expire_dates + let min_created_ms_time = current_bc_time - currency_params.ms_validity; + let mut expire_dates: Vec<(NodeId, u64)> = wot_databases + .ms_db + .read(|db| { + let mut expire_dates = Vec::new(); + for (block_id, nodes_ids) in db { + let created_ms_time = blocks_times[&block_id]; + if created_ms_time > min_created_ms_time { + for node_id in nodes_ids { + expire_dates.push(( + *node_id, + created_ms_time + currency_params.ms_validity, + )); + } + } + } + expire_dates + }) + .expect("Fail to read ms db"); + if *reverse { + expire_dates.sort_unstable_by(|(_, d1), (_, d2)| d1.cmp(&d2)); + } else { + expire_dates.sort_unstable_by(|(_, d1), (_, d2)| d2.cmp(&d1)); + } + for (node_id, expire_date) in expire_dates { + println!("{}, {}", wot_uid_index[&node_id], expire_date); + } + } DBExWotQuery::MemberDatas(ref uid) => { + println!(" Members count = {}.", members_count); if let Some(pubkey) = duniter_dal::identity::get_pubkey_from_uid(&wot_databases.identities_db, uid) .expect("get_pubkey_from_uid() : DALError !") @@ -160,6 +276,26 @@ pub fn dbex_wot(conf: &DuniterConf, query: &DBExWotQuery) { wot_id.0, pubkey.to_string() ); + let distance_datas = wot_db + .read(|db| { + DISTANCE_CALCULATOR.compute_distance( + db, + WotDistanceParameters { + node: wot_id, + sentry_requirement: 5, + step_max: currency_params.step_max as u32, + x_percent: currency_params.x_percent, + }, + ) + }) + .expect("Fail to read WotDB") + .expect("Fail to get distance !"); + let distance_percent: f64 = + f64::from(distance_datas.success) / f64::from(distance_datas.sentries) * 100.0; + println!( + "Distance {:.2}% ({}/{})", + distance_percent, distance_datas.success, distance_datas.sentries + ); let sources = wot_db .read(|db| db.get_links_source(wot_id)) .expect("Fail to read WotDB") @@ -177,13 +313,6 @@ pub fn dbex_wot(conf: &DuniterConf, query: &DBExWotQuery) { println!("Uid \"{}\" not found !", uid); } } + _ => {} } - let req_process_duration = SystemTime::now() - .duration_since(req_process_begin) - .expect("duration_since error"); - println!( - "Request processed in {}.{:06} seconds.", - req_process_duration.as_secs(), - req_process_duration.subsec_nanos() / 1_000 - ); } diff --git a/blockchain/lib.rs b/blockchain/lib.rs index c7ef4ec4c8d4d2712d77faeea781c64d5e6ba0d1..7fbd4fbab84237134e5908a68efb3cdc21a9412a 100644 --- a/blockchain/lib.rs +++ b/blockchain/lib.rs @@ -42,6 +42,7 @@ extern crate sqlite; mod apply_valid_block; mod check_and_apply_block; mod dbex; +mod revert_block; mod sync; mod ts_parsers; @@ -74,6 +75,7 @@ use duniter_network::{ NetworkBlock, NetworkDocument, NetworkEvent, NetworkRequest, NetworkResponse, NodeFullId, }; use duniter_wotb::data::rusty::RustyWebOfTrust; +use duniter_wotb::operations::distance::RustyDistanceCalculator; use duniter_wotb::{NodeId, WebOfTrust}; use rustbreak::backend::{Backend, FileBackend}; @@ -83,6 +85,8 @@ pub static CHUNK_SIZE: &'static u32 = &50; pub static INFINITE_SIG_STOCK: &'static usize = &4_000_000_000; /// The blocks are requested by packet groups. This constant sets the number of packets per group. pub static MAX_BLOCKS_REQUEST: &'static u32 = &500; +/// The distance calculator +pub static DISTANCE_CALCULATOR: &'static RustyDistanceCalculator = &RustyDistanceCalculator {}; /// Blockchain Module #[derive(Debug)] @@ -193,17 +197,6 @@ impl BlockchainModule { } /// Synchronize blockchain from a duniter-ts database pub fn sync_ts(conf: &DuniterConf, ts_profile: &str, cautious: bool) { - // get databases path - let db_path = duniter_conf::get_blockchain_db_path(&conf.profile(), &conf.currency()); - // Open blocks dbs - let blocks_dbs = BlocksV10DBs::open(&db_path, false); - // Get local current blockstamp - debug!("Get local current blockstamp..."); - let current_blockstamp: Blockstamp = duniter_dal::block::get_current_blockstamp( - &blocks_dbs, - ).expect("ForksV10DB : RustBreakError !") - .unwrap_or_default(); - debug!("Success to get local current blockstamp."); // get db_ts_path let mut db_ts_path = match env::home_dir() { Some(path) => path, @@ -215,7 +208,7 @@ impl BlockchainModule { if !db_ts_path.as_path().exists() { panic!("Fatal error : duniter-ts database don't exist !"); } - sync::sync_ts(conf, ¤t_blockstamp, db_ts_path, cautious); + sync::sync_ts(conf, db_ts_path, cautious); } /// Request chunk from network (chunk = group of blocks) fn request_chunk(&self, req_id: &ModuleReqId, from: u32) -> (ModuleReqId, NetworkRequest) { @@ -651,6 +644,26 @@ impl BlockchainModule { { if let Ok(blockstamp) = response { consensus = blockstamp; + if current_blockstamp.id.0 > consensus.id.0 + 2 { + // Find free fork id + let free_fork_id = ForkId(49); + // Get last dal_block + let last_dal_block_id = + BlockId(current_blockstamp.id.0 - 1); + let last_dal_block = self + .blocks_databases + .blockchain_db + .read(|db| db.get(&last_dal_block_id).cloned()) + .expect("Fail to read blockchain DB.") + .expect("Fatal error : not foutn last dal block !"); + revert_block::revert_block( + &last_dal_block, + &mut wotb_index, + &wot_db, + Some(free_fork_id), + &self.currency_databases.tx_db.read(|db| db.clone()).expect("Fail to read TxDB.") + ).expect("Fail to revert block"); + } } } } diff --git a/blockchain/revert_block.rs b/blockchain/revert_block.rs new file mode 100644 index 0000000000000000000000000000000000000000..a349ba7fad4b0252500f72c045dc18b39e0ec1d4 --- /dev/null +++ b/blockchain/revert_block.rs @@ -0,0 +1,230 @@ +// Copyright (C) 2018 The Duniter Project Developers. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +use duniter_crypto::keys::*; +use duniter_dal::block::DALBlock; +use duniter_dal::sources::SourceAmount; +use duniter_dal::writers::requests::*; +use duniter_dal::writers::transaction::DALTxV10; +use duniter_dal::{BinDB, ForkId, TxV10Datas}; +use duniter_documents::blockchain::v10::documents::block::TxDocOrTxHash; +use duniter_documents::blockchain::v10::documents::transaction::{TxAmount, TxBase}; +use duniter_documents::blockchain::Document; +use duniter_wotb::data::NewLinkResult; +use duniter_wotb::{NodeId, WebOfTrust}; +use rustbreak::backend::Backend; +use std::collections::HashMap; +use std::fmt::Debug; + +#[derive(Debug)] +/// Stores all queries to apply in database to "apply" the block +pub struct ValidBlockRevertReqs( + pub BlocksDBsWriteQuery, + pub Vec<WotsDBsWriteQuery>, + pub Vec<CurrencyDBsWriteQuery>, +); + +#[derive(Debug, Copy, Clone)] +/// RevertValidBlockError +pub enum RevertValidBlockError { + ExcludeUnknowNodeId(), + RevokeUnknowNodeId(), +} + +pub fn revert_block<W: WebOfTrust, B: Backend + Debug>( + dal_block: &DALBlock, + wot_index: &mut HashMap<PubKey, NodeId>, + wot_db: &BinDB<W, B>, + to_fork_id: Option<ForkId>, + txs: &TxV10Datas, +) -> Result<ValidBlockRevertReqs, RevertValidBlockError> { + // Revert DALBlock + let mut block = dal_block.block.clone(); + let expire_certs = dal_block + .expire_certs + .clone() + .expect("Try to get expire_certs of an uncompleted block !"); + + // Get transactions + let dal_txs: Vec<DALTxV10> = block + .transactions + .iter() + .map(|tx_enum| match *tx_enum { + TxDocOrTxHash::TxHash(ref tx_hash) => txs[tx_hash].clone(), + TxDocOrTxHash::TxDoc(ref _dal_tx) => panic!("Try to revert not reduce block !"), + }) + .collect(); + + // Revert reduce block + block.compute_inner_hash(); + debug!( + "BlockchainModule : revert_valid_block({})", + block.blockstamp() + ); + + // REVERT_CURRENCY_EVENTS + let mut currency_dbs_requests = Vec::new(); + // Revert transactions + for dal_tx in dal_txs.iter().rev() { + currency_dbs_requests.push(CurrencyDBsWriteQuery::RevertTx(Box::new(dal_tx.clone()))); + } + // Revert DU + if let Some(du_amount) = block.dividend { + if du_amount > 0 { + let members_wot_ids = wot_db + .read(|db| db.get_enabled()) + .expect("Fail to read WotDB"); + let mut members_pubkeys = Vec::new(); + for (pubkey, wotb_id) in wot_index.iter() { + if members_wot_ids.contains(wotb_id) { + members_pubkeys.push(*pubkey); + } + } + currency_dbs_requests.push(CurrencyDBsWriteQuery::RevertDU( + SourceAmount(TxAmount(du_amount as isize), TxBase(block.unit_base)), + block.number, + members_pubkeys, + )); + } + } + // REVERT WOT EVENTS + let mut wot_dbs_requests = Vec::new(); + // Revert expire_certs + for ((source, target), created_block_id) in expire_certs { + wot_dbs_requests.push(WotsDBsWriteQuery::RevertExpireCert( + source, + target, + created_block_id, + )); + } + // Revert certifications + for certification in block.certifications.clone() { + trace!("stack_up_valid_block: apply cert..."); + let compact_cert = certification.to_compact_document(); + let wotb_node_from = wot_index[&compact_cert.issuer]; + let wotb_node_to = wot_index[&compact_cert.target]; + wot_db + .write(|db| { + let result = db.add_link(wotb_node_from, wotb_node_to); + match result { + NewLinkResult::Ok(_) => {} + _ => panic!( + "Fail to add_link {}->{} : {:?}", + wotb_node_from.0, wotb_node_to.0, result + ), + } + }) + .expect("Fail to read WotDB"); + wot_dbs_requests.push(WotsDBsWriteQuery::RevertCert( + compact_cert, + wotb_node_from, + wotb_node_to, + )); + trace!("stack_up_valid_block: apply cert...success."); + } + // Revert revocations + for revocation in block.revoked.clone() { + let compact_revoc = revocation.to_compact_document(); + let wot_id = if let Some(wot_id) = wot_index.get(&compact_revoc.issuer) { + wot_id + } else { + return Err(RevertValidBlockError::RevokeUnknowNodeId()); + }; + wot_db + .write(|db| { + db.set_enabled(*wot_id, false); + }) + .expect("Fail to write in WotDB"); + wot_dbs_requests.push(WotsDBsWriteQuery::RevertRevokeIdentity( + compact_revoc.issuer, + block.blockstamp(), + true, + )); + } + // Revert exclusions + for exclusion in block.excluded.clone() { + let wot_id = if let Some(wot_id) = wot_index.get(&exclusion) { + wot_id + } else { + return Err(RevertValidBlockError::ExcludeUnknowNodeId()); + }; + wot_db + .write(|db| { + db.set_enabled(*wot_id, false); + }) + .expect("Fail to write in WotDB"); + wot_dbs_requests.push(WotsDBsWriteQuery::RevertExcludeIdentity( + exclusion, + block.blockstamp(), + )); + } + // List block identities + let mut identities = HashMap::with_capacity(block.identities.len()); + for identity in block.identities.clone() { + identities.insert(identity.issuers()[0], identity); + } + // Revert renewals + for active in block.actives.clone() { + let pubkey = active.issuers()[0]; + if !identities.contains_key(&pubkey) { + let wotb_id = wot_index[&pubkey]; + wot_db + .write(|db| { + db.set_enabled(wotb_id, true); + }) + .expect("Fail to write in WotDB"); + wot_dbs_requests.push(WotsDBsWriteQuery::RevertRenewalIdentity( + pubkey, + wotb_id, + block.median_time, + active.blockstamp().id, + )); + } + } + // Revert joiners + for joiner in block.joiners.iter().rev() { + let pubkey = joiner.clone().issuers()[0]; + if let Some(_idty_doc) = identities.get(&pubkey) { + // Newcomer + wot_db + .write(|db| { + db.rem_node(); + }) + .expect("Fail to write in WotDB"); + wot_index.remove(&pubkey); + wot_dbs_requests.push(WotsDBsWriteQuery::RevertCreateIdentity(pubkey)); + } else { + // Renewer + let wotb_id = wot_index[&joiner.issuers()[0]]; + wot_db + .write(|db| { + db.set_enabled(wotb_id, true); + }) + .expect("Fail to write in WotDB"); + wot_dbs_requests.push(WotsDBsWriteQuery::RevertRenewalIdentity( + joiner.issuers()[0], + wotb_id, + block.median_time, + joiner.blockstamp().id, + )); + } + } + // Return DBs requests + Ok(ValidBlockRevertReqs( + BlocksDBsWriteQuery::RevertBlock(Box::new(dal_block.clone()), to_fork_id), + wot_dbs_requests, + currency_dbs_requests, + )) +} diff --git a/blockchain/sync.rs b/blockchain/sync.rs index 2f5c2f0f8a18371fb6396bb3575bb425a4f3c6f6..6636be2a604fcfd55bc907bd2b880aab40b75c44 100644 --- a/blockchain/sync.rs +++ b/blockchain/sync.rs @@ -67,23 +67,27 @@ enum SyncJobsMess { } /// Sync from a duniter-ts database -pub fn sync_ts( - conf: &DuniterConf, - current_blockstamp: &Blockstamp, - db_ts_path: PathBuf, - cautious: bool, -) { +pub fn sync_ts(conf: &DuniterConf, db_ts_path: PathBuf, cautious: bool) { // get profile and currency and current_blockstamp let profile = &conf.profile(); let currency = &conf.currency(); - let mut current_blockstamp = *current_blockstamp; - // Get wot path + // Get databases path let db_path = duniter_conf::get_blockchain_db_path(&profile, ¤cy); // Open wot db let wot_db = open_wot_db::<RustyWebOfTrust>(&db_path).expect("Fail to open WotDB !"); + // Open blocks databases + let databases = BlocksV10DBs::open(&db_path, false); + + // Get local current blockstamp + debug!("Get local current blockstamp..."); + let mut current_blockstamp: Blockstamp = duniter_dal::block::get_current_blockstamp(&databases) + .expect("ForksV10DB : RustBreakError !") + .unwrap_or_default(); + debug!("Success to get local current blockstamp."); + // Get verification level let _verif_level = if cautious { println!("Start cautious sync..."); @@ -275,14 +279,9 @@ pub fn sync_ts( let (sender_wot_thread, recv_wot_thread) = mpsc::channel(); // Launch blocks_worker thread - let profile_copy = conf.profile().clone(); - let currency_copy = conf.currency().clone(); let sender_sync_thread_clone = sender_sync_thread.clone(); pool.execute(move || { let blocks_job_begin = SystemTime::now(); - // Open databases - let db_path = duniter_conf::get_blockchain_db_path(&profile_copy, ¤cy_copy); - let databases = BlocksV10DBs::open(&db_path, false); // Listen db requets let mut chunk_index = 0; @@ -441,6 +440,11 @@ pub fn sync_ts( }); let main_job_begin = SystemTime::now(); + // Open currency_params_db + let dbs_path = duniter_conf::get_blockchain_db_path(&conf.profile(), &conf.currency()); + let currency_params_db = + open_db::<CurrencyParamsV10Datas>(&dbs_path, "params.db").expect("Fail to open params db"); + // Apply blocks let mut blocks_not_expiring = VecDeque::with_capacity(200_000); let mut last_block_expiring: isize = -1; @@ -464,19 +468,21 @@ pub fn sync_ts( .duration_since(complete_block_begin) .unwrap(); // Get currency params - if !get_currency_params { - if block_doc.number.0 == 0 { - if block_doc.parameters.is_some() { - currency_params = CurrencyParameters::from(( - block_doc.currency.clone(), - block_doc.parameters.unwrap(), - )); - get_currency_params = true; - } else { - panic!("The genesis block are None parameters !"); - } + if !get_currency_params && block_doc.number.0 == 0 { + if block_doc.parameters.is_some() { + currency_params_db + .write(|db| { + db.0 = block_doc.currency.clone(); + db.1 = block_doc.parameters.unwrap(); + }) + .expect("fail to write in params DB"); + currency_params = CurrencyParameters::from(( + block_doc.currency.clone(), + block_doc.parameters.unwrap(), + )); + get_currency_params = true; } else { - panic!("The first block is not genesis !"); + panic!("The genesis block are None parameters !"); } } // Push block median_time in blocks_not_expiring @@ -582,6 +588,9 @@ pub fn sync_ts( .expect("Sync : Fail to send End signal to writer worker !"); info!("Sync : send End signal to tx job."); + // Save params db + currency_params_db.save().expect("Fail to save params db"); + // Save wot file wot_db.save().expect("Fail to save wotb db"); diff --git a/core/cli/en.yml b/core/cli/en.yml index ff97559fd4978303483a432af5d5b24a63795822..f295780739b4181d8856aa3825f0d7a4d27f1478 100644 --- a/core/cli/en.yml +++ b/core/cli/en.yml @@ -43,9 +43,23 @@ subcommands: about: durs databases explorer version: "0.1.0" author: Elois L. <elois@duniter.org> + args: + - csv: + short: c + long: csv + help: csv output subcommands: + - distances: + about: durs databases explorer (distances datas) + version: "0.1.0" + author: Elois L. <elois@duniter.org> + args: + - reverse: + short: r + long: reverse + help: reverse order - member: - about: durs databases explorer (wot members datas) + about: durs databases explorer (wot member datas) version: "0.1.0" author: Elois L. <elois@duniter.org> args: @@ -53,6 +67,19 @@ subcommands: help : choose member uid index: 1 required: true + - members: + about: durs databases explorer (wot members datas) + version: "0.1.0" + author: Elois L. <elois@duniter.org> + args: + - expire: + short: e + long: expire + help: show members expire date + - reverse: + short: r + long: reverse + help: reverse order - balance: about: durs databases explorer (balances datas) version: "0.1.0" diff --git a/core/lib.rs b/core/lib.rs index 773a77f785b5e4a11870c7254188f384cdbb7b53..574bd7811818aeddfae0d2530a685a2865648fa0 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -125,12 +125,37 @@ impl DuniterCore { sync_ts(&conf, ts_profile, matches.is_present("cautious")); None } else if let Some(matches) = cli_args.subcommand_matches("dbex") { - if let Some(member_matches) = matches.subcommand_matches("member") { + let csv = matches.is_present("csv"); + if let Some(distances_matches) = matches.subcommand_matches("distances") { + dbex( + &conf, + &DBExQuery::WotQuery(DBExWotQuery::AllDistances( + distances_matches.is_present("reverse"), + )), + ); + } else if let Some(member_matches) = matches.subcommand_matches("member") { let uid = member_matches.value_of("UID").unwrap_or(""); dbex( &conf, &DBExQuery::WotQuery(DBExWotQuery::MemberDatas(String::from(uid))), ); + } else if let Some(members_matches) = matches.subcommand_matches("members") { + if members_matches.is_present("expire") { + dbex( + &conf, + &DBExQuery::WotQuery(DBExWotQuery::ExpireMembers( + members_matches.is_present("reverse"), + csv, + )), + ); + } else { + dbex( + &conf, + &DBExQuery::WotQuery(DBExWotQuery::ListMembers( + members_matches.is_present("reverse"), + )), + ); + } } else if let Some(balance_matches) = matches.subcommand_matches("balance") { let address = balance_matches.value_of("ADDRESS").unwrap_or(""); dbex( diff --git a/dal/identity.rs b/dal/identity.rs index 38ee0955b4e0a2dc379c3749bcc7565684d69b51..ee35e4c3bec9660eb847b7e024ed4b81fd922006 100644 --- a/dal/identity.rs +++ b/dal/identity.rs @@ -25,7 +25,8 @@ pub struct DALIdentity { pub expired_on: Option<Blockstamp>, pub revoked_on: Option<Blockstamp>, pub idty_doc: IdentityDocument, - pub wotb_id: NodeId, + pub wot_id: NodeId, + pub ms_created_block_id: BlockId, pub ms_chainable_on: Vec<u64>, pub cert_chainable_on: Vec<u64>, } @@ -100,35 +101,13 @@ impl DALIdentity { Ok(identities_db.read(|db| { let mut wotb_index: HashMap<PubKey, NodeId> = HashMap::new(); for (pubkey, member_datas) in db { - let wotb_id = member_datas.wotb_id; + let wotb_id = member_datas.wot_id; wotb_index.insert(*pubkey, wotb_id); } wotb_index })?) } - pub fn create_identity( - currency_params: &CurrencyParameters, - idty_doc: &IdentityDocument, - wotb_id: NodeId, - current_blockstamp: Blockstamp, - current_bc_time: u64, - ) -> DALIdentity { - let mut idty_doc = idty_doc.clone(); - idty_doc.reduce(); - DALIdentity { - hash: "0".to_string(), - state: DALIdentityState::Member(vec![0]), - joined_on: current_blockstamp, - expired_on: None, - revoked_on: None, - idty_doc, - wotb_id, - ms_chainable_on: vec![current_bc_time + currency_params.ms_period], - cert_chainable_on: vec![], - } - } - pub fn revoke_identity<B: Backend + Debug>( identities_db: &BinDB<IdentitiesV10Datas, B>, pubkey: &PubKey, diff --git a/dal/lib.rs b/dal/lib.rs index 3704a8db7c901b3f0b6005af0028c109bb637003..d6e4196a56aca24151cecd0ee9e8775a4fa2c8d9 100644 --- a/dal/lib.rs +++ b/dal/lib.rs @@ -50,6 +50,7 @@ pub mod tools; pub mod writers; use duniter_crypto::keys::*; +use duniter_documents::blockchain::v10::documents::block::{BlockV10Parameters, CurrencyName}; use duniter_documents::blockchain::v10::documents::transaction::*; use duniter_documents::{BlockHash, BlockId, Blockstamp, Hash, PreviousBlockstamp}; use duniter_wotb::{NodeId, WebOfTrust}; @@ -73,6 +74,7 @@ use writers::transaction::DALTxV10; /// Each fork has a unique identifier. The local blockchain (also called local branch) has ForkId equal to zero. pub struct ForkId(pub usize); +pub type CurrencyParamsV10Datas = (CurrencyName, BlockV10Parameters); pub type LocalBlockchainV10Datas = HashMap<BlockId, DALBlock>; pub type ForksV10Datas = HashMap<ForkId, HashMap<PreviousBlockstamp, BlockHash>>; pub type ForksBlocksV10Datas = HashMap<Blockstamp, DALBlock>; diff --git a/dal/sources.rs b/dal/sources.rs index dcb27bbafdee5b75b10f3f60df846b91487e085b..bfe6c54b6dfbf98512f5cd285756af5c0c19d94d 100644 --- a/dal/sources.rs +++ b/dal/sources.rs @@ -19,9 +19,10 @@ extern crate duniter_documents; use duniter_crypto::keys::PubKey; use duniter_documents::blockchain::v10::documents::transaction::*; use duniter_documents::{BlockId, Hash}; +use std::cmp::Ordering; use std::ops::{Add, Sub}; -#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Serialize)] pub struct SourceAmount(pub TxAmount, pub TxBase); impl Default for SourceAmount { @@ -30,6 +31,16 @@ impl Default for SourceAmount { } } +impl Ord for SourceAmount { + fn cmp(&self, other: &SourceAmount) -> Ordering { + if self.1 == other.1 { + self.0.cmp(&other.0) + } else { + self.1.cmp(&other.1) + } + } +} + impl Add for SourceAmount { type Output = SourceAmount; fn add(self, s2: SourceAmount) -> Self::Output { diff --git a/dal/writers/block.rs b/dal/writers/block.rs index e86bf9f6714ef94e7bdc19962a1e01d47d7f5378..053146d4bb2bca5f2798d2c29f6681071c39226f 100644 --- a/dal/writers/block.rs +++ b/dal/writers/block.rs @@ -1,6 +1,6 @@ use block::DALBlock; use duniter_documents::blockchain::Document; -use duniter_documents::{BlockHash, BlockId, Blockstamp, PreviousBlockstamp}; +use duniter_documents::{BlockHash, BlockId, PreviousBlockstamp}; use std::collections::HashMap; use ForkId; use {BinFileDB, DALError, ForksBlocksV10Datas, ForksV10Datas, LocalBlockchainV10Datas}; @@ -11,39 +11,61 @@ pub fn write( forks_db: &BinFileDB<ForksV10Datas>, forks_blocks_db: &BinFileDB<ForksBlocksV10Datas>, dal_block: &DALBlock, - old_fork_id: Option<ForkId>, + from_to_fork_id: Option<ForkId>, sync: bool, + revert: bool, ) -> Result<(), DALError> { if dal_block.fork_id.0 == 0 { blockchain_db.write(|db| { - db.insert(dal_block.block.number, dal_block.clone()); + if revert { + db.remove(&dal_block.block.number); + } else { + db.insert(dal_block.block.number, dal_block.clone()); + } })?; - if old_fork_id.is_some() { + if from_to_fork_id.is_some() { forks_blocks_db.write(|db| { db.remove(&dal_block.block.blockstamp()); })?; } } - if let Some(old_fork_id) = old_fork_id { + // Move block in a fork + if revert { + if let Some(to_fork_id) = from_to_fork_id { + forks_db.write(|db| { + let previous_blockstamp = dal_block.block.previous_blockstamp(); + let mut fork_meta_datas = db.get(&to_fork_id).unwrap().clone(); + fork_meta_datas.insert( + previous_blockstamp, + dal_block + .block + .hash + .expect("Try to get hash of a reduce block !"), + ); + db.insert(to_fork_id, fork_meta_datas); + })?; + } + } else if let Some(from_fork_id) = from_to_fork_id { + // Remove block in fork origin forks_db.write(|db| { let mut fork_meta_datas = db - .get(&old_fork_id) - .expect("old_fork_id don(t exist !") + .get(&from_fork_id) + .expect("from_fork_id don(t exist !") .clone(); - let previous_blockstamp = Blockstamp { - id: BlockId(dal_block.block.blockstamp().id.0 - 1), - hash: dal_block - .block - .hash - .expect("Try to get hash of an uncompleted or reduce block !"), - }; + let previous_blockstamp = dal_block.block.previous_blockstamp(); fork_meta_datas.remove(&previous_blockstamp); - db.insert(old_fork_id, fork_meta_datas); + db.insert(from_fork_id, fork_meta_datas); if dal_block.fork_id.0 > 0 { let mut fork_meta_datas = db.get(&dal_block.fork_id).unwrap().clone(); - fork_meta_datas.insert(previous_blockstamp, dal_block.block.hash.unwrap()); - db.insert(old_fork_id, fork_meta_datas); + fork_meta_datas.insert( + previous_blockstamp, + dal_block + .block + .hash + .expect("Try to get hash of a reduce block !"), + ); + db.insert(from_fork_id, fork_meta_datas); } })?; } diff --git a/dal/writers/dividend.rs b/dal/writers/dividend.rs index 7f7a4a350bdc0872de0fac405f48fe6f0ba4dd1a..3071e6c675942754143d36be262b2d254d8a1817 100644 --- a/dal/writers/dividend.rs +++ b/dal/writers/dividend.rs @@ -28,12 +28,17 @@ pub fn create_du<B: Backend + Debug>( du_amount: &SourceAmount, du_block_id: &BlockId, members: &[PubKey], + revert: bool, ) -> Result<(), DALError> { - // Insert DU sources in DUsV10DB + // Insert/Remove DU sources in DUsV10DB du_db.write(|db| { for pubkey in members { let mut pubkey_dus = db.get(&pubkey).cloned().unwrap_or_default(); - pubkey_dus.insert(*du_block_id); + if revert { + pubkey_dus.remove(du_block_id); + } else { + pubkey_dus.insert(*du_block_id); + } db.insert(*pubkey, pubkey_dus); } })?; @@ -52,11 +57,15 @@ pub fn create_du<B: Backend + Debug>( } members_balances })?; - // Increment members balance + // Increase/Decrease members balance let members_balances: Vec<(PubKey, (SourceAmount, HashSet<UTXOIndexV10>))> = members_balances .iter() .map(|(pubkey, (balance, utxos_indexs))| { - let new_balance = *balance + *du_amount; + let new_balance = if revert { + *balance - *du_amount + } else { + *balance + *du_amount + }; (*pubkey, (new_balance, utxos_indexs.clone())) }) .collect(); diff --git a/dal/writers/identity.rs b/dal/writers/identity.rs index 214f4dbd769baee30dabe49325f8124c723bfe25..8426edf30340ee82163eebd9cc559f83eab1646d 100644 --- a/dal/writers/identity.rs +++ b/dal/writers/identity.rs @@ -1,24 +1,70 @@ -use super::super::identity::DALIdentity; +use currency_params::CurrencyParameters; +use duniter_crypto::keys::PubKey; +use duniter_documents::blockchain::v10::documents::IdentityDocument; use duniter_documents::blockchain::Document; -use duniter_documents::BlockId; +use duniter_documents::{BlockId, Blockstamp}; use duniter_wotb::NodeId; +use identity::{DALIdentity, DALIdentityState}; use {BinFileDB, DALError, IdentitiesV10Datas, MsExpirV10Datas}; -pub fn write( - idty: &DALIdentity, - idty_wot_id: NodeId, +pub fn revert_create_identity( identities_db: &BinFileDB<IdentitiesV10Datas>, ms_db: &BinFileDB<MsExpirV10Datas>, + pubkey: &PubKey, +) -> Result<(), DALError> { + let dal_idty = identities_db.read(|db| { + db.get(&pubkey) + .expect("Fatal error : try to revert unknow identity !") + .clone() + })?; + // Remove membership + ms_db.write(|db| { + let mut memberships = db + .get(&dal_idty.ms_created_block_id) + .cloned() + .expect("Try to revert a membership that does not exist !"); + memberships.remove(&dal_idty.wot_id); + db.insert(dal_idty.ms_created_block_id, memberships); + })?; + // Remove identity + identities_db.write(|db| { + db.remove(&dal_idty.idty_doc.issuers()[0]); + })?; + Ok(()) +} + +pub fn create_identity( + currency_params: &CurrencyParameters, + identities_db: &BinFileDB<IdentitiesV10Datas>, + ms_db: &BinFileDB<MsExpirV10Datas>, + idty_doc: &IdentityDocument, ms_created_block_id: BlockId, + wot_id: NodeId, + current_blockstamp: Blockstamp, + current_bc_time: u64, ) -> Result<(), DALError> { + let mut idty_doc = idty_doc.clone(); + idty_doc.reduce(); + let idty = DALIdentity { + hash: "0".to_string(), + state: DALIdentityState::Member(vec![0]), + joined_on: current_blockstamp, + expired_on: None, + revoked_on: None, + idty_doc, + wot_id, + ms_created_block_id, + ms_chainable_on: vec![current_bc_time + currency_params.ms_period], + cert_chainable_on: vec![], + }; // Write Identity identities_db.write(|db| { db.insert(idty.idty_doc.issuers()[0], idty.clone()); })?; - // Update IdentitiesV10DB + // Write membership ms_db.write(|db| { let mut memberships = db.get(&ms_created_block_id).cloned().unwrap_or_default(); - memberships.insert(idty_wot_id); + memberships.insert(wot_id); db.insert(ms_created_block_id, memberships); })?; Ok(()) diff --git a/dal/writers/requests.rs b/dal/writers/requests.rs index ef5ca6216a1bf9948080e0e3a60a22b24b4cf29f..0b42b7d24f9d0a3682c94640e6b57827b11cd417 100644 --- a/dal/writers/requests.rs +++ b/dal/writers/requests.rs @@ -4,6 +4,7 @@ extern crate serde_json; use block::DALBlock; use currency_params::CurrencyParameters; use duniter_crypto::keys::PubKey; +use duniter_documents::blockchain::v10::documents::certification::CompactCertificationDocument; use duniter_documents::blockchain::v10::documents::identity::IdentityDocument; use duniter_documents::Blockstamp; use duniter_wotb::NodeId; @@ -12,6 +13,7 @@ use rustbreak::backend::Backend; use sources::SourceAmount; use std::fmt::Debug; use std::ops::Deref; +use writers::transaction::DALTxV10; use *; #[derive(Debug, Clone)] @@ -31,29 +33,40 @@ pub enum BlocksDBsWriteQuery { /// Write block WriteBlock(Box<DALBlock>, Option<ForkId>, PreviousBlockstamp, BlockHash), /// Revert block - RevertBlock(Box<DALBlock>), + RevertBlock(Box<DALBlock>, Option<ForkId>), } impl BlocksDBsWriteQuery { pub fn apply(&self, databases: &BlocksV10DBs, sync: bool) -> Result<(), DALError> { - if let BlocksDBsWriteQuery::WriteBlock( - ref dal_block, - ref old_fork_id, - ref _previous_blockstamp, - ref _block_hash, - ) = *self - { - let dal_block = dal_block.deref(); - trace!("BlocksDBsWriteQuery::WriteBlock..."); - super::block::write( - &databases.blockchain_db, - &databases.forks_db, - &databases.forks_blocks_db, - &dal_block, - *old_fork_id, - sync, - )?; - trace!("BlocksDBsWriteQuery::WriteBlock...finish"); + match *self { + BlocksDBsWriteQuery::WriteBlock(ref dal_block, ref old_fork_id, _, _) => { + let dal_block = dal_block.deref(); + trace!("BlocksDBsWriteQuery::WriteBlock..."); + super::block::write( + &databases.blockchain_db, + &databases.forks_db, + &databases.forks_blocks_db, + &dal_block, + *old_fork_id, + sync, + false, + )?; + trace!("BlocksDBsWriteQuery::WriteBlock...finish"); + } + BlocksDBsWriteQuery::RevertBlock(ref dal_block, ref to_fork_id) => { + let dal_block = dal_block.deref(); + trace!("BlocksDBsWriteQuery::WriteBlock..."); + super::block::write( + &databases.blockchain_db, + &databases.forks_db, + &databases.forks_blocks_db, + &dal_block, + *to_fork_id, + sync, + true, + )?; + trace!("BlocksDBsWriteQuery::WriteBlock...finish"); + } } Ok(()) } @@ -64,16 +77,28 @@ impl BlocksDBsWriteQuery { pub enum WotsDBsWriteQuery { /// Newcomer (wotb_id, blockstamp, current_bc_time, idty_doc, ms_created_block_id) CreateIdentity(NodeId, Blockstamp, u64, Box<IdentityDocument>, BlockId), + /// Revert newcomer event (wotb_id, blockstamp, current_bc_time, idty_doc, ms_created_block_id) + RevertCreateIdentity(PubKey), /// Active (pubKey, idty_wot_id, current_bc_time, ms_created_block_id) RenewalIdentity(PubKey, NodeId, u64, BlockId), + /// Revert active (pubKey, idty_wot_id, current_bc_time, ms_created_block_id) + RevertRenewalIdentity(PubKey, NodeId, u64, BlockId), /// Excluded ExcludeIdentity(PubKey, Blockstamp), + /// Revert exclusion + RevertExcludeIdentity(PubKey, Blockstamp), /// Revoked - RevokeIdentity(PubKey, Blockstamp), + RevokeIdentity(PubKey, Blockstamp, bool), + /// Revert revocation + RevertRevokeIdentity(PubKey, Blockstamp, bool), /// Certification (source_pubkey, source, target, created_block_id, median_time) CreateCert(PubKey, NodeId, NodeId, BlockId, u64), + /// Revert certification (source_pubkey, source, target, created_block_id, median_time) + RevertCert(CompactCertificationDocument, NodeId, NodeId), /// Certification expiry (source, target, created_block_id) ExpireCert(NodeId, NodeId, BlockId), + /// Revert certification expiry event (source, target, created_block_id) + RevertExpireCert(NodeId, NodeId, BlockId), } impl WotsDBsWriteQuery { @@ -90,22 +115,23 @@ impl WotsDBsWriteQuery { ref idty_doc, ref ms_created_block_id, ) => { - trace!("WotsDBsWriteQuery::CreateIdentity..."); - let idty = DALIdentity::create_identity( + writers::identity::create_identity( currency_params, + &databases.identities_db, + &databases.ms_db, idty_doc.deref(), + *ms_created_block_id, *wotb_id, *blockstamp, *current_bc_time, - ); - super::identity::write( - &idty, - *wotb_id, + )?; + } + WotsDBsWriteQuery::RevertCreateIdentity(ref pubkey) => { + writers::identity::revert_create_identity( &databases.identities_db, &databases.ms_db, - *ms_created_block_id, + pubkey, )?; - trace!("WotsDBsWriteQuery::CreateIdentity...finish."); } WotsDBsWriteQuery::RenewalIdentity( ref pubkey, @@ -128,18 +154,49 @@ impl WotsDBsWriteQuery { )?; trace!("DBWrWotsDBsWriteQueryiteRequest::RenewalIdentity..."); } + WotsDBsWriteQuery::RevertRenewalIdentity( + ref pubkey, + ref idty_wot_id, + ref current_bc_time, + ms_created_block_id, + ) => { + let mut idty = DALIdentity::get_identity(&databases.identities_db, pubkey)? + .expect("Fatal error : impossible to renewal an identidy that don't exist !"); + idty.renewal_identity( + currency_params, + &databases.identities_db, + &databases.ms_db, + pubkey, + *idty_wot_id, + *current_bc_time, + ms_created_block_id, + true, + )?; + } WotsDBsWriteQuery::ExcludeIdentity(ref pubkey, ref blockstamp) => { DALIdentity::exclude_identity(&databases.identities_db, pubkey, blockstamp, false)?; } - WotsDBsWriteQuery::RevokeIdentity(ref pubkey, ref blockstamp) => { + WotsDBsWriteQuery::RevertExcludeIdentity(ref pubkey, ref blockstamp) => { + DALIdentity::exclude_identity(&databases.identities_db, pubkey, blockstamp, true)?; + } + WotsDBsWriteQuery::RevokeIdentity(ref pubkey, ref blockstamp, ref explicit) => { DALIdentity::revoke_identity( &databases.identities_db, pubkey, blockstamp, - true, + *explicit, false, )?; } + WotsDBsWriteQuery::RevertRevokeIdentity(ref pubkey, ref blockstamp, ref explicit) => { + DALIdentity::revoke_identity( + &databases.identities_db, + pubkey, + blockstamp, + *explicit, + true, + )?; + } WotsDBsWriteQuery::CreateCert( ref source_pubkey, ref source, @@ -148,7 +205,7 @@ impl WotsDBsWriteQuery { ref median_time, ) => { trace!("WotsDBsWriteQuery::CreateCert..."); - super::certification::write_certification( + writers::certification::write_certification( currency_params, &databases.identities_db, &databases.certs_db, @@ -160,12 +217,37 @@ impl WotsDBsWriteQuery { )?; trace!("WotsDBsWriteQuery::CreateCert...finish"); } + WotsDBsWriteQuery::RevertCert(ref compact_doc, ref source, ref target) => { + trace!("WotsDBsWriteQuery::CreateCert..."); + writers::certification::revert_write_cert( + &databases.identities_db, + &databases.certs_db, + *compact_doc, + *source, + *target, + )?; + trace!("WotsDBsWriteQuery::CreateCert...finish"); + } WotsDBsWriteQuery::ExpireCert(ref _source, ref _target, ref _created_block_id) => { /*super::certification::expire_cert( &databases.certs_db, *source, *target, *created_block_id, + false, + )?;*/ + } + WotsDBsWriteQuery::RevertExpireCert( + ref _source, + ref _target, + ref _created_block_id, + ) => { + /*super::certification::expire_cert( + &databases.certs_db, + *source, + *target, + *created_block_id, + true, )?;*/ } } @@ -178,29 +260,41 @@ impl WotsDBsWriteQuery { pub enum CurrencyDBsWriteQuery { /// Write transaction WriteTx(Box<TransactionDocument>), + /// Revert transaction + RevertTx(Box<DALTxV10>), /// Create dividend CreateDU(SourceAmount, BlockId, Vec<PubKey>), + /// Revert dividend + RevertDU(SourceAmount, BlockId, Vec<PubKey>), } impl CurrencyDBsWriteQuery { pub fn apply<B: Backend + Debug>(&self, databases: &CurrencyV10DBs<B>) -> Result<(), DALError> { match *self { CurrencyDBsWriteQuery::WriteTx(ref tx_doc) => { - super::transaction::apply_and_write_tx::<B>( - &databases.tx_db, - &databases.utxos_db, + super::transaction::apply_and_write_tx::<B>(&databases, tx_doc.deref())?; + } + CurrencyDBsWriteQuery::RevertTx(ref dal_tx) => { + super::transaction::revert_tx::<B>(&databases, dal_tx.deref())?; + } + CurrencyDBsWriteQuery::CreateDU(ref du_amount, ref block_id, ref members) => { + super::dividend::create_du::<B>( &databases.du_db, &databases.balances_db, - tx_doc.deref(), + du_amount, + block_id, + members, + false, )?; } - CurrencyDBsWriteQuery::CreateDU(ref du_amount, ref block_id, ref members) => { + CurrencyDBsWriteQuery::RevertDU(ref du_amount, ref block_id, ref members) => { super::dividend::create_du::<B>( &databases.du_db, &databases.balances_db, du_amount, block_id, members, + true, )?; } } diff --git a/dal/writers/transaction.rs b/dal/writers/transaction.rs index 662dc1712148fb84e5480bf1a184612758c49c88..9aeafafa92f91c95b310435f67d40e82018e4882 100644 --- a/dal/writers/transaction.rs +++ b/dal/writers/transaction.rs @@ -33,15 +33,212 @@ impl From<DALError> for TxError { #[derive(Debug, Clone, Deserialize, Serialize)] pub struct DALTxV10 { - tx_doc: TransactionDocument, - sources_destroyed: HashSet<UTXOIndexV10>, + pub tx_doc: TransactionDocument, + pub sources_destroyed: HashSet<UTXOIndexV10>, +} + +pub fn revert_tx<B: Backend + Debug>( + dbs: &CurrencyV10DBs<B>, + dal_tx: &DALTxV10, +) -> Result<(), DALError> { + let mut tx_doc = dal_tx.tx_doc.clone(); + let tx_hash = tx_doc.get_hash(); + let sources_destroyed = &dal_tx.sources_destroyed; + + // Index consumed utxos + let consumed_utxos: Vec<UTXOV10> = tx_doc + .get_outputs() + .iter() + .enumerate() + .map(|(tx_index, output)| UTXOV10(UTXOIndexV10(tx_hash, TxIndex(tx_index)), output.clone())) + .collect(); + // Recalculate balance of consumed adress + let new_balances_consumed_adress = dbs.balances_db.read(|db| { + let mut new_balances_consumed_adress: HashMap< + TransactionOutputConditionGroup, + (SourceAmount, HashSet<UTXOIndexV10>), + > = HashMap::new(); + for source in &consumed_utxos { + let source_amount = source.get_amount(); + let conditions = source.get_conditions(); + let (balance, new_sources_index) = if let Some((balance, sources_index)) = + new_balances_consumed_adress.get(&conditions) + { + let mut new_sources_index = sources_index.clone(); + new_sources_index.remove(&source.0); + (*balance, new_sources_index) + } else if let Some((balance, sources_index)) = db.get(&conditions) { + let mut new_sources_index = sources_index.clone(); + new_sources_index.remove(&source.0); + (*balance, new_sources_index) + } else { + panic!("Fail to revert tx : an output conditions don't exist in BalancesDB.") + }; + let new_balance = if balance >= source_amount { + balance - source_amount + } else { + panic!("Fail to revert tx : an output revert cause negative balance.") + }; + new_balances_consumed_adress.insert(conditions, (new_balance, new_sources_index)); + } + new_balances_consumed_adress + })?; + // Remove consumed UTXOs + dbs.utxos_db.write(|db| { + for utxo_v10 in consumed_utxos { + db.remove(&utxo_v10.0); + } + })?; + // Write new balance of consumed adress + dbs.balances_db.write(|db| { + for (conditions, (balance, sources_index)) in new_balances_consumed_adress { + db.insert(conditions, (balance, sources_index)); + } + })?; + // Complete sources_destroyed + let sources_destroyed: HashMap< + TransactionOutputConditionGroup, + Vec<(UTXOIndexV10, SourceAmount)>, + > = if !sources_destroyed.is_empty() { + dbs.tx_db.read(|db| { + let mut sources_destroyed_completed = HashMap::new(); + for s_index in sources_destroyed { + let tx_output = db + .get(&s_index.0) + .expect("Not find tx") + .tx_doc + .get_outputs()[(s_index.1).0] + .clone(); + let mut sources_destroyed_for_same_address: Vec<( + UTXOIndexV10, + SourceAmount, + )> = sources_destroyed_completed + .get(&tx_output.conditions) + .cloned() + .unwrap_or_default(); + sources_destroyed_for_same_address + .push((*s_index, SourceAmount(tx_output.amount, tx_output.base))); + sources_destroyed_completed + .insert(tx_output.conditions, sources_destroyed_for_same_address); + } + sources_destroyed_completed + })? + } else { + HashMap::with_capacity(0) + }; + // Index recreated sources + let recreated_sources: HashMap<SourceIndexV10, SourceAmount> = tx_doc + .get_inputs() + .iter() + .map(|input| match *input { + TransactionInput::D(tx_amout, tx_amout_base, pubkey, block_id) => ( + SourceIndexV10::DU(pubkey, block_id), + SourceAmount(tx_amout, tx_amout_base), + ), + TransactionInput::T(tx_amout, tx_amout_base, hash, tx_index) => ( + SourceIndexV10::UTXO(UTXOIndexV10(hash, tx_index)), + SourceAmount(tx_amout, tx_amout_base), + ), + }) + .collect(); + // Find adress of recreated sources + let recreated_adress: HashMap< + TransactionOutputConditionGroup, + (SourceAmount, HashSet<UTXOIndexV10>), + > = dbs.utxos_db.read(|db| { + let mut recreated_adress: HashMap< + TransactionOutputConditionGroup, + (SourceAmount, HashSet<UTXOIndexV10>), + > = HashMap::new(); + for (source_index, source_amount) in &recreated_sources { + if let SourceIndexV10::UTXO(utxo_index) = source_index { + // Get utxo + let utxo = db + .get(&utxo_index) + .expect("ApplyBLockError : unknow UTXO in inputs !"); + // Get utxo conditions(=address) + let conditions = &utxo.conditions; + // Calculate new balances datas for "conditions" address + let (mut balance, mut utxos_index) = recreated_adress + .get(conditions) + .cloned() + .unwrap_or_default(); + balance = balance + *source_amount; + utxos_index.insert(*utxo_index); + // Write new balances datas for "conditions" address + recreated_adress.insert(conditions.clone(), (balance, utxos_index)); + } else if let SourceIndexV10::DU(pubkey, _block_id) = source_index { + let address = TransactionOutputConditionGroup::Single( + TransactionOutputCondition::Sig(*pubkey), + ); + let (mut balance, utxos_index) = + recreated_adress.get(&address).cloned().unwrap_or_default(); + balance = balance + *source_amount; + recreated_adress.insert(address, (balance, utxos_index)); + } + } + recreated_adress + })?; + // Recalculate balance of recreated adress + let new_balances_recreated_adress = dbs.balances_db.read(|db| { + let mut new_balances_recreated_adress = Vec::new(); + for (conditions, (amount_recreated, adress_recreated_sources)) in recreated_adress { + let (mut balance, mut sources_indexs) = + if let Some((balance, sources_indexs)) = db.get(&conditions) { + (*balance, sources_indexs.clone()) + } else { + (SourceAmount::default(), HashSet::new()) + }; + // Apply recreated sources (inputs) + balance = balance + amount_recreated; + for s_index in adress_recreated_sources { + sources_indexs.insert(s_index); + } + // Recreate destroy sources + if let Some(address_sources_destroyed) = sources_destroyed.get(&conditions) { + for (utxo_index, s_amout) in address_sources_destroyed { + balance = balance + *s_amout; + sources_indexs.insert(*utxo_index); + } + } + new_balances_recreated_adress.push((conditions.clone(), (balance, sources_indexs))); + } + new_balances_recreated_adress + })?; + // Write new balance of recreated adress + dbs.balances_db.write(|db| { + for (conditions, (balance, sources_index)) in new_balances_recreated_adress { + db.insert(conditions, (balance, sources_index)); + } + })?; + // Recreate recreated sources + for s_index in recreated_sources.keys() { + if let SourceIndexV10::UTXO(utxo_index) = s_index { + let utxo_content = dbs.tx_db.read(|db| { + db.get(&utxo_index.0) + .expect("Fatal error : not found Source TX of this utxo !") + .tx_doc + .get_outputs()[(utxo_index.1).0] + .clone() + })?; + dbs.utxos_db.write(|db| { + db.insert(*utxo_index, utxo_content); + })?; + } else if let SourceIndexV10::DU(pubkey, block_id) = s_index { + let mut pubkey_dus: HashSet<BlockId> = dbs + .du_db + .read(|db| db.get(&pubkey).cloned().unwrap_or_default())?; + pubkey_dus.insert(*block_id); + dbs.du_db.write(|db| { + db.insert(*pubkey, pubkey_dus); + })?; + } + } + Ok(()) } pub fn apply_and_write_tx<B: Backend + Debug>( - tx_db: &BinDB<TxV10Datas, B>, - utxos_db: &BinDB<UTXOsV10Datas, B>, - dus_db: &BinDB<DUsV10Datas, B>, - balances_db: &BinDB<BalancesV10Datas, B>, + dbs: &CurrencyV10DBs<B>, tx_doc: &TransactionDocument, ) -> Result<(), DALError> { let mut tx_doc = tx_doc.clone(); @@ -66,7 +263,7 @@ pub fn apply_and_write_tx<B: Backend + Debug>( let consumed_adress: HashMap< TransactionOutputConditionGroup, (SourceAmount, HashSet<UTXOIndexV10>), - > = utxos_db.read(|db| { + > = dbs.utxos_db.read(|db| { let mut consumed_adress: HashMap< TransactionOutputConditionGroup, (SourceAmount, HashSet<UTXOIndexV10>), @@ -99,7 +296,7 @@ pub fn apply_and_write_tx<B: Backend + Debug>( consumed_adress })?; // Recalculate balance of consumed adress - let new_balances_consumed_adress = balances_db.read(|db| { + let new_balances_consumed_adress = dbs.balances_db.read(|db| { let mut new_balances_consumed_adress = Vec::new(); for (conditions, (amount_consumed, adress_consumed_sources)) in consumed_adress { if let Some((balance, sources)) = db.get(&conditions) { @@ -121,7 +318,7 @@ pub fn apply_and_write_tx<B: Backend + Debug>( new_balances_consumed_adress })?; // Write new balance of consumed adress - balances_db.write(|db| { + dbs.balances_db.write(|db| { for (conditions, (balance, sources_index)) in new_balances_consumed_adress { db.insert(conditions, (balance, sources_index)); } @@ -129,14 +326,15 @@ pub fn apply_and_write_tx<B: Backend + Debug>( // Remove consumed sources for source_index in consumed_sources.keys() { if let SourceIndexV10::UTXO(utxo_index) = source_index { - utxos_db.write(|db| { + dbs.utxos_db.write(|db| { db.remove(utxo_index); })?; } else if let SourceIndexV10::DU(pubkey, block_id) = source_index { - let mut pubkey_dus: HashSet<BlockId> = - dus_db.read(|db| db.get(&pubkey).cloned().unwrap_or_default())?; + let mut pubkey_dus: HashSet<BlockId> = dbs + .du_db + .read(|db| db.get(&pubkey).cloned().unwrap_or_default())?; pubkey_dus.remove(block_id); - dus_db.write(|db| { + dbs.du_db.write(|db| { db.insert(*pubkey, pubkey_dus); })?; } @@ -158,7 +356,7 @@ pub fn apply_and_write_tx<B: Backend + Debug>( .map(|(tx_index, output)| UTXOV10(UTXOIndexV10(tx_hash, TxIndex(tx_index)), output.clone())) .collect(); // Recalculate balance of supplied adress - let new_balances_supplied_adress = balances_db.read(|db| { + let new_balances_supplied_adress = dbs.balances_db.read(|db| { let mut new_balances_supplied_adress: HashMap< TransactionOutputConditionGroup, (SourceAmount, HashSet<UTXOIndexV10>), @@ -187,20 +385,20 @@ pub fn apply_and_write_tx<B: Backend + Debug>( new_balances_supplied_adress })?; // Insert created UTXOs - utxos_db.write(|db| { + dbs.utxos_db.write(|db| { for utxo_v10 in created_utxos { db.insert(utxo_v10.0, utxo_v10.1); } })?; // Write new balance of supplied adress - balances_db.write(|db| { + dbs.balances_db.write(|db| { for (conditions, (balance, sources_index)) in new_balances_supplied_adress { db.insert(conditions, (balance, sources_index)); } })?; // Write tx tx_doc.reduce(); - tx_db.write(|db| { + dbs.tx_db.write(|db| { db.insert( tx_hash, DALTxV10 { @@ -256,7 +454,7 @@ mod tests { } #[test] - fn apply_one_tx() { + fn apply_and_revert_one_tx() { // Get document of first g1 transaction let tx_doc = build_first_tx_of_g1(); assert_eq!(tx_doc.verify_signatures(), VerificationResult::Valid()); @@ -274,6 +472,7 @@ mod tests { &SourceAmount(TxAmount(1000), TxBase(0)), &BlockId(1), &vec![tx_doc.issuers()[0], tortue_pubkey], + false, ).expect("Fail to create first g1 DU !"); // Check members balance let cgeek_new_balance = currency_dbs @@ -300,13 +499,7 @@ mod tests { SourceAmount(TxAmount(1000), TxBase(0)) ); // Apply first g1 transaction - apply_and_write_tx( - ¤cy_dbs.tx_db, - ¤cy_dbs.utxos_db, - ¤cy_dbs.du_db, - ¤cy_dbs.balances_db, - &tx_doc, - ).expect("Fail to apply first g1 tx"); + apply_and_write_tx(¤cy_dbs, &tx_doc).expect("Fail to apply first g1 tx"); // Check issuer new balance let cgeek_new_balance = currency_dbs .balances_db @@ -333,5 +526,41 @@ mod tests { receiver_new_balance.0, SourceAmount(TxAmount(1001), TxBase(0)) ); + + // Revert first g1 tx + revert_tx( + ¤cy_dbs, + &DALTxV10 { + tx_doc: tx_doc.clone(), + sources_destroyed: HashSet::with_capacity(0), + }, + ).expect("Fail to revert first g1 tx"); + + // Check issuer new balance + let cgeek_new_balance = currency_dbs + .balances_db + .read(|db| { + db.get(&TransactionOutputConditionGroup::Single( + TransactionOutputCondition::Sig(tx_doc.issuers()[0]), + )).cloned() + }) + .expect("Fail to read cgeek new balance") + .expect("Error : cgeek is not referenced in balances_db !"); + assert_eq!(cgeek_new_balance.0, SourceAmount(TxAmount(1000), TxBase(0))); + + // Check receiver new balance + let receiver_new_balance = currency_dbs + .balances_db + .read(|db| { + db.get(&TransactionOutputConditionGroup::Single( + TransactionOutputCondition::Sig(tortue_pubkey), + )).cloned() + }) + .expect("Fail to read receiver new balance") + .expect("Error : receiver is not referenced in balances_db !"); + assert_eq!( + receiver_new_balance.0, + SourceAmount(TxAmount(1000), TxBase(0)) + ); } } diff --git a/documents/blockchain/v10/documents/block.rs b/documents/blockchain/v10/documents/block.rs index 5cc23ba33cddede3460126e7457a694bee571d9d..1968890f733498c6208d04b2c1fcc42fb7789fe2 100644 --- a/documents/blockchain/v10/documents/block.rs +++ b/documents/blockchain/v10/documents/block.rs @@ -34,6 +34,12 @@ use {BlockHash, BlockId, Blockstamp, Hash}; #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct CurrencyName(pub String); +impl Default for CurrencyName { + fn default() -> CurrencyName { + CurrencyName(String::from("default_currency")) + } +} + impl Display for CurrencyName { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { write!(f, "{}", self.0) diff --git a/documents/blockchain/v10/documents/transaction.rs b/documents/blockchain/v10/documents/transaction.rs index aa6ddacd9db91975ccd1a4d803bf1fe2e9cbe62a..12388f01f17ab4a91a555ce5ca211471d7285260 100644 --- a/documents/blockchain/v10/documents/transaction.rs +++ b/documents/blockchain/v10/documents/transaction.rs @@ -75,7 +75,7 @@ impl Sub for TxAmount { } /// Wrap a transaction amout base -#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Hash, Serialize)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Deserialize, Hash, Serialize)] pub struct TxBase(pub usize); /// Wrap a transaction index diff --git a/documents/lib.rs b/documents/lib.rs index f39b5f5db3d16f2a8cf5336fcedc2939dd6ed6e3..4d006cb654eeb7ff909a09f3cd88c318d01bc6bc 100644 --- a/documents/lib.rs +++ b/documents/lib.rs @@ -43,7 +43,7 @@ use std::fmt::{Debug, Display, Error, Formatter}; pub mod blockchain; /// A block Id. -#[derive(Debug, Deserialize, Copy, Clone, Ord, PartialEq, PartialOrd, Eq, Hash, Serialize)] +#[derive(Copy, Clone, Debug, Deserialize, Ord, PartialEq, PartialOrd, Eq, Hash, Serialize)] pub struct BlockId(pub u32); impl Display for BlockId { diff --git a/src/main.rs b/src/main.rs index c9e127fb73aeea7c141dcba4ecfa7250f1f68531..d8e7d606e6bacb619f58c9ba45988f829ec32c46 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,10 +24,12 @@ extern crate duniter_core; extern crate duniter_tui; +#[cfg(feature = "ws2p")] extern crate duniter_ws2p; pub use duniter_core::DuniterCore; pub use duniter_tui::TuiModule; +#[cfg(feature = "ws2p")] pub use duniter_ws2p::WS2PModule; /// Main function @@ -38,13 +40,21 @@ fn main() { // Run duniter core if let Some(mut duniter_core) = DuniterCore::new(soft_name, soft_version) { - duniter_core.plug::<WS2PModule>(); - duniter_core.plug::<TuiModule>(); - //duniter_core.plug::<PoolModule>(); - //duniter_core.plug::<PowModule>(); - //duniter_core.plug::<GvaModule>(); //duniter_core.plug::<DasaModule>(); //duniter_core.plug::<GuiModule>(); + //duniter_core.plug::<GvaModule>(); + //duniter_core.plug::<PoolModule>(); + //duniter_core.plug::<PowModule>(); + duniter_core.plug::<TuiModule>(); + plug_ws2p_module(&mut duniter_core); duniter_core.start_blockchain(); }; } + +/// Plug WS2P Module +#[cfg(feature = "ws2p")] +fn plug_ws2p_module(duniter_core: &mut DuniterCore) { + duniter_core.plug::<WS2PModule>(); +} +#[cfg(not(feature = "ws2p"))] +fn plug_ws2p_module(_duniter_core: &mut DuniterCore) {} diff --git a/wotb/data/mod.rs b/wotb/data/mod.rs index fe6beec488891f4a6943b0b87a2fc92b58db9b88..e88b69337c1da0c2a0b9a9fa5d2e8652e74d1c52 100644 --- a/wotb/data/mod.rs +++ b/wotb/data/mod.rs @@ -19,14 +19,68 @@ pub mod rusty; -use serde::de::DeserializeOwned; -use serde::Serialize; -use std::fmt::Debug; +use serde::de::{self, Deserialize, DeserializeOwned, Deserializer, Visitor}; +use serde::{Serialize, Serializer}; +use std::fmt::{self, Debug}; /// Wrapper for a node id. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct NodeId(pub usize); +impl Serialize for NodeId { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.serialize_u32(self.0 as u32) + } +} + +struct NodeIdVisitor; + +impl<'de> Visitor<'de> for NodeIdVisitor { + type Value = NodeId; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an integer between -2^31 and 2^31") + } + + fn visit_u8<E>(self, value: u8) -> Result<NodeId, E> + where + E: de::Error, + { + Ok(NodeId(value as usize)) + } + + fn visit_u32<E>(self, value: u32) -> Result<NodeId, E> + where + E: de::Error, + { + Ok(NodeId(value as usize)) + } + + fn visit_u64<E>(self, value: u64) -> Result<NodeId, E> + where + E: de::Error, + { + use std::usize; + if value >= usize::MIN as u64 && value <= usize::MAX as u64 { + Ok(NodeId(value as usize)) + } else { + Err(E::custom(format!("u32 out of range: {}", value))) + } + } +} + +impl<'de> Deserialize<'de> for NodeId { + fn deserialize<D>(deserializer: D) -> Result<NodeId, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_u32(NodeIdVisitor) + } +} + /// Results of a certification, with the current certification count /// of the destination as parameter. #[derive(Debug, Copy, Clone, PartialEq, Eq)]