Skip to content

Commit

Permalink
fix: validator with wrong key should not be able to produce blocks (#…
Browse files Browse the repository at this point in the history
…2683)

See #2682 for the issue description. Now if a validator with incorrect key tries to produce a block they will fail with an error printed in the log indicating that they have the wrong validator key.

Test plan
---------
`test_incorrect_validator_key_produce_block` passes.
  • Loading branch information
bowenwang1996 authored May 20, 2020
1 parent cbfbf19 commit 649d1b2
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 9 deletions.
10 changes: 8 additions & 2 deletions chain/chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -938,10 +938,16 @@ impl RuntimeAdapter for KeyValueRuntime {

fn get_validator_by_account_id(
&self,
_epoch_id: &EpochId,
epoch_id: &EpochId,
_last_known_block_hash: &CryptoHash,
_account_id: &String,
account_id: &String,
) -> Result<(ValidatorStake, bool), Error> {
let validators = &self.validators[self.get_valset_for_epoch(epoch_id)?];
for validator_stake in validators.iter() {
if &validator_stake.account_id == account_id {
return Ok((validator_stake.clone(), false));
}
}
Err(ErrorKind::NotAValidator.into())
}

Expand Down
20 changes: 16 additions & 4 deletions chain/client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,10 +282,10 @@ impl Client {
);

// Check that we are were called at the block that we are producer for.
let next_block_proposer = self.runtime_adapter.get_block_producer(
&self.runtime_adapter.get_epoch_id_from_prev_block(&head.last_block_hash).unwrap(),
next_height,
)?;
let epoch_id =
self.runtime_adapter.get_epoch_id_from_prev_block(&head.last_block_hash).unwrap();
let next_block_proposer =
self.runtime_adapter.get_block_producer(&epoch_id, next_height)?;

let prev = self.chain.get_block_header(&head.last_block_hash)?.clone();
let prev_hash = head.last_block_hash;
Expand All @@ -309,6 +309,18 @@ impl Client {
)? {
return Ok(None);
}
let (validator_stake, _) = self.runtime_adapter.get_validator_by_account_id(
&epoch_id,
&head.last_block_hash,
&next_block_proposer,
)?;
if validator_stake.public_key != validator_signer.public_key() {
return Err(Error::BlockProducer(format!(
"Validator key doesn't match. Expected {} Actual {}",
validator_stake.public_key,
validator_signer.public_key()
)));
}

debug!(target: "client", "{:?} Producing block at height {}, parent {} @ {}", validator_signer.validator_id(), next_height, prev.inner_lite.height, format_hash(head.last_block_hash));

Expand Down
2 changes: 1 addition & 1 deletion chain/client/src/client_actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ impl ClientActor {
) {
if let Err(err) = self.produce_block(height) {
// If there is an error, report it and let it retry on the next loop step.
error!(target: "client", "Block production failed: {:?}", err);
error!(target: "client", "Block production failed: {}", err);
}
}
}
Expand Down
34 changes: 32 additions & 2 deletions chain/client/tests/process_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use num_rational::Rational;

use near_chain::chain::{check_refcount_map, NUM_EPOCHS_TO_KEEP_STORE_DATA};
use near_chain::{Block, ChainGenesis, ChainStoreAccess, ErrorKind, Provenance, RuntimeAdapter};
use near_chain_configs::Genesis;
use near_chain_configs::{ClientConfig, Genesis};
use near_chunks::{ChunkStatus, ShardsManager};
use near_client::test_utils::setup_mock_all_validators;
use near_client::test_utils::{setup_client, setup_mock, TestEnv};
Expand Down Expand Up @@ -1061,7 +1061,6 @@ fn test_gc_tail_update() {
fn test_gas_price_change() {
init_test_logger();
let mut genesis = Genesis::test(vec!["test0", "test1"], 1);
println!("total supply = {}", genesis.config.total_supply);
let target_num_tokens_left = NEAR_BASE / 10 + 1;
let send_money_total_gas = genesis
.config
Expand Down Expand Up @@ -1153,3 +1152,34 @@ fn test_invalid_block_root() {
_ => assert!(false, "succeeded, tip: {:?}", tip),
}
}

#[test]
fn test_incorrect_validator_key_produce_block() {
let genesis = Genesis::test(vec!["test0", "test1"], 2);
let genesis = Arc::new(genesis);
let chain_genesis = ChainGenesis::from(&genesis);
let runtime_adapter: Arc<dyn RuntimeAdapter> = Arc::new(neard::NightshadeRuntime::new(
Path::new("."),
create_test_store(),
genesis,
vec![],
vec![],
));
let signer = Arc::new(InMemoryValidatorSigner::from_seed("test0", KeyType::ED25519, "seed"));
let mut config = ClientConfig::test(true, 10, 20, 2, false);
config.epoch_length = chain_genesis.epoch_length;
let mut client = Client::new(
config,
chain_genesis,
runtime_adapter,
Arc::new(MockNetworkAdapter::default()),
Some(signer),
false,
)
.unwrap();
let res = client.produce_block(1);
match res {
Err(near_client::Error::BlockProducer(_)) => {}
_ => panic!("unexpected result: {:?}", res),
}
}

0 comments on commit 649d1b2

Please sign in to comment.