(cherry picked from commit 0f76077969)
Co-authored-by: Michael Vines <mvines@gmail.com>
			
			
This commit is contained in:
		@@ -88,3 +88,28 @@ Post something like the following to #announcements (adjusting the text as appro
 | 
				
			|||||||
### Step 7. Wait and listen
 | 
					### Step 7. Wait and listen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Monitor the validators as they restart. Answer questions, help folks,
 | 
					Monitor the validators as they restart. Answer questions, help folks,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Troubleshooting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 80% of the stake didn't participate in the restart, now what?
 | 
				
			||||||
 | 
					If less than 80% of the stake join the restart after a reasonable amount of
 | 
				
			||||||
 | 
					time, it will be necessary to retry the restart attempt with the stake from the
 | 
				
			||||||
 | 
					non-responsive validators removed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The community should identify and come to social consensus on the set of
 | 
				
			||||||
 | 
					non-responsive validators. Then all participating validators return to Step 4
 | 
				
			||||||
 | 
					and create a new snapshot with additional `--destake-vote-account <PUBKEY>`
 | 
				
			||||||
 | 
					arguments for each of the non-responsive validator's vote account address
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					$ solana-ledger-tool -l ledger create-snapshot SLOT_X ledger --hard-fork SLOT_X \
 | 
				
			||||||
 | 
					    --destake-vote-account <VOTE_ACCOUNT_1> \
 | 
				
			||||||
 | 
					    --destake-vote-account <VOTE_ACCOUNT_2> \
 | 
				
			||||||
 | 
					    .
 | 
				
			||||||
 | 
					    .
 | 
				
			||||||
 | 
					    --destake-vote-account <VOTE_ACCOUNT_N> \
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This will cause all stake associated with the non-responsive validators to be
 | 
				
			||||||
 | 
					immediately deactivated. All their stakers will need to re-delegate their stake
 | 
				
			||||||
 | 
					once the cluster restart is successful.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,6 +32,7 @@ use solana_runtime::{
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
use solana_sdk::{
 | 
					use solana_sdk::{
 | 
				
			||||||
    account::{AccountSharedData, ReadableAccount, WritableAccount},
 | 
					    account::{AccountSharedData, ReadableAccount, WritableAccount},
 | 
				
			||||||
 | 
					    account_utils::StateMut,
 | 
				
			||||||
    clock::{Epoch, Slot},
 | 
					    clock::{Epoch, Slot},
 | 
				
			||||||
    genesis_config::{ClusterType, GenesisConfig},
 | 
					    genesis_config::{ClusterType, GenesisConfig},
 | 
				
			||||||
    hash::Hash,
 | 
					    hash::Hash,
 | 
				
			||||||
@@ -1224,6 +1225,16 @@ fn main() {
 | 
				
			|||||||
                    .multiple(true)
 | 
					                    .multiple(true)
 | 
				
			||||||
                    .help("List of accounts to remove while creating the snapshot"),
 | 
					                    .help("List of accounts to remove while creating the snapshot"),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					            .arg(
 | 
				
			||||||
 | 
					                Arg::with_name("vote_accounts_to_destake")
 | 
				
			||||||
 | 
					                    .required(false)
 | 
				
			||||||
 | 
					                    .long("destake-vote-account")
 | 
				
			||||||
 | 
					                    .takes_value(true)
 | 
				
			||||||
 | 
					                    .value_name("PUBKEY")
 | 
				
			||||||
 | 
					                    .validator(is_pubkey)
 | 
				
			||||||
 | 
					                    .multiple(true)
 | 
				
			||||||
 | 
					                    .help("List of validator vote accounts to destake")
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
            .arg(
 | 
					            .arg(
 | 
				
			||||||
                Arg::with_name("remove_stake_accounts")
 | 
					                Arg::with_name("remove_stake_accounts")
 | 
				
			||||||
                    .required(false)
 | 
					                    .required(false)
 | 
				
			||||||
@@ -1433,6 +1444,7 @@ fn main() {
 | 
				
			|||||||
    let wal_recovery_mode = matches
 | 
					    let wal_recovery_mode = matches
 | 
				
			||||||
        .value_of("wal_recovery_mode")
 | 
					        .value_of("wal_recovery_mode")
 | 
				
			||||||
        .map(BlockstoreRecoveryMode::from);
 | 
					        .map(BlockstoreRecoveryMode::from);
 | 
				
			||||||
 | 
					    let verbose_level = matches.occurrences_of("verbose");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    match matches.subcommand() {
 | 
					    match matches.subcommand() {
 | 
				
			||||||
        ("bigtable", Some(arg_matches)) => bigtable_process_command(&ledger_path, arg_matches),
 | 
					        ("bigtable", Some(arg_matches)) => bigtable_process_command(&ledger_path, arg_matches),
 | 
				
			||||||
@@ -1442,7 +1454,6 @@ fn main() {
 | 
				
			|||||||
            let num_slots = value_t!(arg_matches, "num_slots", Slot).ok();
 | 
					            let num_slots = value_t!(arg_matches, "num_slots", Slot).ok();
 | 
				
			||||||
            let allow_dead_slots = arg_matches.is_present("allow_dead_slots");
 | 
					            let allow_dead_slots = arg_matches.is_present("allow_dead_slots");
 | 
				
			||||||
            let only_rooted = arg_matches.is_present("only_rooted");
 | 
					            let only_rooted = arg_matches.is_present("only_rooted");
 | 
				
			||||||
            let verbose = matches.occurrences_of("verbose");
 | 
					 | 
				
			||||||
            output_ledger(
 | 
					            output_ledger(
 | 
				
			||||||
                open_blockstore(
 | 
					                open_blockstore(
 | 
				
			||||||
                    &ledger_path,
 | 
					                    &ledger_path,
 | 
				
			||||||
@@ -1454,7 +1465,7 @@ fn main() {
 | 
				
			|||||||
                allow_dead_slots,
 | 
					                allow_dead_slots,
 | 
				
			||||||
                LedgerOutputMethod::Print,
 | 
					                LedgerOutputMethod::Print,
 | 
				
			||||||
                num_slots,
 | 
					                num_slots,
 | 
				
			||||||
                verbose,
 | 
					                verbose_level,
 | 
				
			||||||
                only_rooted,
 | 
					                only_rooted,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -1877,6 +1888,11 @@ fn main() {
 | 
				
			|||||||
            let bootstrap_validator_pubkeys = pubkeys_of(arg_matches, "bootstrap_validator");
 | 
					            let bootstrap_validator_pubkeys = pubkeys_of(arg_matches, "bootstrap_validator");
 | 
				
			||||||
            let accounts_to_remove =
 | 
					            let accounts_to_remove =
 | 
				
			||||||
                pubkeys_of(arg_matches, "accounts_to_remove").unwrap_or_default();
 | 
					                pubkeys_of(arg_matches, "accounts_to_remove").unwrap_or_default();
 | 
				
			||||||
 | 
					            let vote_accounts_to_destake: HashSet<_> =
 | 
				
			||||||
 | 
					                pubkeys_of(arg_matches, "vote_accounts_to_destake")
 | 
				
			||||||
 | 
					                    .unwrap_or_default()
 | 
				
			||||||
 | 
					                    .into_iter()
 | 
				
			||||||
 | 
					                    .collect();
 | 
				
			||||||
            let snapshot_version =
 | 
					            let snapshot_version =
 | 
				
			||||||
                arg_matches
 | 
					                arg_matches
 | 
				
			||||||
                    .value_of("snapshot_version")
 | 
					                    .value_of("snapshot_version")
 | 
				
			||||||
@@ -1937,6 +1953,7 @@ fn main() {
 | 
				
			|||||||
                        || hashes_per_tick.is_some()
 | 
					                        || hashes_per_tick.is_some()
 | 
				
			||||||
                        || remove_stake_accounts
 | 
					                        || remove_stake_accounts
 | 
				
			||||||
                        || !accounts_to_remove.is_empty()
 | 
					                        || !accounts_to_remove.is_empty()
 | 
				
			||||||
 | 
					                        || !vote_accounts_to_destake.is_empty()
 | 
				
			||||||
                        || faucet_pubkey.is_some()
 | 
					                        || faucet_pubkey.is_some()
 | 
				
			||||||
                        || bootstrap_validator_pubkeys.is_some();
 | 
					                        || bootstrap_validator_pubkeys.is_some();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1977,10 +1994,38 @@ fn main() {
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    for address in accounts_to_remove {
 | 
					                    for address in accounts_to_remove {
 | 
				
			||||||
                        if let Some(mut account) = bank.get_account(&address) {
 | 
					                        let mut account = bank.get_account(&address).unwrap_or_else(|| {
 | 
				
			||||||
 | 
					                            eprintln!(
 | 
				
			||||||
 | 
					                                "Error: Account does not exist, unable to remove it: {}",
 | 
				
			||||||
 | 
					                                address
 | 
				
			||||||
 | 
					                            );
 | 
				
			||||||
 | 
					                            exit(1);
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        account.set_lamports(0);
 | 
					                        account.set_lamports(0);
 | 
				
			||||||
                        bank.store_account(&address, &account);
 | 
					                        bank.store_account(&address, &account);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if !vote_accounts_to_destake.is_empty() {
 | 
				
			||||||
 | 
					                        for (address, mut account) in bank
 | 
				
			||||||
 | 
					                            .get_program_accounts(&stake::program::id())
 | 
				
			||||||
 | 
					                            .unwrap()
 | 
				
			||||||
 | 
					                            .into_iter()
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            if let Ok(StakeState::Stake(meta, stake)) = account.state() {
 | 
				
			||||||
 | 
					                                if vote_accounts_to_destake.contains(&stake.delegation.voter_pubkey)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    if verbose_level > 0 {
 | 
				
			||||||
 | 
					                                        warn!(
 | 
				
			||||||
 | 
					                                            "Undelegating stake account {} from {}",
 | 
				
			||||||
 | 
					                                            address, stake.delegation.voter_pubkey,
 | 
				
			||||||
 | 
					                                        );
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    account.set_state(&StakeState::Initialized(meta)).unwrap();
 | 
				
			||||||
 | 
					                                    bank.store_account(&address, &account);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if let Some(bootstrap_validator_pubkeys) = bootstrap_validator_pubkeys {
 | 
					                    if let Some(bootstrap_validator_pubkeys) = bootstrap_validator_pubkeys {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user