From e615e318878cdbaa66f706f877c482281ed3b4fa Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Thu, 2 Jun 2022 17:53:42 +0000 Subject: [PATCH 01/45] downgrade error msg to info --- state-sync/src/request_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state-sync/src/request_manager.rs b/state-sync/src/request_manager.rs index 2370a5ad16..e605f56828 100644 --- a/state-sync/src/request_manager.rs +++ b/state-sync/src/request_manager.rs @@ -208,7 +208,7 @@ impl RequestManager { ]) .observe(*score); - error!("update peer score: {:?} with update_type {:?}, old score: {:?}, new score: {:?}", &peer, &update_type, &old_score, &score); + info!("update peer score: {:?} with update_type {:?}, old score: {:?}, new score: {:?}", &peer, &update_type, &old_score, &score); } } From 6d81c530f7d8389b25419d5b03fc84776726a8ad Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Tue, 7 Jun 2022 13:19:28 -0400 Subject: [PATCH 02/45] cleanup unused prometheus log code --- state-sync/src/counters.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/state-sync/src/counters.rs b/state-sync/src/counters.rs index adfe2725f6..ff614258f8 100644 --- a/state-sync/src/counters.rs +++ b/state-sync/src/counters.rs @@ -433,15 +433,6 @@ pub static STATE_SYNC_VERSION_REQUEST_TIMEOUT: Lazy = Lazy::new(| .unwrap() }); -pub static STATE_SYNC_ADDING_VALIDATOR_TO_STATE_SYNC: Lazy = Lazy::new(|| { - register_int_counter_vec!( - "diem_state_sync_adding_validator_to_state_sync", - "Number of times sync state added a validator to state sync", - &["network", "peer"] - ) - .unwrap() -}); - pub static STATE_SYNC_LOST_PEER: Lazy = Lazy::new(|| { register_int_counter_vec!( "diem_state_sync_lost_peer", From 92f4e6467715f19fb87837fe273d7b515606bf7d Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Fri, 10 Jun 2022 14:22:44 -0400 Subject: [PATCH 03/45] downgrade state sync error message to info --- state-sync/src/coordinator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state-sync/src/coordinator.rs b/state-sync/src/coordinator.rs index c9da18e46c..9fa3c91009 100644 --- a/state-sync/src/coordinator.rs +++ b/state-sync/src/coordinator.rs @@ -220,7 +220,7 @@ impl StateSyncCoordinator { } Event::Message(peer_id, message) => { if let Err(e) = self.process_chunk_message(network_id.clone(), peer_id, message).await { - error!(LogSchema::new(LogEntry::ProcessChunkMessage).error(&e)); + info!(LogSchema::new(LogEntry::ProcessChunkMessage).error(&e)); } } unexpected_event => { From 74440f751765c94b52bf83f0ba76bc7108ebc682 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Fri, 10 Jun 2022 18:19:20 -0400 Subject: [PATCH 04/45] makefile for set-waypoint --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 814773f8ab..5b5fddbc8b 100644 --- a/Makefile +++ b/Makefile @@ -413,6 +413,8 @@ set-waypoint: jq -r '. | with_entries(select(.key|match("-oper/genesis-waypoint";"i")))[].value' ${DATA_PATH}/key_store.json > ${DATA_PATH}/genesis_waypoint; \ fi + cargo r -p ol -- init --update-waypoint --waypoint $(shell echo ${DATA_PATH}/client_waypoint) + @echo client_waypoint: @cat ${DATA_PATH}/client_waypoint From decdc27e10544c1eec0456e2ff401bb00a25a018 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Fri, 10 Jun 2022 18:23:30 -0400 Subject: [PATCH 05/45] patch makefile --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5b5fddbc8b..095729e903 100644 --- a/Makefile +++ b/Makefile @@ -413,7 +413,7 @@ set-waypoint: jq -r '. | with_entries(select(.key|match("-oper/genesis-waypoint";"i")))[].value' ${DATA_PATH}/key_store.json > ${DATA_PATH}/genesis_waypoint; \ fi - cargo r -p ol -- init --update-waypoint --waypoint $(shell echo ${DATA_PATH}/client_waypoint) + cargo r -p ol -- init --update-waypoint --waypoint $(shell cat ${DATA_PATH}/client_waypoint) @echo client_waypoint: @cat ${DATA_PATH}/client_waypoint @@ -568,6 +568,6 @@ fork-config: cargo run -p onboard -- fork -u http://167.172.248.37 --prebuilt-genesis ${DATA_PATH}/genesis_from_snapshot.blob # start node from files -fork-start: +fork-start: rm -rf ~/.0L/db cargo run -p libra-node -- --config ~/.0L/validator.node.yaml From 1d668e9e5ba8e563b6e81dff4c59693818d379f6 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Sat, 11 Jun 2022 22:10:47 +0000 Subject: [PATCH 06/45] refresh onchain state --- ol/cli/src/commands/init_cmd.rs | 2 +- ol/cli/src/node/refresh_peers.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ol/cli/src/commands/init_cmd.rs b/ol/cli/src/commands/init_cmd.rs index 4d4097cb4c..62708c4cd8 100644 --- a/ol/cli/src/commands/init_cmd.rs +++ b/ol/cli/src/commands/init_cmd.rs @@ -163,7 +163,7 @@ impl Runnable for InitCmd { }; let mut node = Node::new(client, &app_cfg, is_swarm); - + match node.refresh_fullnode_seeds() { Ok(s) => { match serde_yaml::to_string(&s) { diff --git a/ol/cli/src/node/refresh_peers.rs b/ol/cli/src/node/refresh_peers.rs index 789f9c27f2..e9510a8ffe 100644 --- a/ol/cli/src/node/refresh_peers.rs +++ b/ol/cli/src/node/refresh_peers.rs @@ -15,6 +15,7 @@ impl Node { pub fn refresh_fullnode_seeds(&mut self) -> Result { let mut seed_addr = SeedAddresses::default(); + self.refresh_onchain_state(); if let Some(account_state) = &self.chain_state { match account_state.get_validator_set() { Ok(Some(v)) => { From 33492d54474de3bcd889faa3420583e19225ebe9 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Sat, 11 Jun 2022 22:30:08 +0000 Subject: [PATCH 07/45] genesis should assign vouches --- language/tools/vm-genesis/src/lib.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/language/tools/vm-genesis/src/lib.rs b/language/tools/vm-genesis/src/lib.rs index c71375e9a8..7f0e86272c 100644 --- a/language/tools/vm-genesis/src/lib.rs +++ b/language/tools/vm-genesis/src/lib.rs @@ -487,6 +487,13 @@ fn create_and_initialize_owners_operators( // prefix || address. Because of this, the initial auth key will be invalid as we produce the // account address from the name and not the public key. // println!("0 ======== Create Owner Accounts"); + + let all_vals: Vec = operator_registrations.iter() + .map(|a|{ + a.3 + }) + .collect(); + for (owner_key, owner_name, _op_assignment, genesis_proof, _operator) in operator_assignments { // TODO: Remove. Temporary Authkey for genesis, because accounts are being created from human names. let staged_owner_auth_key = AuthenticationKey::ed25519(owner_key.as_ref().unwrap()); @@ -586,6 +593,21 @@ fn create_and_initialize_owners_operators( MoveValue::Signer(owner_address), ]), ); + + let mut vals = all_vals.clone(); + vals.retain(|el|{ el != &owner_address}); + exec_function( + session, + log_context, + "Vouch", + "vm_migrate", + vec![], + serialize_values(&vec![ + MoveValue::Signer(diem_root_address), + MoveValue::Address(owner_address), + MoveValue::vector_address(vals), + ]), + ); } // println!("1 ======== Create OP Accounts"); From e7ab9fb935a47920c7f1f6a11369bdf9713d1174 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Sat, 11 Jun 2022 22:58:57 +0000 Subject: [PATCH 08/45] set layout for devnet has 4 nodes --- ol/devnet/genesis/previous/genesis.blob | Bin 126014 -> 138440 bytes ol/devnet/genesis/previous/genesis_waypoint | 2 +- .../genesis/previous/genesis_waypoint.txt | 1 + ol/devnet/set_layout_test.toml | 2 ++ 4 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 ol/devnet/genesis/previous/genesis_waypoint.txt diff --git a/ol/devnet/genesis/previous/genesis.blob b/ol/devnet/genesis/previous/genesis.blob index da28e4f166fc4ce832146d2136f43ece92d30861..41f592124eef616bee71665b2a1e176673c97989 100644 GIT binary patch delta 35463 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 B>U{tJ delta 24016 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 diff --git a/ol/devnet/genesis/previous/genesis_waypoint b/ol/devnet/genesis/previous/genesis_waypoint index 5a05e382c2..0339cf5eef 100644 --- a/ol/devnet/genesis/previous/genesis_waypoint +++ b/ol/devnet/genesis/previous/genesis_waypoint @@ -1 +1 @@ -0:afaa4067e6511b22207c13bbdc272804be2693b444127b16d517c4d155e766d8 +0:58023dd8eaa99905ba51060a7d7c983ebb79ffb44af234d3815c3aac60fd461f diff --git a/ol/devnet/genesis/previous/genesis_waypoint.txt b/ol/devnet/genesis/previous/genesis_waypoint.txt new file mode 100644 index 0000000000..0b8deffc74 --- /dev/null +++ b/ol/devnet/genesis/previous/genesis_waypoint.txt @@ -0,0 +1 @@ +0:683185844ef67e5c8eeaa158e635de2a4c574ce7bbb7f41f787d38db2d623ae2 \ No newline at end of file diff --git a/ol/devnet/set_layout_test.toml b/ol/devnet/set_layout_test.toml index 19256cc1cc..df47b489dd 100644 --- a/ol/devnet/set_layout_test.toml +++ b/ol/devnet/set_layout_test.toml @@ -2,9 +2,11 @@ owners = [ "4c613c2f4b1e67ca8d98a542ee3f59f5", "88e74dfed34420f2ad8032148280a84b", "e660402d586ad220ed9beff47d662d54", + "9e6bb3a75e9618fba057e86e69338c94" ] operators = [ "4c613c2f4b1e67ca8d98a542ee3f59f5-oper", "88e74dfed34420f2ad8032148280a84b-oper", "e660402d586ad220ed9beff47d662d54-oper", + "9e6bb3a75e9618fba057e86e69338c94-oper" ] From 857e96ce9af1e9b9aa4be1c3618ff3de3fd32216 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Sat, 11 Jun 2022 23:06:57 +0000 Subject: [PATCH 09/45] init val in genesis first --- language/tools/vm-genesis/src/lib.rs | 11 +++++++++++ ol/devnet/genesis/previous/genesis.blob | Bin 138440 -> 141254 bytes ol/devnet/genesis/previous/genesis_waypoint | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/language/tools/vm-genesis/src/lib.rs b/language/tools/vm-genesis/src/lib.rs index 7f0e86272c..061e18e52e 100644 --- a/language/tools/vm-genesis/src/lib.rs +++ b/language/tools/vm-genesis/src/lib.rs @@ -594,6 +594,17 @@ fn create_and_initialize_owners_operators( ]), ); + exec_function( + session, + log_context, + "Vouch", + "init", + vec![], + serialize_values(&vec![ + MoveValue::Signer(owner_address) + ]), + ); + let mut vals = all_vals.clone(); vals.retain(|el|{ el != &owner_address}); exec_function( diff --git a/ol/devnet/genesis/previous/genesis.blob b/ol/devnet/genesis/previous/genesis.blob index 41f592124eef616bee71665b2a1e176673c97989..9ec2a8cb0dbc44a1af8cf8af96187964a1324194 100644 GIT binary patch delta 1754 zcmX@HljGQV4rWG%s~efGF)=eF&!5c5DmnQplN2M%W&vh5Mn=x*g5pdHlQ%F6Om1Kk znjXN}xHkJ-XCP$XZ4r~Sj^RhQDkDDg(dqMb%yiDVsDVqz}%o$mJu`;l1 zUd?XBRF5vt$N&KftOjWtdfiR-cX!O@D$~5}J0o$K@NW)2iOa{6`Dce)&i8?-1gp0@ zk+o~m!$~;@PGzjTAUDO{J96%k9gge}^>W2pj@WR~3gm2)c(%M?Zi>>i!`P*fBcHasADdOGBa^tNKI{Ia#OWTHA_k| zPBb@7wKOxdNJ~mIFf~uLFiSPFG&Z(KwlvYrFGww#E+@dGG;xE%_Bq^4M_4dYJtWN0 z(>f%~F9-m`99?QUILv3|DNgq2oVZQ*Qn&jx-V4^~su&3ipoclS4p@l7!yHM095~0q zR3J%!#Wlex<^vCt9H#3xfT9Ck13G_t0SA)>rrv$LOuB^if};|{L|{~EVVYRS$z-h1 zQR|%QV)1vZ$v|S%kAF zO2AtdF<|681wu&{J>0hI2{2i(GK(=tOkT*WFuhiSNf1(;*NHKSZr?4+w1E*bRQbh$ z*=DXdlhyQWaVDeboDx9Rbr1`von!h}Q6S4%f=Oz+q&SlVBggc2qD+=T=sA*wVX^?T z#&)2NFsAAHl1vhl_lR>$KPv{bKS7d79n(@q87Av#l1%#BFH12kWSkx+jV0Gk2P*Qw P)Ot>uNqTyT3{waIuLo|A delta 262 zcmX?hp5w$$4rWG%LmQc|F|jyweP^8P$Sg7a0~ZtP3SSYf}6LobTBd*GEa73GuYg~X3og6hlPQ8dLajs#OBNFN=%cp zm<2W;=Gw}`T*3fWG`Ubve0q;O6W8QQLH@}f#FZw?Nu)9|Pp_9}5{FV?nGMW>lP^nX z!i=_))Q4Hqyk2VidMUT8CL1BA5KhqJG?V6HIY^;oe+YRKHSeT|SP+&5e qo~FQLHJwKh$hrh#RVXq^O_pF**e<8U6vnjOO_gaO Date: Mon, 13 Jun 2022 18:01:34 -0400 Subject: [PATCH 10/45] github repo tools can put file in genesis repo --- Cargo.lock | 1 + config/management/genesis/Cargo.toml | 1 + .../management/genesis/src/ol_create_repo.rs | 22 ++++++++++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 0e37b37771..c1a78f56b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1995,6 +1995,7 @@ name = "diem-genesis-tool" version = "0.1.0" dependencies = [ "anyhow", + "base64 0.13.0", "bcs", "consensus-types", "diem-config", diff --git a/config/management/genesis/Cargo.toml b/config/management/genesis/Cargo.toml index f455878ea2..a14534161b 100644 --- a/config/management/genesis/Cargo.toml +++ b/config/management/genesis/Cargo.toml @@ -47,6 +47,7 @@ serde_json = "1" diem-github-client = { path = "../../../secure/storage/github" } ol-types = {path = "../../../ol/types"} serde_yaml = "0.8.17" +base64 = "0.13.0" [dev-dependencies] diem-config = { path = "../..", features = ["fuzzing"]} diff --git a/config/management/genesis/src/ol_create_repo.rs b/config/management/genesis/src/ol_create_repo.rs index dff5506161..d78434b633 100644 --- a/config/management/genesis/src/ol_create_repo.rs +++ b/config/management/genesis/src/ol_create_repo.rs @@ -3,8 +3,9 @@ use diem_github_client::Client; use diem_management::{config::ConfigPath, error::Error, secure_backend::SharedBackend}; -use std::process::exit; +use std::{process::exit, path::PathBuf, fs::File}; use structopt::StructOpt; +use std::io::prelude::*; /// Note, it is implicitly expected that the storage supports /// a namespace but one has not been set. @@ -24,6 +25,8 @@ pub struct CreateGenesisRepo { pub pull_request_user: Option, #[structopt(long)] pub delete_repo_user: Option, + #[structopt(long)] + pub publish_genesis: Option, } impl CreateGenesisRepo { @@ -47,6 +50,23 @@ impl CreateGenesisRepo { .read_token() .expect("could not get github token"), ); + + if let Some(p) = self.publish_genesis { + + + let mut file = File::open(&p) + .expect("cannot read file"); + + let mut bytes = Vec::new(); + file.read_to_end(&mut bytes).expect("could not read file"); + let base64_encoded = base64::encode(bytes); + + let repo_file_path = format!("/genesis/{}", p.file_name().unwrap().to_str().unwrap()); + + github.put(&repo_file_path, &base64_encoded).expect("could not put file in github repo"); + + return Ok("published genesis.blob and genesis_waypoint.txt to genesis repo.".to_string()); + } // Make a pull request of the the forked repo, back to the genesis coordination repository. if let Some(user) = self.pull_request_user { match github.make_genesis_pull_request(&config.repository_owner, &config.repository, &user) { From cae4f3b1c10512f96b89632df075593b8c1eeffc Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Mon, 13 Jun 2022 22:32:05 +0000 Subject: [PATCH 11/45] save files to genesis repo --- Makefile | 11 ++++++++--- config/management/genesis/src/ol_create_repo.rs | 15 ++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 095729e903..dcde51e1ea 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ endif # Registration params REMOTE = 'backend=github;repository_owner=${GITHUB_USER};repository=${REPO_NAME};token=${DATA_PATH}/github_token.txt;namespace=${ACC}' -GENESIS_REMOTE = 'backend=github;repository_owner=${REPO_ORG};repository=${REPO_NAME};token=${DATA_PATH}/github_token.txt;namespace=${ACC}' +GENESIS_REMOTE = 'backend=github;repository_owner=${REPO_ORG};repository=${REPO_NAME};token=${DATA_PATH}/github_token.txt;namespace=${ACC};branch=master' LOCAL = 'backend=disk;path=${DATA_PATH}/key_store.json;namespace=${ACC}' @@ -490,8 +490,13 @@ dev-genesis: genesis dev-save-genesis fix-genesis dev-infra: dev-backup-archive dev-commit dev-save-genesis: set-waypoint - rsync -a ${DATA_PATH}/genesis* ${SOURCE}/ol/devnet/genesis/${V}/ - git add ${SOURCE}/ol/devnet/genesis/${V}/ + cargo run -p diem-genesis-tool ${CARGO_ARGS} -- create-repo \ + --publish-genesis ${DATA_PATH}/genesis.blob \ + --shared-backend ${GENESIS_REMOTE} + + cargo run -p diem-genesis-tool ${CARGO_ARGS} -- create-repo \ + --publish-genesis ${DATA_PATH}/genesis_waypoint.txt \ + --shared-backend ${GENESIS_REMOTE} dev-backup-archive: cd ${HOME}/dev-epoch-archive && make devnet-backup diff --git a/config/management/genesis/src/ol_create_repo.rs b/config/management/genesis/src/ol_create_repo.rs index d78434b633..fbfc89372f 100644 --- a/config/management/genesis/src/ol_create_repo.rs +++ b/config/management/genesis/src/ol_create_repo.rs @@ -18,9 +18,9 @@ pub struct CreateGenesisRepo { #[structopt(flatten)] pub backend: SharedBackend, #[structopt(long)] - pub repo_owner: String, + pub repo_owner: Option, #[structopt(long)] - pub repo_name: String, + pub repo_name: Option, #[structopt(long)] pub pull_request_user: Option, #[structopt(long)] @@ -44,7 +44,7 @@ impl CreateGenesisRepo { let github = Client::new( config.repository_owner.clone(), config.repository.clone(), - config.branch.unwrap_or("main".to_string()), + config.branch.unwrap_or("master".to_string()), config .token .read_token() @@ -61,11 +61,11 @@ impl CreateGenesisRepo { file.read_to_end(&mut bytes).expect("could not read file"); let base64_encoded = base64::encode(bytes); - let repo_file_path = format!("/genesis/{}", p.file_name().unwrap().to_str().unwrap()); + let repo_file_path = format!("genesis/{}", p.file_name().unwrap().to_str().unwrap()); github.put(&repo_file_path, &base64_encoded).expect("could not put file in github repo"); - return Ok("published genesis.blob and genesis_waypoint.txt to genesis repo.".to_string()); + return Ok(format!("published file to genesis repo at {:?}", &repo_file_path)); } // Make a pull request of the the forked repo, back to the genesis coordination repository. if let Some(user) = self.pull_request_user { @@ -88,8 +88,8 @@ impl CreateGenesisRepo { } } else { // Fork the genesis coordination repo into a personal repo - match github.fork_genesis_repo(&self.repo_owner, &self.repo_name) { - Ok(_) => Ok(format!("Created new repo {}", &self.repo_name)), + match github.fork_genesis_repo(&self.repo_owner.unwrap(), &self.repo_name.as_ref().unwrap()) { + Ok(_) => Ok(format!("Created new repo {}", &self.repo_name.unwrap())), Err(e) => Err(Error::StorageWriteError( "github", "fork genesis repo", @@ -105,3 +105,4 @@ impl CreateGenesisRepo { } } } + From 4d24245fe99c0a7e14f211c2ac36cd2d778cd2df Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Mon, 13 Jun 2022 22:54:15 +0000 Subject: [PATCH 12/45] reorganize testnet scripts --- Makefile | 85 +++++++++++++++++++------------------------------------- 1 file changed, 29 insertions(+), 56 deletions(-) diff --git a/Makefile b/Makefile index dcde51e1ea..7e2e3be7e0 100644 --- a/Makefile +++ b/Makefile @@ -452,44 +452,35 @@ debug: make smoke-onboard <<< $$'${MNEM}' -##### DEVNET TESTS ##### - -devnet: clear fix dev-wizard dev-genesis start -# runs a smoke test from fixtures. -# Uses genesis blob from fixtures, assumes 3 validators, and test settings. -# This will work for validator nodes alice, bob, carol, and any fullnodes; 'eve' - -dev-join: clear fix fix-genesis dev-wizard -# REQUIRES MOCK GIT INFRASTRUCTURE: OLSF/dev-genesis OLSF/dev-epoch-archive -# see `devnet-archive` below -# We want to simulate the onboarding/new validator fetching genesis files from the mock archive: dev-genesis-archive - -# mock restore backups from dev-epoch-archive - rm -rf ~/.0L/restore -# restore from MOCK archive OLSF/dev-epoch-archive - cargo r -p ol -- restore +#### TESTNET ##### + +# Do this to restart the network with new code. Assumes a registration has been completed, and the genesis validators are unchanged. If new IP addresses or number of genesis nodes changed, you must RERUN SETUP below. +# - builds stdlib from source +# - clears many of the home files +# - adds fixtures +# - initializes node configs +# - rebuids genesis files and shares to github genesis repo +# - starts node in validator mode +testnet-start: stdlib clear fix testnet-validator-init-wizard testnet-setup-make-genesis-files start + +# For subsequent validators joining the testnet. This will fetch the genesis information saved +testnet-onboard: clear fix + MNEM='${MNEM}' cargo run -p onboard -- val --github-org OLSF --repo dev-genesis --chain-id 1 # start a node with fullnode.node.yaml configs make start-full -dev-wizard: -# REQUIRES there is a genesis.blob in the fixtures/genesis/ you are testing - MNEM='${MNEM}' cargo run -p onboard -- val --prebuilt-genesis ${DATA_PATH}/genesis.blob --skip-mining --chain-id 1 --genesis-ceremony +#### TESTNET SETUP #### -#### DEVNET RESTART #### -# usually do this on Alice, which has the dev-epoch-archive repo, and dev-genesis +testnet-validator-init-wizard: +# REQUIRES there is a genesis.blob in the fixtures/genesis/ you are testing + MNEM='${MNEM}' cargo run -p onboard -- val --skip-mining --chain-id 1 --genesis-ceremony -# Do the ceremony: and also save the genesis fixtures, needs to happen before fix. -dev-register: clear fix dev-wizard gen-register +# Do the genesis ceremony registration +testnet-setup-register-val: clear fix testnet-validator-init-wizard gen-register # Do a dev genesis on each node after EVERY NODE COMPLETED registration. -dev-genesis: genesis dev-save-genesis fix-genesis - -#### DEVNET INFRA #### -# To make reproducible devnet files. -# Save the files to mock infrastructure i.e. devnet github -dev-infra: dev-backup-archive dev-commit - -dev-save-genesis: set-waypoint +# Makes the gensis file on each genesis validator, AND SAVES TO GITHUB so that other validators can be onboarded after genesis. +testnet-setup-make-genesis-files: genesis set-waypoint cargo run -p diem-genesis-tool ${CARGO_ARGS} -- create-repo \ --publish-genesis ${DATA_PATH}/genesis.blob \ --shared-backend ${GENESIS_REMOTE} @@ -498,31 +489,6 @@ dev-save-genesis: set-waypoint --publish-genesis ${DATA_PATH}/genesis_waypoint.txt \ --shared-backend ${GENESIS_REMOTE} -dev-backup-archive: - cd ${HOME}/dev-epoch-archive && make devnet-backup - -dev-commit: - git commit -a -m "save genesis fixtures to ${V}" | true - git push | true - - -TAG=$(shell git tag -l "previous") -clean-tags: - git push origin --delete ${TAG} - git tag -d ${TAG} - -nuke-testnet: - @echo WIPING EVERYTHING but keeping: github_token.txt, autopay_batch.json, set_layout.toml, /vdf_proofs/proof_0.json - - @if test -d ${DATA_PATH}; then \ - cd ${DATA_PATH} && cp github_token.txt autopay_batch.json set_layout.toml vdf_proofs/proof_0.json ~/; \ - cd ${DATA_PATH} && rm -rf *; \ - cd ~ && cp github_token.txt autopay_batch.json set_layout.toml ${DATA_PATH}; \ - cd ${DATA_PATH} && mkdir vdf_proofs;\ - cd ~ && cp proof_0.json ${DATA_PATH}/vdf_proofs/; \ - fi - - ####### SWARM ######## sw: sw-build sw-start sw-init @@ -576,3 +542,10 @@ fork-config: fork-start: rm -rf ~/.0L/db cargo run -p libra-node -- --config ~/.0L/validator.node.yaml + +##### UTIL ##### +TAG=$(shell git tag -l "previous") +clean-tags: + git push origin --delete ${TAG} + git tag -d ${TAG} + \ No newline at end of file From 61827978b0cf5d8e830f0df155762d5276df1347 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Mon, 13 Jun 2022 22:56:43 +0000 Subject: [PATCH 13/45] cleanup --- config/management/genesis/src/storage_helper.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/config/management/genesis/src/storage_helper.rs b/config/management/genesis/src/storage_helper.rs index a7e9579245..02227c6dfa 100644 --- a/config/management/genesis/src/storage_helper.rs +++ b/config/management/genesis/src/storage_helper.rs @@ -122,7 +122,6 @@ impl StorageHelper { let mut storage_oper = self.storage(format!("{}-oper", namespace.clone())); if is_genesis { - dbg!(&is_genesis); // Data needed for testnet, swarm, and genesis ceremony. let mut storage_root = self.storage("root".to_owned()); let dummy_root = Ed25519PrivateKey::from_encoded_string( From e3aa0f06240770ead05402c5f13be1f2a97bc010 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Mon, 13 Jun 2022 23:06:15 +0000 Subject: [PATCH 14/45] documentation --- Makefile | 54 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 7e2e3be7e0..5e6f624e79 100644 --- a/Makefile +++ b/Makefile @@ -453,30 +453,33 @@ debug: #### TESTNET ##### +# The testnet is started using the same tools as genesis to have a faithful reproduction of a network from a clean slate. -# Do this to restart the network with new code. Assumes a registration has been completed, and the genesis validators are unchanged. If new IP addresses or number of genesis nodes changed, you must RERUN SETUP below. -# - builds stdlib from source -# - clears many of the home files -# - adds fixtures -# - initializes node configs -# - rebuids genesis files and shares to github genesis repo -# - starts node in validator mode -testnet-start: stdlib clear fix testnet-validator-init-wizard testnet-setup-make-genesis-files start +# 1. The first thing necessary is initializing testnet genesis validators. +# 2. Next those validators will register config data to a github repo OLSD/dev-genesis. Note: there could be github http errors, if validators attempt to write the same resource simultaneously + +# THESE STEPS ARE ACHIEVED WITH `make testnet-setup-register-val` + +# 3. Wait. All genesis nodes need to complete registration. Otherwise buidling a genesis.blob (the first block), will fail. +# 4. Each genesis node builds the genesis file locally, and submits to the github repo. (this remote genesis file is what subsequent non-genesis validators will use to bootstrap their db). +# 5. Genesis validators can start their nodes. + +# THESE STEPS ARE ACHIEVED WITH testnet-setup-make-genesis-files + + +# 6. Assuming there is progress in the block production, subsequent validators can join. + +# THIS IS ACHIEVED WITH: testnet-onboard -# For subsequent validators joining the testnet. This will fetch the genesis information saved -testnet-onboard: clear fix - MNEM='${MNEM}' cargo run -p onboard -- val --github-org OLSF --repo dev-genesis --chain-id 1 -# start a node with fullnode.node.yaml configs - make start-full -#### TESTNET SETUP #### +#### 1. TESTNET SETUP #### -testnet-validator-init-wizard: +testnet-validator-init-wizard: clear fix # REQUIRES there is a genesis.blob in the fixtures/genesis/ you are testing MNEM='${MNEM}' cargo run -p onboard -- val --skip-mining --chain-id 1 --genesis-ceremony # Do the genesis ceremony registration -testnet-setup-register-val: clear fix testnet-validator-init-wizard gen-register +testnet-setup-register-val: testnet-validator-init-wizard gen-register # Do a dev genesis on each node after EVERY NODE COMPLETED registration. # Makes the gensis file on each genesis validator, AND SAVES TO GITHUB so that other validators can be onboarded after genesis. @@ -489,6 +492,25 @@ testnet-setup-make-genesis-files: genesis set-waypoint --publish-genesis ${DATA_PATH}/genesis_waypoint.txt \ --shared-backend ${GENESIS_REMOTE} +#### 2. TESTNET START #### + +# Do this to restart the network with new code. Assumes a registration has been completed, and the genesis validators are unchanged. If new IP addresses or number of genesis nodes changed, you must RERUN SETUP below. +# - builds stdlib from source +# - clears many of the home files +# - adds fixtures +# - initializes node configs +# - rebuids genesis files and shares to github genesis repo +# - starts node in validator mode +testnet-start: stdlib clear fix testnet-validator-init-wizard testnet-setup-make-genesis-files start + +# For subsequent validators joining the testnet. This will fetch the genesis information saved +testnet-onboard: clear fix + MNEM='${MNEM}' cargo run -p onboard -- val --github-org OLSF --repo dev-genesis --chain-id 1 +# start a node with fullnode.node.yaml configs + make start-full + + + ####### SWARM ######## sw: sw-build sw-start sw-init From decf2f88dbba0e2c0c2fa5e5aaedc14d5b30d04b Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Mon, 13 Jun 2022 23:15:47 +0000 Subject: [PATCH 15/45] patch makefile --- Makefile | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 5e6f624e79..c02e34a4f8 100644 --- a/Makefile +++ b/Makefile @@ -401,16 +401,12 @@ ifdef TEST cp ./ol/devnet/set_layout_test.toml ${DATA_PATH}/set_layout.toml endif -fix-genesis: - cp ./ol/devnet/genesis/${V}/genesis.blob ${DATA_PATH}/ - cp ./ol/devnet/genesis/${V}/genesis_waypoint ${DATA_PATH}/ - #### HELPERS #### set-waypoint: @if test -f ${DATA_PATH}/key_store.json; then \ jq -r '. | with_entries(select(.key|match("-oper/waypoint";"i")))[].value' ${DATA_PATH}/key_store.json > ${DATA_PATH}/client_waypoint; \ - jq -r '. | with_entries(select(.key|match("-oper/genesis-waypoint";"i")))[].value' ${DATA_PATH}/key_store.json > ${DATA_PATH}/genesis_waypoint; \ + jq -r '. | with_entries(select(.key|match("-oper/genesis-waypoint";"i")))[].value' ${DATA_PATH}/key_store.json > ${DATA_PATH}/genesis_waypoint.txt; \ fi cargo r -p ol -- init --update-waypoint --waypoint $(shell cat ${DATA_PATH}/client_waypoint) @@ -455,7 +451,8 @@ debug: #### TESTNET ##### # The testnet is started using the same tools as genesis to have a faithful reproduction of a network from a clean slate. -# 1. The first thing necessary is initializing testnet genesis validators. +# 1. The first thing necessary is initializing testnet genesis validators. All genesis nodes need to set up environment variables for their namespace/personas e.g. NS=alice. Also the TEST=y mode must be set, as well as a chain environment e.g. NODE_ENV=test. These settings must be done manually, preferably in .bashrc + # 2. Next those validators will register config data to a github repo OLSD/dev-genesis. Note: there could be github http errors, if validators attempt to write the same resource simultaneously # THESE STEPS ARE ACHIEVED WITH `make testnet-setup-register-val` @@ -478,7 +475,7 @@ testnet-validator-init-wizard: clear fix # REQUIRES there is a genesis.blob in the fixtures/genesis/ you are testing MNEM='${MNEM}' cargo run -p onboard -- val --skip-mining --chain-id 1 --genesis-ceremony -# Do the genesis ceremony registration +# Do the genesis ceremony registration, this includes the step testnet-validator-init-wizard testnet-setup-register-val: testnet-validator-init-wizard gen-register # Do a dev genesis on each node after EVERY NODE COMPLETED registration. From 60f40fdc81bb1c26a99f24cb6b9d1c9c5d905670 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Tue, 14 Jun 2022 20:59:52 +0000 Subject: [PATCH 16/45] makefile --- Makefile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index c02e34a4f8..16eb006cab 100644 --- a/Makefile +++ b/Makefile @@ -290,7 +290,7 @@ verify-gen: --validator-backend ${LOCAL} \ --genesis-path ${DATA_PATH}/genesis.blob -genesis: +genesis: stdlib cargo run -p diem-genesis-tool ${CARGO_ARGS} -- files \ --chain-id ${CHAIN_ID} \ --validator-backend ${LOCAL} \ @@ -455,13 +455,13 @@ debug: # 2. Next those validators will register config data to a github repo OLSD/dev-genesis. Note: there could be github http errors, if validators attempt to write the same resource simultaneously -# THESE STEPS ARE ACHIEVED WITH `make testnet-setup-register-val` +# THESE STEPS ARE ACHIEVED WITH `make testnet-register` # 3. Wait. All genesis nodes need to complete registration. Otherwise buidling a genesis.blob (the first block), will fail. # 4. Each genesis node builds the genesis file locally, and submits to the github repo. (this remote genesis file is what subsequent non-genesis validators will use to bootstrap their db). # 5. Genesis validators can start their nodes. -# THESE STEPS ARE ACHIEVED WITH testnet-setup-make-genesis-files +# THESE STEPS ARE ACHIEVED WITH testnet-genesis # 6. Assuming there is progress in the block production, subsequent validators can join. @@ -471,16 +471,16 @@ debug: #### 1. TESTNET SETUP #### -testnet-validator-init-wizard: clear fix +testnet-init: clear fix # REQUIRES there is a genesis.blob in the fixtures/genesis/ you are testing MNEM='${MNEM}' cargo run -p onboard -- val --skip-mining --chain-id 1 --genesis-ceremony # Do the genesis ceremony registration, this includes the step testnet-validator-init-wizard -testnet-setup-register-val: testnet-validator-init-wizard gen-register +testnet-register: testnet-init gen-register # Do a dev genesis on each node after EVERY NODE COMPLETED registration. # Makes the gensis file on each genesis validator, AND SAVES TO GITHUB so that other validators can be onboarded after genesis. -testnet-setup-make-genesis-files: genesis set-waypoint +testnet-genesis: genesis set-waypoint cargo run -p diem-genesis-tool ${CARGO_ARGS} -- create-repo \ --publish-genesis ${DATA_PATH}/genesis.blob \ --shared-backend ${GENESIS_REMOTE} @@ -498,7 +498,7 @@ testnet-setup-make-genesis-files: genesis set-waypoint # - initializes node configs # - rebuids genesis files and shares to github genesis repo # - starts node in validator mode -testnet-start: stdlib clear fix testnet-validator-init-wizard testnet-setup-make-genesis-files start +testnet: clear fix testnet-init testnet-setup-make-genesis-files start # For subsequent validators joining the testnet. This will fetch the genesis information saved testnet-onboard: clear fix From 4fbb5f69942eb3bf61e161292b899c03ded4324a Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Tue, 14 Jun 2022 21:04:29 +0000 Subject: [PATCH 17/45] makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 16eb006cab..9610fae2a0 100644 --- a/Makefile +++ b/Makefile @@ -498,7 +498,7 @@ testnet-genesis: genesis set-waypoint # - initializes node configs # - rebuids genesis files and shares to github genesis repo # - starts node in validator mode -testnet: clear fix testnet-init testnet-setup-make-genesis-files start +testnet: clear fix testnet-init testnet-genesis start # For subsequent validators joining the testnet. This will fetch the genesis information saved testnet-onboard: clear fix From 65133fdcf23c29d848414e86618f2701824aad3f Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Tue, 14 Jun 2022 21:06:23 +0000 Subject: [PATCH 18/45] text [skip-ci] --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9610fae2a0..070c6a06e1 100644 --- a/Makefile +++ b/Makefile @@ -461,7 +461,7 @@ debug: # 4. Each genesis node builds the genesis file locally, and submits to the github repo. (this remote genesis file is what subsequent non-genesis validators will use to bootstrap their db). # 5. Genesis validators can start their nodes. -# THESE STEPS ARE ACHIEVED WITH testnet-genesis +# THESE STEPS ARE ACHIEVED WITH `make testnet` # 6. Assuming there is progress in the block production, subsequent validators can join. From c70f9c954dc7c69e49c711bd159033135ef07f2b Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Wed, 15 Jun 2022 22:41:17 +0000 Subject: [PATCH 19/45] update yaml configs so that node file uses multiple fullnode networks [skip-ci] --- config/management/genesis/src/ol_node_files.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/config/management/genesis/src/ol_node_files.rs b/config/management/genesis/src/ol_node_files.rs index 1f1fa79d46..8f8b6b8812 100644 --- a/config/management/genesis/src/ol_node_files.rs +++ b/config/management/genesis/src/ol_node_files.rs @@ -361,14 +361,18 @@ fn make_validator_cfg(output_dir: PathBuf, namespace: &str) -> Result Date: Wed, 15 Jun 2022 22:44:50 +0000 Subject: [PATCH 20/45] patch [skip ci] --- config/management/genesis/src/ol_node_files.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/management/genesis/src/ol_node_files.rs b/config/management/genesis/src/ol_node_files.rs index 8f8b6b8812..056849b541 100644 --- a/config/management/genesis/src/ol_node_files.rs +++ b/config/management/genesis/src/ol_node_files.rs @@ -370,7 +370,7 @@ fn make_validator_cfg(output_dir: PathBuf, namespace: &str) -> Result Date: Wed, 15 Jun 2022 23:03:24 +0000 Subject: [PATCH 21/45] patch ports [skip ci] --- config/management/genesis/src/ol_node_files.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/management/genesis/src/ol_node_files.rs b/config/management/genesis/src/ol_node_files.rs index 056849b541..b77196c40b 100644 --- a/config/management/genesis/src/ol_node_files.rs +++ b/config/management/genesis/src/ol_node_files.rs @@ -366,7 +366,7 @@ fn make_validator_cfg(output_dir: PathBuf, namespace: &str) -> Result Date: Thu, 16 Jun 2022 00:38:46 +0000 Subject: [PATCH 22/45] validator init on genesis and ol init, will use seed peers --- config/global-constants/src/lib.rs | 1 - .../management/genesis/src/ol_node_files.rs | 24 ++- ol/cli/src/commands/init_cmd.rs | 141 ++++++++++-------- 3 files changed, 96 insertions(+), 70 deletions(-) diff --git a/config/global-constants/src/lib.rs b/config/global-constants/src/lib.rs index b53cab2995..6577320ea8 100644 --- a/config/global-constants/src/lib.rs +++ b/config/global-constants/src/lib.rs @@ -43,7 +43,6 @@ pub const DEFAULT_VAL_PORT: u64 = 6180; pub const DEFAULT_VFN_PORT: u64 = 6179; pub const DEFAULT_PUB_PORT: u64 = 6178; - // TODO: make this lazy static. /// Switch settings between production and testing pub fn delay_difficulty() -> u64 { diff --git a/config/management/genesis/src/ol_node_files.rs b/config/management/genesis/src/ol_node_files.rs index b77196c40b..bb1b32ae40 100644 --- a/config/management/genesis/src/ol_node_files.rs +++ b/config/management/genesis/src/ol_node_files.rs @@ -1,6 +1,6 @@ use std::{fmt::Debug, fs, net::Ipv4Addr, path::PathBuf, process::exit}; -use crate::{storage_helper::StorageHelper, seeds::SeedAddresses}; +use crate::{storage_helper::StorageHelper, seeds::{SeedAddresses, Seeds}}; use diem_config::{ config::OnDiskStorageConfig, config::SafetyRulesService, @@ -105,7 +105,7 @@ pub fn onboard_helper_all_files( let storage_helper = StorageHelper::get_with_path(output_dir.clone()); - let (_genesis_path, genesis_waypoint) = make_genesis_file( + let (genesis_path, genesis_waypoint) = make_genesis_file( &output_dir, prebuilt_genesis, &repo, @@ -124,7 +124,9 @@ pub fn onboard_helper_all_files( let file_string = fs::read_to_string(&p)?; let yaml: SeedAddresses = serde_yaml::from_str(&file_string)?; Some(yaml) - } else { None }; + } else { + Seeds::new(genesis_path).get_network_peers_info().ok() + }; let vfn_ip_address = val_ip_address.clone(); // This next step depends on genesis waypoint existing in key_store. @@ -164,9 +166,9 @@ pub fn make_all_profiles_yaml( genesis_waypoint: Waypoint, // _fullnode_only: bool, ) -> Result { + // fullnodes need seed peers, try to extract from the genesis file as a starting place. - - let config = make_val_file(output_dir.clone(), vfn_ip_address, namespace)?; + let config = make_val_file(output_dir.clone(), seed_addr.clone(), vfn_ip_address, namespace)?; make_vfn_file(output_dir.clone(), val_ip_address, genesis_waypoint, namespace)?; make_fullnode_file(output_dir.clone(), seed_addr, genesis_waypoint)?; @@ -177,12 +179,12 @@ pub fn make_all_profiles_yaml( // helper to write a new validator.node.yaml file. pub fn make_val_file( output_dir: PathBuf, - // val_ip_address: Ipv4Addr, + seed_addr: Option, _vfn_ip_address: Option, namespace: &str, ) -> Result { // TODO: The validator's connection to VFN should be restricted to the vfn_ip_address - let mut val = make_validator_cfg(output_dir.clone(), namespace)?; + let mut val = make_validator_cfg(output_dir.clone(), namespace, seed_addr)?; write_yaml(output_dir.clone(), &mut val, NodeType::Validator)?; Ok(val) } @@ -312,7 +314,7 @@ pub fn make_fullnode_cfg( Ok(c) } -fn make_validator_cfg(output_dir: PathBuf, namespace: &str) -> Result { +fn make_validator_cfg(output_dir: PathBuf, namespace: &str, seed_addresses: Option) -> Result { // TODO: make the validator node have mutual authentication with VFN. // for that it will need to get the Peer object of the VFN after the identity has been created // by default the VFN identity is random. @@ -372,6 +374,12 @@ fn make_validator_cfg(output_dir: PathBuf, namespace: &str) -> Result { - println!("waypoint updated successfully in files 0L.toml, and key_store.json"); - }, - Err(e ) => { - println!("ERROR: could not update files 0L.toml, and key_store.json with waypoint, message: {:?}", e.to_string()); + println!("waypoint updated successfully in files 0L.toml, and key_store.json"); + } + Err(e) => { + println!("ERROR: could not update files 0L.toml, and key_store.json with waypoint, message: {:?}", e.to_string()); } } return; @@ -151,52 +158,12 @@ impl Runnable for InitCmd { // fetch a list of seed peers from the current on chain discovery // doesn't need mnemonic if self.seed_peer { - let client = match client::pick_client(entry_args.swarm_path.clone(), &mut app_cfg) { - Ok(c) => c, - Err(e) => { - println!( - "Could not connect to a fullnode with JSON API, exiting. Message: {:?}", - e - ); - exit(1); - } - }; + let seed = pick_seed_peer(&mut app_cfg, entry_args.swarm_path.clone()).expect("could not find any seed peers"); - let mut node = Node::new(client, &app_cfg, is_swarm); + let path = app_cfg.workspace.node_home.join("seed_fullnodes.yaml"); - match node.refresh_fullnode_seeds() { - Ok(s) => { - match serde_yaml::to_string(&s) { - Ok(y) => { - let path = app_cfg.workspace.node_home.join("seed_fullnodes.yaml"); - match std::fs::write(&path, &y) { - Ok(_) => { - println!("seed_fullnodes.yaml file written to: {:?}", &path) - } - Err(e) => { - println!( - "Could not write yaml file, exiting. Message: {:?}", - e - ); - exit(1); - } - }; - } - Err(e) => { - println!("Could not serialize yaml, exiting. Message: {:?}", e); - exit(1); - } - } - return; - } - Err(e) => { - println!( - "Could not fetch seed peers from chain, exiting. Message: {:?}", - e - ); - exit(1); - } - }; + write_seed_peers_file(&path, &seed).unwrap(); + exit(0); } // create files for VFN @@ -230,9 +197,9 @@ impl Runnable for InitCmd { // TODO: check we can open key-store file let namespace = app_cfg.format_oper_namespace(); - let output_dir = app_cfg.workspace.node_home; - - match ol_node_files::make_val_file(output_dir, None, &namespace) { + let output_dir = app_cfg.workspace.node_home.clone(); + let seeds = pick_seed_peer(&mut app_cfg, entry_args.swarm_path.clone()); + match ol_node_files::make_val_file(output_dir, seeds.ok(), None, &namespace) { Ok(_) => {} Err(e) => { println!("Could not create file, exiting. Message: {:?}", e); @@ -245,15 +212,15 @@ impl Runnable for InitCmd { // create files for public fullnode if self.fullnode { println!("Creating fullnode.node.yaml file."); - + let seed = pick_seed_peer(&mut app_cfg, entry_args.swarm_path.clone()).ok(); // TODO: check we can open key-store file - let output_dir = app_cfg.workspace.node_home; + let output_dir = app_cfg.workspace.node_home.clone(); let gen_wp = app_cfg.chain_info.base_waypoint; // TODO: get seed addresses from file optionally // let seed = SeedAddresses::read_from_file(seed_peers_path); - match ol_node_files::make_fullnode_file(output_dir, None, gen_wp.unwrap_or_default()) { + match ol_node_files::make_fullnode_file(output_dir, seed, gen_wp.unwrap_or_default()) { Ok(_) => {} Err(e) => { println!("Could not create file, exiting. Message: {:?}", e); @@ -430,11 +397,15 @@ impl config::Override for InitCmd { } /// helper to update waypoint from a known waypoint or query an upstream node for current waypoint -fn update_waypoint(mut app_cfg: AppCfg, waypoint_opt: Option, swarm_path: Option) -> anyhow::Result { +fn update_waypoint( + app_cfg: &mut AppCfg, + waypoint_opt: Option, + swarm_path: Option, +) -> anyhow::Result { let new_waypoint = match waypoint_opt { Some(w) => w, None => { - let client = client::pick_client(swarm_path, &mut app_cfg)?; + let client = client::pick_client(swarm_path, app_cfg)?; match client.get_waypoint_state()? { Some(wv) => wv.waypoint, @@ -442,7 +413,7 @@ fn update_waypoint(mut app_cfg: AppCfg, waypoint_opt: Option, swarm_p } } }; - + // set the 0L.toml file waypoint app_cfg.chain_info.base_waypoint = Some(new_waypoint); app_cfg.save_file()?; @@ -462,3 +433,51 @@ fn update_waypoint(mut app_cfg: AppCfg, waypoint_opt: Option, swarm_p Ok(new_waypoint) } + +fn pick_seed_peer(app_cfg: &mut AppCfg, swarm_path: Option) -> anyhow::Result { + match seed_peers_from_chain(app_cfg, swarm_path) { + Ok(s) => Ok(s), + Err(_) => { + println!("could not get seeds from chain, trying from genesis.blob"); + let seed = Seeds::new(app_cfg.workspace.node_home.join("genesis.blob")).get_network_peers_info() + .map_err(|_| { anyhow!("could not parse seed peers from genesis.blob")})?; + Ok(seed) + } + } +} + +fn seed_peers_from_chain( + app_cfg: &mut AppCfg, + swarm_path: Option, +) -> anyhow::Result { + let client = client::pick_client(swarm_path.clone(), app_cfg)?; + + let mut node = Node::new(client, &app_cfg, swarm_path.is_some()); + + let seeds = node.refresh_fullnode_seeds()?; + + Ok(seeds) +} + +fn write_seed_peers_file(path: &PathBuf, seeds: &SeedAddresses) -> anyhow::Result<()> { + match serde_yaml::to_string(&seeds) { + Ok(y) => { + match std::fs::write(&path, &y) { + Ok(_) => { + println!("seed_fullnodes.yaml file written to: {:?}", &path); + return Ok(()); + } + Err(e) => { + let m = format!("Could not write yaml file, exiting. Message: {:?}", e); + println!("{}", &m); + bail!(m) + } + }; + } + Err(e) => { + let m = format!("Could not serialize yaml, exiting. Message: {:?}", e); + println!("{}", &m); + bail!(m) + } + } +} From 8160dce4ffcca50ff38078498af8e84c5f8fb236 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Thu, 16 Jun 2022 17:33:45 -0400 Subject: [PATCH 23/45] trim whitespace on genesis_waypoint.txt --- config/management/genesis/src/ol_node_files.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/management/genesis/src/ol_node_files.rs b/config/management/genesis/src/ol_node_files.rs index bb1b32ae40..f1b4cec477 100644 --- a/config/management/genesis/src/ol_node_files.rs +++ b/config/management/genesis/src/ol_node_files.rs @@ -249,9 +249,9 @@ fn make_genesis_file( Some(path) => { // TODO: insert waypoint let gen_wp_path = path.parent().unwrap().join("genesis_waypoint.txt"); - let wp: Waypoint = - fs::read_to_string(&gen_wp_path)? - .parse().map_err(|_| anyhow::anyhow!("cannot parse genesis_waypoint.txt"))?; + let wp_string = fs::read_to_string(&gen_wp_path)?; + let wp: Waypoint = wp_string.trim().parse() + .map_err(|_| anyhow::anyhow!("cannot parse genesis_waypoint.txt"))?; Ok((path.to_owned(), wp)) } None => { @@ -496,4 +496,4 @@ fn encode_validator_seed_for_vfn_discovery( let mut seeds = PeerSet::default(); seeds.insert(validator_account, val_peer_data); Ok(seeds) -} +} \ No newline at end of file From ba50ecef02cd6e023d967b558cb133e9971daa29 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Thu, 16 Jun 2022 17:43:06 -0400 Subject: [PATCH 24/45] makefile --- Makefile | 6 +----- config/management/genesis/src/ol_node_files.rs | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 070c6a06e1..59b34d977e 100644 --- a/Makefile +++ b/Makefile @@ -309,10 +309,6 @@ start: # run in foreground. Only for testing, use a daemon for net. RUST_LOG=error cargo run -p diem-node -- --config ${DATA_PATH}/validator.node.yaml -# Start a fullnode instead of a validator node -start-full: - cargo run -p diem-node -- --config ${DATA_PATH}/fullnode.node.yaml - daemon: mkdir -p ~/.config/systemd/user/ cp ./ol/util/diem-node.service ~/.config/systemd/user/ @@ -504,7 +500,7 @@ testnet: clear fix testnet-init testnet-genesis start testnet-onboard: clear fix MNEM='${MNEM}' cargo run -p onboard -- val --github-org OLSF --repo dev-genesis --chain-id 1 # start a node with fullnode.node.yaml configs - make start-full + make start diff --git a/config/management/genesis/src/ol_node_files.rs b/config/management/genesis/src/ol_node_files.rs index f1b4cec477..1a663653d6 100644 --- a/config/management/genesis/src/ol_node_files.rs +++ b/config/management/genesis/src/ol_node_files.rs @@ -294,7 +294,6 @@ pub fn make_fullnode_cfg( c.base.waypoint = WaypointConfig::FromConfig(waypoint); c.base.role = RoleType::FullNode; // c.execution.genesis_file_location = output_dir.clone().join("genesis.blob"); - // prune window exists to prevent state snapshots from taking up too much space. c.storage.prune_window = Some(100_000); From 8c8d9f3a23e9f6ab9421c66513d78f653f054f76 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Fri, 17 Jun 2022 20:49:34 -0400 Subject: [PATCH 25/45] reverse state-sync default params --- config/src/config/state_sync_config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/src/config/state_sync_config.rs b/config/src/config/state_sync_config.rs index e1147812b4..8026297907 100644 --- a/config/src/config/state_sync_config.rs +++ b/config/src/config/state_sync_config.rs @@ -44,8 +44,8 @@ impl Default for StateSyncConfig { max_timeout_ms: 120_000, mempool_commit_timeout_ms: 5_000, multicast_timeout_ms: 30_000, - sync_request_timeout_ms: 1_000, //////// 0L ///////// - tick_interval_ms: 5000, //////// 0L //////// + sync_request_timeout_ms: 60_000, //////// 0L ///////// + tick_interval_ms: 500, //////// 0L //////// } } } From 222b9636f9601e6b1a5e7401e8fa8bbd09343526 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Sat, 18 Jun 2022 17:10:36 -0400 Subject: [PATCH 26/45] add helper in init to reset safety data --- ol/cli/src/commands/init_cmd.rs | 12 ++++++++++++ ol/cli/src/mgmt/restore.rs | 1 + 2 files changed, 13 insertions(+) diff --git a/ol/cli/src/commands/init_cmd.rs b/ol/cli/src/commands/init_cmd.rs index 92ec2e9828..bc54804421 100644 --- a/ol/cli/src/commands/init_cmd.rs +++ b/ol/cli/src/commands/init_cmd.rs @@ -85,6 +85,10 @@ pub struct InitCmd { /// Path to source code, for devs #[options(help = "Path to source code, for devs")] source_path: Option, + + /// reset the safety rules state in key_store.json + #[options(help = "reset the safety data in key_store.json to null")] + reset_safety: bool, } impl Runnable for InitCmd { @@ -250,6 +254,14 @@ impl Runnable for InitCmd { return; } + if self.reset_safety { + diem_genesis_tool::key::reset_safety_data( + &app_cfg.workspace.node_home, + &app_cfg.format_owner_namespace() + ); + exit(0) + } + /////////// Everything below requires mnemonic //////// let (authkey, account, wallet) = wallet::get_account_from_prompt(); diff --git a/ol/cli/src/mgmt/restore.rs b/ol/cli/src/mgmt/restore.rs index 29f9850cb9..7ab3a448ab 100644 --- a/ol/cli/src/mgmt/restore.rs +++ b/ol/cli/src/mgmt/restore.rs @@ -73,6 +73,7 @@ pub fn fast_forward_db( &backup.home_path, &backup.node_namespace ); + println!("SUCCESS"); Ok(()) } From 6f31a6044aaa2e12e2f286ff6e04ada234d5de5c Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Sat, 18 Jun 2022 17:16:16 -0400 Subject: [PATCH 27/45] bump version --- Cargo.lock | 16 ++++++++-------- config/Cargo.toml | 2 +- config/management/Cargo.toml | 2 +- diem-node/Cargo.toml | 2 +- ol/cli/Cargo.toml | 2 +- ol/onboard/Cargo.toml | 2 +- ol/tower/Cargo.toml | 2 +- ol/txs/Cargo.toml | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1a78f56b3..7d52c720ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1764,7 +1764,7 @@ dependencies = [ [[package]] name = "diem-config" -version = "5.1.2" +version = "5.1.3" dependencies = [ "bcs", "diem-crypto", @@ -2222,7 +2222,7 @@ dependencies = [ [[package]] name = "diem-management" -version = "5.1.2" +version = "5.1.3" dependencies = [ "anyhow", "bcs", @@ -2341,7 +2341,7 @@ dependencies = [ [[package]] name = "diem-node" -version = "5.1.2" +version = "5.1.3" dependencies = [ "backup-service", "consensus", @@ -6023,7 +6023,7 @@ dependencies = [ [[package]] name = "ol" -version = "5.1.2" +version = "5.1.3" dependencies = [ "abscissa_core", "abscissa_tokio", @@ -6170,7 +6170,7 @@ dependencies = [ [[package]] name = "onboard" -version = "5.1.2" +version = "5.1.3" dependencies = [ "abscissa_core", "anyhow", @@ -6195,7 +6195,7 @@ dependencies = [ "serde_json", "thiserror", "toml", - "tower 5.1.2", + "tower 5.1.3", "txs", "wait-timeout", "zip", @@ -9117,7 +9117,7 @@ dependencies = [ [[package]] name = "tower" -version = "5.1.2" +version = "5.1.3" dependencies = [ "abscissa_core", "ajson", @@ -9341,7 +9341,7 @@ dependencies = [ [[package]] name = "txs" -version = "5.1.2" +version = "5.1.3" dependencies = [ "abscissa_core", "ajson", diff --git a/config/Cargo.toml b/config/Cargo.toml index f7c9622ce6..618a34551b 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "diem-config" -version = "5.1.2" +version = "5.1.3" authors = ["Diem Association "] description = "Diem diem-config" repository = "https://github.com/diem/diem" diff --git a/config/management/Cargo.toml b/config/management/Cargo.toml index 3b068b3971..d552bd0b17 100644 --- a/config/management/Cargo.toml +++ b/config/management/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "diem-management" -version = "5.1.2" +version = "5.1.3" authors = ["Diem Association "] description = "Diem Management is a tool used to manage the configuration of a Diem Node" repository = "https://github.com/diem/diem" diff --git a/diem-node/Cargo.toml b/diem-node/Cargo.toml index e7bbcbbb45..bcd307951a 100644 --- a/diem-node/Cargo.toml +++ b/diem-node/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "diem-node" -version = "5.1.2" +version = "5.1.3" authors = ["Diem Association "] description = "Diem node" repository = "https://github.com/diem/diem" diff --git a/ol/cli/Cargo.toml b/ol/cli/Cargo.toml index f126208f3c..fb66057cfa 100644 --- a/ol/cli/Cargo.toml +++ b/ol/cli/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ol" authors = [] -version = "5.1.2" +version = "5.1.3" edition = "2018" [dependencies] diff --git a/ol/onboard/Cargo.toml b/ol/onboard/Cargo.toml index 06f64ac445..7d142cee6c 100644 --- a/ol/onboard/Cargo.toml +++ b/ol/onboard/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "onboard" -version = "5.1.2" +version = "5.1.3" edition = "2018" authors = ["0L contributors"] description = "0L onboarding wizard" diff --git a/ol/tower/Cargo.toml b/ol/tower/Cargo.toml index 7f97a03fcd..5561afb3f4 100644 --- a/ol/tower/Cargo.toml +++ b/ol/tower/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tower" -version = "5.1.2" +version = "5.1.3" edition = "2018" authors = ["0L contributors"] description = "0L tower" diff --git a/ol/txs/Cargo.toml b/ol/txs/Cargo.toml index 3359209960..3e98d65b31 100644 --- a/ol/txs/Cargo.toml +++ b/ol/txs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "txs" authors = [] -version = "5.1.2" +version = "5.1.3" edition = "2018" [dependencies] From 7f8fddc85c4f71ec1f4853e853db196039d61e40 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Sat, 18 Jun 2022 17:50:27 -0400 Subject: [PATCH 28/45] ol restore has --boundary-only or -b which will not attempt to restore an advanced version. This is the safest restore option. --- ol/cli/src/commands/restore_cmd.rs | 5 +++- ol/cli/src/mgmt/restore.rs | 47 +++++++++++++++++------------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/ol/cli/src/commands/restore_cmd.rs b/ol/cli/src/commands/restore_cmd.rs index 22e999b101..9423366361 100644 --- a/ol/cli/src/commands/restore_cmd.rs +++ b/ol/cli/src/commands/restore_cmd.rs @@ -21,6 +21,9 @@ pub struct RestoreCmd { #[options(short="v", help = "specify a version or height if there is more than one per archive")] version: Option, + #[options(short="b", help = "only restore the boundary, not an advanced version.")] + boundary_only: bool, + #[options(help = "get only the exact last block at the end of an epoch. Not extra blocks at the start of following epoch.")] exclude_buffer: bool, } @@ -28,7 +31,7 @@ pub struct RestoreCmd { impl Runnable for RestoreCmd { /// Start the application. fn run(&self) { - match mgmt::restore::fast_forward_db(self.verbose, self.epoch, self.version) { + match mgmt::restore::fast_forward_db(self.verbose, self.epoch, self.version, self.boundary_only) { Ok(_) => {}, Err(e) => println!("ERROR: could not complete db restore, message: {:?}", e), }; diff --git a/ol/cli/src/mgmt/restore.rs b/ol/cli/src/mgmt/restore.rs index 7ab3a448ab..0f4a3deaa9 100644 --- a/ol/cli/src/mgmt/restore.rs +++ b/ol/cli/src/mgmt/restore.rs @@ -53,6 +53,7 @@ pub fn fast_forward_db( verbose: bool, epoch: Option, version_opt: Option, + boundary_only: bool, ) -> Result<(), Error> { let mut backup = Backup::new(epoch); @@ -63,16 +64,13 @@ pub fn fast_forward_db( backup.set_waypoint()?; println!("\nRestoring db from archive to home path"); - backup.restore_backup(verbose, version_opt)?; + backup.restore_backup(verbose, version_opt, boundary_only)?; println!("\nCreating fullnode.node.yaml to home path"); backup.create_fullnode_yaml()?; println!("\nResetting Safety Data in key_store.json\n"); - diem_genesis_tool::key::reset_safety_data( - &backup.home_path, - &backup.node_namespace - ); + diem_genesis_tool::key::reset_safety_data(&backup.home_path, &backup.node_namespace); println!("SUCCESS"); Ok(()) @@ -178,18 +176,26 @@ impl Backup { } /// Restore Backups - pub fn restore_backup(&self, verbose: bool, version_opt: Option) -> Result<(), Error> { + pub fn restore_backup( + &self, + verbose: bool, + version_opt: Option, + boundary_only: bool, + ) -> Result<(), Error> { dbg!(&version_opt); let db_path = &self.home_path.join("db/"); let restore_path = self.restore_path.clone(); - // NOTE: First restore the Epoch before restoring a higher version in the epoch. restore_epoch(db_path, restore_path.to_str().unwrap(), verbose)?; - restore_transaction(db_path, self.restore_path.to_owned().to_str().unwrap(), verbose)?; + restore_transaction( + db_path, + self.restore_path.to_owned().to_str().unwrap(), + verbose, + )?; restore_snapshot( db_path, @@ -199,21 +205,20 @@ impl Backup { )?; // Restore an advanced version in the epoch - - let version = version_opt.unwrap_or(get_heighest_version(restore_path)?); - - let restore_path_for_version = self.restore_path.to_owned().join(version.to_string()); + if !boundary_only { + let version = version_opt.unwrap_or(get_heighest_version(restore_path)?); - dbg!(&restore_path_for_version); + let restore_path_for_version = self.restore_path.to_owned().join(version.to_string()); - restore_transaction(db_path, restore_path_for_version.to_str().unwrap(), verbose)?; + restore_transaction(db_path, restore_path_for_version.to_str().unwrap(), verbose)?; - restore_snapshot( - db_path, - restore_path_for_version.to_str().unwrap(), - &version, - verbose, - )?; + restore_snapshot( + db_path, + restore_path_for_version.to_str().unwrap(), + &version, + verbose, + )?; + } Ok(()) } @@ -514,7 +519,7 @@ fn get_heighest_version(restore_path: PathBuf) -> anyhow::Result { } if highest > 0 { - return Ok(highest); + return Ok(highest); } bail!("No versioned manifest path found in: {:?}", restore_path); } From 21c694266c7467b23e9203dfb784f638734c6fab Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Sun, 19 Jun 2022 15:34:04 -0400 Subject: [PATCH 29/45] ol restore defaults to only fetch the epoch boundary. --highest-version must be explicitly passed if the user wants versions beyond the epoch boundary (this is still experimental). --- ol/cli/src/commands/restore_cmd.rs | 11 ++++------- ol/cli/src/mgmt/restore.rs | 15 +++++++-------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/ol/cli/src/commands/restore_cmd.rs b/ol/cli/src/commands/restore_cmd.rs index 9423366361..cb1b8c28b8 100644 --- a/ol/cli/src/commands/restore_cmd.rs +++ b/ol/cli/src/commands/restore_cmd.rs @@ -21,18 +21,15 @@ pub struct RestoreCmd { #[options(short="v", help = "specify a version or height if there is more than one per archive")] version: Option, - #[options(short="b", help = "only restore the boundary, not an advanced version.")] - boundary_only: bool, - - #[options(help = "get only the exact last block at the end of an epoch. Not extra blocks at the start of following epoch.")] - exclude_buffer: bool, + #[options(short="h", help = "fetch the highest version available, of the latest epoch.")] + highest_version: bool, } impl Runnable for RestoreCmd { /// Start the application. fn run(&self) { - match mgmt::restore::fast_forward_db(self.verbose, self.epoch, self.version, self.boundary_only) { - Ok(_) => {}, + match mgmt::restore::fast_forward_db(self.verbose, self.epoch, self.version, self.highest_version) { + Ok(_) => {println!("SUCCESS")}, Err(e) => println!("ERROR: could not complete db restore, message: {:?}", e), }; } diff --git a/ol/cli/src/mgmt/restore.rs b/ol/cli/src/mgmt/restore.rs index 0f4a3deaa9..d74d53adab 100644 --- a/ol/cli/src/mgmt/restore.rs +++ b/ol/cli/src/mgmt/restore.rs @@ -53,7 +53,7 @@ pub fn fast_forward_db( verbose: bool, epoch: Option, version_opt: Option, - boundary_only: bool, + highest_version: bool, ) -> Result<(), Error> { let mut backup = Backup::new(epoch); @@ -64,14 +64,13 @@ pub fn fast_forward_db( backup.set_waypoint()?; println!("\nRestoring db from archive to home path"); - backup.restore_backup(verbose, version_opt, boundary_only)?; + backup.restore_backup(verbose, version_opt, highest_version)?; println!("\nCreating fullnode.node.yaml to home path"); backup.create_fullnode_yaml()?; println!("\nResetting Safety Data in key_store.json\n"); diem_genesis_tool::key::reset_safety_data(&backup.home_path, &backup.node_namespace); - println!("SUCCESS"); Ok(()) } @@ -180,10 +179,8 @@ impl Backup { &self, verbose: bool, version_opt: Option, - boundary_only: bool, + highest_version: bool, ) -> Result<(), Error> { - dbg!(&version_opt); - let db_path = &self.home_path.join("db/"); let restore_path = self.restore_path.clone(); @@ -204,8 +201,10 @@ impl Backup { verbose, )?; - // Restore an advanced version in the epoch - if !boundary_only { + // Only restore a Version beyond the epoch boundary if explicitly requested + if highest_version || version_opt.is_some() { + println!("WARN: restoring a version beyond epoch boundary is EXPERIMENTAL"); + let version = version_opt.unwrap_or(get_heighest_version(restore_path)?); let restore_path_for_version = self.restore_path.to_owned().join(version.to_string()); From c61e4cb2997e7a0504749b8c647d710f324bb2c2 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Sun, 19 Jun 2022 15:40:23 -0400 Subject: [PATCH 30/45] ol serve: deprecating the --run-checks or -c option. We now assume the user wants to run checks while running the web-monitor --- ol/cli/src/commands/serve_cmd.rs | 6 +++--- ol/cli/src/server.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ol/cli/src/commands/serve_cmd.rs b/ol/cli/src/commands/serve_cmd.rs index 79320514e1..1d1a8c3b39 100644 --- a/ol/cli/src/commands/serve_cmd.rs +++ b/ol/cli/src/commands/serve_cmd.rs @@ -8,7 +8,7 @@ use abscissa_core::{Command, Options, Runnable}; #[derive(Command, Debug, Options)] pub struct ServeCmd { /// Start healthcheck runner - #[options(short = "c", help = "start health check runner")] + #[options(short = "c", help = "deprecation notice: -c is no longer valid. Previously it was necessary if healthchecks were to be updated while server is running, but now we assume that is the intention of the user.")] run_checks: bool, /// Update the web files #[options(no_short, help = "update web files for server")] @@ -32,8 +32,8 @@ impl Runnable for ServeCmd { }, }; let mut node = Node::new(client, &cfg, is_swarm); - server::init(&mut node, self.run_checks); - server::start_server(node, self.run_checks); + server::init(&mut node, true); + server::start_server(node, true); } } } diff --git a/ol/cli/src/server.rs b/ol/cli/src/server.rs index 4d7b5be6a6..18b82c0cc3 100644 --- a/ol/cli/src/server.rs +++ b/ol/cli/src/server.rs @@ -14,14 +14,14 @@ use crate::{cache::Vitals, check::runner, node::node::Node}; #[tokio::main] /// starts the web server -pub async fn start_server(mut node: Node, run_checks: bool) { +pub async fn start_server(mut node: Node, _run_checks: bool) { let cfg = node.app_conf.clone(); - if run_checks { + // if run_checks { thread::spawn(move || { runner::run_checks(&mut node, false, true, false, false); }); - } + // } //GET check/ (json api for check data) let node_home = cfg.clone().workspace.node_home.clone(); @@ -82,15 +82,15 @@ pub async fn start_server(mut node: Node, run_checks: bool) { } /// Prepare to start server -pub fn init(node: &mut Node, run_checks: bool) { - if run_checks { +pub fn init(node: &mut Node, _run_checks: bool) { + // if run_checks { /* Initialize cache to avoid: - read a cache file not created yet - load old cache with invalid structs */ node.check_once(false); - } + // } } fn sse_vitals(data: Vitals) -> Result { From 5f7945f6a1ef4706c4047f12da35d1e497e1faf9 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Mon, 20 Jun 2022 14:43:37 -0400 Subject: [PATCH 31/45] improve error messages on safety rules initialize --- consensus/src/metrics_safety_rules.rs | 3 ++- storage/diemdb/src/ledger_store/mod.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/consensus/src/metrics_safety_rules.rs b/consensus/src/metrics_safety_rules.rs index bfa7d7ef4e..064e2a6c1f 100644 --- a/consensus/src/metrics_safety_rules.rs +++ b/consensus/src/metrics_safety_rules.rs @@ -34,7 +34,8 @@ impl MetricsSafetyRules { .retrieve_epoch_change_proof(sr_waypoint.version()) .map_err(|e| { Error::InternalError(format!( - "Unable to retrieve Waypoint state from storage, encountered Error:{}", + "Unable to retrieve epoch change proof from storage for Waypoint. State for version {} not found. Error:{}", + &sr_waypoint.version(), e )) })?; diff --git a/storage/diemdb/src/ledger_store/mod.rs b/storage/diemdb/src/ledger_store/mod.rs index e7395b26de..d46052588a 100644 --- a/storage/diemdb/src/ledger_store/mod.rs +++ b/storage/diemdb/src/ledger_store/mod.rs @@ -372,7 +372,7 @@ impl HashReader for LedgerStore { fn get(&self, position: Position) -> Result { self.db .get::(&position)? - .ok_or_else(|| format_err!("{} does not exist.", position)) + .ok_or_else(|| format_err!("Accumulator error. {} does not exist.", position)) } } From 2603123b6ba6742d0c433c6eb6eeb40675f12626 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Mon, 20 Jun 2022 16:02:11 -0400 Subject: [PATCH 32/45] validator should panic on trying to startup safety rules --- consensus/src/epoch_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensus/src/epoch_manager.rs b/consensus/src/epoch_manager.rs index e4f121eace..80a600ad46 100644 --- a/consensus/src/epoch_manager.rs +++ b/consensus/src/epoch_manager.rs @@ -303,7 +303,7 @@ impl EpochManager { let mut safety_rules = MetricsSafetyRules::new(self.safety_rules_manager.client(), self.storage.clone()); if let Err(error) = safety_rules.perform_initialize() { - error!( + panic!( epoch = epoch, error = error, "Unable to initialize safety rules.", From a64464d0a2144ee21ca7c3715b27ddb26b3b80c0 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Mon, 20 Jun 2022 17:58:21 -0400 Subject: [PATCH 33/45] patch --- consensus/src/epoch_manager.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/consensus/src/epoch_manager.rs b/consensus/src/epoch_manager.rs index 80a600ad46..9de974a015 100644 --- a/consensus/src/epoch_manager.rs +++ b/consensus/src/epoch_manager.rs @@ -304,9 +304,7 @@ impl EpochManager { MetricsSafetyRules::new(self.safety_rules_manager.client(), self.storage.clone()); if let Err(error) = safety_rules.perform_initialize() { panic!( - epoch = epoch, - error = error, - "Unable to initialize safety rules.", + "Unable to initialize safety rules, epoch: {}, error: {}", epoch, error ); } From d6f393a39aa7d1ba6cf4b31a704d0d7da3871a80 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Mon, 20 Jun 2022 18:03:57 -0400 Subject: [PATCH 34/45] makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 59b34d977e..fb3c2c8ff6 100644 --- a/Makefile +++ b/Makefile @@ -500,7 +500,7 @@ testnet: clear fix testnet-init testnet-genesis start testnet-onboard: clear fix MNEM='${MNEM}' cargo run -p onboard -- val --github-org OLSF --repo dev-genesis --chain-id 1 # start a node with fullnode.node.yaml configs - make start + cargo r -p diem-node -- -f ~/.0L/fullnode.node.yaml From 0dca4b0936b7c7bafb2a1c16ca0aff17fd44c653 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Tue, 12 Jul 2022 15:26:52 -0400 Subject: [PATCH 35/45] make testnet start with alice, bob, carol only --- ol/devnet/set_layout_test.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ol/devnet/set_layout_test.toml b/ol/devnet/set_layout_test.toml index df47b489dd..3f485096ac 100644 --- a/ol/devnet/set_layout_test.toml +++ b/ol/devnet/set_layout_test.toml @@ -2,11 +2,11 @@ owners = [ "4c613c2f4b1e67ca8d98a542ee3f59f5", "88e74dfed34420f2ad8032148280a84b", "e660402d586ad220ed9beff47d662d54", - "9e6bb3a75e9618fba057e86e69338c94" + # "9e6bb3a75e9618fba057e86e69338c94" ] operators = [ "4c613c2f4b1e67ca8d98a542ee3f59f5-oper", "88e74dfed34420f2ad8032148280a84b-oper", "e660402d586ad220ed9beff47d662d54-oper", - "9e6bb3a75e9618fba057e86e69338c94-oper" + # "9e6bb3a75e9618fba057e86e69338c94-oper" ] From 3fc0ba38fcf8337e604b7f7960066d4e8f47aef9 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Tue, 12 Jul 2022 15:51:23 -0400 Subject: [PATCH 36/45] add execution.genesis_file_location to fullnode yaml --- config/management/genesis/src/ol_node_files.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/config/management/genesis/src/ol_node_files.rs b/config/management/genesis/src/ol_node_files.rs index 1a663653d6..b588c06083 100644 --- a/config/management/genesis/src/ol_node_files.rs +++ b/config/management/genesis/src/ol_node_files.rs @@ -293,6 +293,7 @@ pub fn make_fullnode_cfg( c.set_data_dir(output_dir.clone()); c.base.waypoint = WaypointConfig::FromConfig(waypoint); c.base.role = RoleType::FullNode; + c.execution.genesis_file_location = output_dir.clone().join("genesis.blob"); // c.execution.genesis_file_location = output_dir.clone().join("genesis.blob"); // prune window exists to prevent state snapshots from taking up too much space. c.storage.prune_window = Some(100_000); From 74fe43dc420813ce3682fd008d8b106a520d7a6f Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Tue, 12 Jul 2022 16:07:03 -0400 Subject: [PATCH 37/45] set layout to have 5 addresses for testnet genesis --- ol/devnet/set_layout_test.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ol/devnet/set_layout_test.toml b/ol/devnet/set_layout_test.toml index 3f485096ac..011b7a367f 100644 --- a/ol/devnet/set_layout_test.toml +++ b/ol/devnet/set_layout_test.toml @@ -2,11 +2,13 @@ owners = [ "4c613c2f4b1e67ca8d98a542ee3f59f5", "88e74dfed34420f2ad8032148280a84b", "e660402d586ad220ed9beff47d662d54", - # "9e6bb3a75e9618fba057e86e69338c94" + "9e6bb3a75e9618fba057e86e69338c94", + "3dc18d1cf61faac6ac70e3a63f062e4b" ] operators = [ "4c613c2f4b1e67ca8d98a542ee3f59f5-oper", "88e74dfed34420f2ad8032148280a84b-oper", "e660402d586ad220ed9beff47d662d54-oper", - # "9e6bb3a75e9618fba057e86e69338c94-oper" + "9e6bb3a75e9618fba057e86e69338c94-oper", + "3dc18d1cf61faac6ac70e3a63f062e4b-oper" ] From b3deb520666c516ece0f9802a273939776478c2f Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Tue, 12 Jul 2022 16:14:48 -0400 Subject: [PATCH 38/45] alway use cargo release mode even in testnet --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fb3c2c8ff6..b7c01eaf3c 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ CARGO_ARGS = --release ifeq (${TEST}, y) REPO_NAME = dev-genesis MNEM = $(shell cat ol/fixtures/mnemonic/${NS}.mnem) -CARGO_ARGS = --locked # just keeping this from doing --release mode, while in testnet mode. +#CARGO_ARGS = --locked # just keeping this from doing --release mode, while in testnet mode. GITHUB_USER = OLSF endif From cd215bad139c9eb2c18cc288c292dacac479d7b5 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Tue, 12 Jul 2022 16:16:24 -0400 Subject: [PATCH 39/45] undo --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b7c01eaf3c..fb3c2c8ff6 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ CARGO_ARGS = --release ifeq (${TEST}, y) REPO_NAME = dev-genesis MNEM = $(shell cat ol/fixtures/mnemonic/${NS}.mnem) -#CARGO_ARGS = --locked # just keeping this from doing --release mode, while in testnet mode. +CARGO_ARGS = --locked # just keeping this from doing --release mode, while in testnet mode. GITHUB_USER = OLSF endif From 3cecb9e4802e923424dfd832d1a73a19f5d7b179 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Tue, 12 Jul 2022 16:31:34 -0400 Subject: [PATCH 40/45] update fixture files with ip addresses for reference. --- ol/fixtures/configs/alice.toml | 2 +- ol/fixtures/configs/carol.toml | 2 +- ol/fixtures/configs/dave.toml | 2 +- ol/fixtures/configs/eve.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ol/fixtures/configs/alice.toml b/ol/fixtures/configs/alice.toml index 5266af0ab3..74cd5c2f08 100644 --- a/ol/fixtures/configs/alice.toml +++ b/ol/fixtures/configs/alice.toml @@ -8,7 +8,7 @@ db_path = "/root/.0L/db" [profile] account = "4c613c2f4b1e67ca8d98a542ee3f59f5" auth_key = "87515d94a244235a1433d7117bc0cb154c613c2f4b1e67ca8d98a542ee3f59f5" -ip = "148.251.89.142" +ip = "143.198.128.132" statement = "Protests rage across the nation" default_node = "http://localhost:8080/" diff --git a/ol/fixtures/configs/carol.toml b/ol/fixtures/configs/carol.toml index 90d712bba1..70aaf9d8da 100644 --- a/ol/fixtures/configs/carol.toml +++ b/ol/fixtures/configs/carol.toml @@ -8,7 +8,7 @@ db_path = "/root/.0L/db" [profile] account = "e660402d586ad220ed9beff47d662d54" auth_key = "926945e56bc68675380bb3a4bbcc3a31e660402d586ad220ed9beff47d662d54" -ip = "91.229.245.110" +ip = "164.92.118.4" statement = "Protests rage across the nation" default_node = "http://localhost:8080/" upstream_nodes = ["http://localhost:8080/"] diff --git a/ol/fixtures/configs/dave.toml b/ol/fixtures/configs/dave.toml index f856f9e1dd..65d925ff06 100644 --- a/ol/fixtures/configs/dave.toml +++ b/ol/fixtures/configs/dave.toml @@ -8,7 +8,7 @@ db_path = "/root/.0L/db" [profile] account = "9e6bb3a75e9618fba057e86e69338c94" auth_key = "9a6e2193488991b62dd28b47d60dd03b9e6bb3a75e9618fba057e86e69338c94" -ip = "104.131.32.62" +ip = "34.73.79.16" statement = "Protests rage across the nation" default_node = "http://localhost:8080/" upstream_nodes = ["http://localhost:8080/"] diff --git a/ol/fixtures/configs/eve.toml b/ol/fixtures/configs/eve.toml index beacbc7dd1..88d49232d6 100644 --- a/ol/fixtures/configs/eve.toml +++ b/ol/fixtures/configs/eve.toml @@ -9,7 +9,7 @@ db_path = "/root/.0L/db" account = "3dc18d1cf61faac6ac70e3a63f062e4b" auth_key = "2bffcbd0e9016013cb8ca78459f69d2b3dc18d1cf61faac6ac70e3a63f062e4b" statement = "Protests rage across the nation" -ip = "157.230.15.42" +ip = "34.162.237.59" default_node = "http://localhost:8080/" upstream_nodes = ["http://localhost:8080/"] From faa81ac19c7dd843d85e11a1c152239f09c027bf Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Sat, 23 Jul 2022 22:01:57 +0000 Subject: [PATCH 41/45] patch validator yaml file generation --- config/management/genesis/src/ol_node_files.rs | 6 ++++-- ol/cli/src/commands/init_cmd.rs | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/config/management/genesis/src/ol_node_files.rs b/config/management/genesis/src/ol_node_files.rs index b588c06083..591834f23d 100644 --- a/config/management/genesis/src/ol_node_files.rs +++ b/config/management/genesis/src/ol_node_files.rs @@ -368,7 +368,8 @@ fn make_validator_cfg(output_dir: PathBuf, namespace: &str, seed_addresses: Opti vfn_net.listen_address = format!("/ip4/0.0.0.0/tcp/{}", DEFAULT_VFN_PORT).parse()?; let mut pub_net = NetworkConfig::network_with_id(NetworkId::Public); - pub_net.listen_address = format!("/ip4/0.0.0.0/tcp/{}", DEFAULT_PUB_PORT).parse()?; + + pub_net.listen_address = format!("/ip4/127.0.0.1/tcp/{}", DEFAULT_PUB_PORT).parse()?; // Don't fullnode sync requests // This ID is how the Validator node identifies themselves on their private VFN network. // same ID as being used in the validator network. @@ -376,9 +377,10 @@ fn make_validator_cfg(output_dir: PathBuf, namespace: &str, seed_addresses: Opti pub_net.identity = network_id; if let Some(s) = seed_addresses { - vfn_net.seed_addrs = s.clone(); pub_net.seed_addrs = s; } + + // pub_net.discovery_method = DiscoveryMethod::Onchain; c.full_node_networks = vec![vfn_net.to_owned(), pub_net.to_owned()]; diff --git a/ol/cli/src/commands/init_cmd.rs b/ol/cli/src/commands/init_cmd.rs index bc54804421..155e3acc99 100644 --- a/ol/cli/src/commands/init_cmd.rs +++ b/ol/cli/src/commands/init_cmd.rs @@ -202,8 +202,9 @@ impl Runnable for InitCmd { let namespace = app_cfg.format_oper_namespace(); let output_dir = app_cfg.workspace.node_home.clone(); - let seeds = pick_seed_peer(&mut app_cfg, entry_args.swarm_path.clone()); - match ol_node_files::make_val_file(output_dir, seeds.ok(), None, &namespace) { + let seeds = if self.seed_peer { pick_seed_peer(&mut app_cfg, entry_args.swarm_path.clone()).ok() } else { None }; + + match ol_node_files::make_val_file(output_dir, seeds,None, &namespace) { Ok(_) => {} Err(e) => { println!("Could not create file, exiting. Message: {:?}", e); From 4b5d7ad20a886a70754d8ddc4f5ef6f633f462a3 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Sat, 23 Jul 2022 22:27:05 +0000 Subject: [PATCH 42/45] ol start doesn't need to swtich between validator and fullnode mode with the new configs! --- ol/cli/src/check/pilot.rs | 138 +++++++++++++++---------------- ol/cli/src/commands/mgmt_cmd.rs | 4 +- ol/cli/src/commands/start_cmd.rs | 2 +- ol/cli/src/mgmt/management.rs | 7 +- ol/cli/src/node/client.rs | 10 ++- 5 files changed, 79 insertions(+), 82 deletions(-) diff --git a/ol/cli/src/check/pilot.rs b/ol/cli/src/check/pilot.rs index 49c88d6403..ce1410b33a 100644 --- a/ol/cli/src/check/pilot.rs +++ b/ol/cli/src/check/pilot.rs @@ -3,7 +3,6 @@ #![allow(clippy::never_loop)] use crate::node::states::*; use crate::{ - mgmt::management::NodeMode::*, node::node::Node, }; use std::{thread, time::Duration}; @@ -53,31 +52,24 @@ pub fn run_once(mut node: &mut Node, verbose: bool) -> &mut Node { } // is node started? - if node.vitals.items.node_running { - if verbose { - println!("Node: node is running"); - } - node.vitals.host_state.node_state = maybe_switch_mode(&mut node, is_in_val_set, verbose); - } else { - let start_mode = if is_in_val_set { Validator } else { Fullnode }; + if !node.vitals.items.node_running { + // if verbose { + // println!("Node: node is running"); + // } + // node.vitals.host_state.node_state = maybe_switch_mode(&mut node, is_in_val_set, verbose); + // } else { + // let start_mode = if is_in_val_set { Validator } else { Fullnode }; if verbose { println!( - "Node: WARN: node is NOT running, starting in {:?} mode", - &start_mode - ); + "Node: WARN: node is NOT running, starting node"); } - node.vitals.host_state.node_state = match node.start_node(start_mode.clone(), verbose) { - Ok(_) => match &start_mode { - Validator => NodeState::ValidatorMode, - Fullnode => NodeState::FullnodeMode, - }, + node.vitals.host_state.node_state = match node.start_node(verbose) { + Ok(_) => NodeState::ValidatorOutOfSet, Err(_) => { - if verbose { - println!(".. Node: WARN: could not start node in: {:?}", &start_mode); - } - NodeState::Stopped + println!(".. Node: WARN: could not start node"); + NodeState::Stopped } } } @@ -131,56 +123,56 @@ pub fn run_once(mut node: &mut Node, verbose: bool) -> &mut Node { node } -fn maybe_switch_mode(node: &mut Node, is_in_val_set: bool, verbose: bool) -> NodeState { - let running_mode = match Node::what_node_mode() { - Ok(t) => t, - Err(_) => return NodeState::Stopped, - }; - - if verbose { - println!(".. Mode: node running in mode: {:?}", running_mode); - } - - let running_in_val_mode = running_mode == Validator; - // Running correctly as a FULLNODE - if !running_in_val_mode && !is_in_val_set { - if verbose { - println!(".... Mode: running the correct mode",); - } - return NodeState::FullnodeMode; - } - // Running correctly as a VALIDATOR - // Do nothing, the account is in validator set, and we are running as a validator - if running_in_val_mode && is_in_val_set { - if verbose { - println!(".... Mode: running the correct mode"); - } - return NodeState::ValidatorMode; - } - - // INCORRECT CASE 1: Need to change mode from Fullnode to Validator mode - if !running_in_val_mode && is_in_val_set { - if verbose { - println!(".... Mode: WARN: running the INCORRECT mode, switching to VALIDATOR mode"); - } - node.stop_node(); - node.start_node(Validator, verbose) - .expect("could not start node"); - - return NodeState::ValidatorMode; - } - - // INCORRECT CASE 2: Need to change mode from Validator to Fullnode mode - if running_in_val_mode && !is_in_val_set { - if verbose { - println!(".... Mode: WARN: running the INCORRECT mode, switching to FULLNODE mode"); - } - node.stop_node(); - node.start_node(Validator, verbose) - .expect("could not start node"); - - return NodeState::FullnodeMode; - } - - NodeState::Stopped -} +// fn maybe_switch_mode(node: &mut Node, is_in_val_set: bool, verbose: bool) -> NodeState { +// let running_mode = match Node::what_node_mode() { +// Ok(t) => t, +// Err(_) => return NodeState::Stopped, +// }; + +// if verbose { +// println!(".. Mode: node running in mode: {:?}", running_mode); +// } + +// let running_in_val_mode = running_mode == Validator; +// // Running correctly as a FULLNODE +// if !running_in_val_mode && !is_in_val_set { +// if verbose { +// println!(".... Mode: running the correct mode",); +// } +// return NodeState::FullnodeMode; +// } +// // Running correctly as a VALIDATOR +// // Do nothing, the account is in validator set, and we are running as a validator +// if running_in_val_mode && is_in_val_set { +// if verbose { +// println!(".... Mode: running the correct mode"); +// } +// return NodeState::ValidatorMode; +// } + +// // INCORRECT CASE 1: Need to change mode from Fullnode to Validator mode +// if !running_in_val_mode && is_in_val_set { +// if verbose { +// println!(".... Mode: WARN: running the INCORRECT mode, switching to VALIDATOR mode"); +// } +// node.stop_node(); +// node.start_node(verbose) +// .expect("could not start node"); + +// return NodeState::ValidatorMode; +// } + +// // INCORRECT CASE 2: Need to change mode from Validator to Fullnode mode +// if running_in_val_mode && !is_in_val_set { +// if verbose { +// println!(".... Mode: WARN: running the INCORRECT mode, switching to FULLNODE mode"); +// } +// node.stop_node(); +// node.start_node(Validator, verbose) +// .expect("could not start node"); + +// return NodeState::FullnodeMode; +// } + +// NodeState::Stopped +// } diff --git a/ol/cli/src/commands/mgmt_cmd.rs b/ol/cli/src/commands/mgmt_cmd.rs index 1246f87dfa..52293076fa 100644 --- a/ol/cli/src/commands/mgmt_cmd.rs +++ b/ol/cli/src/commands/mgmt_cmd.rs @@ -1,6 +1,6 @@ //! `mgmt` subcommand -use crate::{application::app_config, entrypoint, mgmt::management::NodeMode, node::{client, node::Node}}; +use crate::{application::app_config, entrypoint, node::{client, node::Node}}; use abscissa_core::{Command, Options, Runnable}; /// management subcommands @@ -31,7 +31,7 @@ impl Runnable for MgmtCmd { let mut node = Node::new(client, &cfg, is_swarm); if self.start_node { - node.start_node(NodeMode::Fullnode, true).expect("could not start fullnode"); + node.start_node(true).expect("could not start fullnode"); } else if self.stop_node { node.stop_node(); } else if self.start_miner { diff --git a/ol/cli/src/commands/start_cmd.rs b/ol/cli/src/commands/start_cmd.rs index 290aa5f688..610c98ace6 100644 --- a/ol/cli/src/commands/start_cmd.rs +++ b/ol/cli/src/commands/start_cmd.rs @@ -26,7 +26,7 @@ impl Runnable for StartCmd { let client = match client::pick_client(args.swarm_path, &mut cfg) { Ok(c) => c, Err(e) => { - println!("ERROR: Could not create a client to connect to network, exiting. Message: {:?}", e ); + println!("ERROR: Could not create a client to connect to network. Will not be able to send txs. Exiting. Message: {:?}", e ); exit(1); }, }; diff --git a/ol/cli/src/mgmt/management.rs b/ol/cli/src/mgmt/management.rs index f446f1e115..f6479d6312 100644 --- a/ol/cli/src/mgmt/management.rs +++ b/ol/cli/src/mgmt/management.rs @@ -58,7 +58,7 @@ fn spawn_process( impl Node { /// Start Node, as fullnode - pub fn start_node(&mut self, config_type: NodeMode, verbose: bool) -> Result<(), Error> { + pub fn start_node(&mut self, verbose: bool) -> Result<(), Error> { use BINARY_NODE as NODE; // if is running do nothing // TODO: Get another check of node running @@ -72,10 +72,7 @@ impl Node { // Start as validator or fullnode let conf = app_config(); let node_home = conf.workspace.node_home.to_str().unwrap(); - let config_file_name = match config_type { - NodeMode::Validator => format!("{}validator.node.yaml", node_home), - NodeMode::Fullnode => format!("{}fullnode.node.yaml", node_home), - }; + let config_file_name = format!("{}validator.node.yaml", node_home); let child = if *IS_PROD { let args = vec!["--config", &config_file_name]; diff --git a/ol/cli/src/node/client.rs b/ol/cli/src/node/client.rs index bb3ab6fdaf..456fc35745 100644 --- a/ol/cli/src/node/client.rs +++ b/ol/cli/src/node/client.rs @@ -116,7 +116,15 @@ pub fn pick_client(swarm_path: Option, config: &mut AppCfg) -> Result r, + // If we can't connect to any remotes, return the local client. + Err(e) => { + println!("{:?}", e); + return Ok(local_client) + }, + }; // compares to an upstream random remote client. If it is synced, use the local client as the default let mut node = Node::new(local_client, config, is_swarm); match node.check_sync()?.is_synced { From 0c05a65772a8b35a44a12aa13d4ffefb3f5a9982 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Mon, 25 Jul 2022 16:00:00 -0400 Subject: [PATCH 43/45] make pubnet config use onchain discovery --- config/management/genesis/src/ol_node_files.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/management/genesis/src/ol_node_files.rs b/config/management/genesis/src/ol_node_files.rs index 591834f23d..ea2d4d4e98 100644 --- a/config/management/genesis/src/ol_node_files.rs +++ b/config/management/genesis/src/ol_node_files.rs @@ -380,7 +380,7 @@ fn make_validator_cfg(output_dir: PathBuf, namespace: &str, seed_addresses: Opti pub_net.seed_addrs = s; } - // pub_net.discovery_method = DiscoveryMethod::Onchain; + pub_net.discovery_method = DiscoveryMethod::Onchain; c.full_node_networks = vec![vfn_net.to_owned(), pub_net.to_owned()]; From 772206d61b97d7bca7386abbf86b5fa94293ec16 Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Mon, 25 Jul 2022 17:13:20 -0400 Subject: [PATCH 44/45] remove setting for fullnode identity in validator file --- config/management/genesis/src/ol_node_files.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/management/genesis/src/ol_node_files.rs b/config/management/genesis/src/ol_node_files.rs index ea2d4d4e98..e7187d731b 100644 --- a/config/management/genesis/src/ol_node_files.rs +++ b/config/management/genesis/src/ol_node_files.rs @@ -373,8 +373,8 @@ fn make_validator_cfg(output_dir: PathBuf, namespace: &str, seed_addresses: Opti // This ID is how the Validator node identifies themselves on their private VFN network. // same ID as being used in the validator network. - vfn_net.identity = network_id.clone(); - pub_net.identity = network_id; + // Note that the the public network has no setting, so that it is randomly generated. + vfn_net.identity = network_id; if let Some(s) = seed_addresses { pub_net.seed_addrs = s; From dfd02294203c37cfdebb9a32c664507a03b9560b Mon Sep 17 00:00:00 2001 From: 0o-de-lally <1364012+0o-de-lally@users.noreply.github.com> Date: Mon, 25 Jul 2022 18:55:01 -0400 Subject: [PATCH 45/45] rename ol restore option highest_version -> latest_version --- ol/cli/src/commands/restore_cmd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ol/cli/src/commands/restore_cmd.rs b/ol/cli/src/commands/restore_cmd.rs index cb1b8c28b8..466fab041b 100644 --- a/ol/cli/src/commands/restore_cmd.rs +++ b/ol/cli/src/commands/restore_cmd.rs @@ -21,8 +21,8 @@ pub struct RestoreCmd { #[options(short="v", help = "specify a version or height if there is more than one per archive")] version: Option, - #[options(short="h", help = "fetch the highest version available, of the latest epoch.")] - highest_version: bool, + #[options(short="l", help = "fetch the highest version available, of the latest epoch.")] + latest_version: bool, } impl Runnable for RestoreCmd {