Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion chain/chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,12 @@ impl<'a> ChainUpdate<'a> {
.runtime_adapter
.get_block_proposer(header.epoch_hash, header.height)
.map_err(|e| Error::from(ErrorKind::Other(e.to_string())))?;
if self.runtime_adapter.check_validator_signature(&validator, &header.signature) {
if self.runtime_adapter.check_validator_signature(
&header.epoch_hash,
&validator,
header.hash().as_ref(),
&header.signature,
) {
Ok(())
} else {
Err(ErrorKind::InvalidSignature.into())
Expand Down
10 changes: 8 additions & 2 deletions chain/chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::sync::Arc;

use chrono::Utc;

use near_primitives::crypto::signature::Signature;
use near_primitives::crypto::signer::InMemorySigner;
use near_primitives::hash::CryptoHash;
use near_primitives::rpc::{AccountViewCallResult, QueryResponse};
Expand All @@ -18,6 +17,7 @@ use near_store::{Store, StoreUpdate, Trie, TrieChanges, WrappedTrieChanges};
use crate::error::{Error, ErrorKind};
use crate::types::{BlockHeader, ReceiptResult, RuntimeAdapter, Weight};
use crate::{Chain, ValidTransaction};
use near_primitives::crypto::signature::Signature;

/// Simple key value runtime for tests.
pub struct KeyValueRuntime {
Expand Down Expand Up @@ -95,7 +95,13 @@ impl RuntimeAdapter for KeyValueRuntime {
Ok(self.validators[(height as usize) % self.validators.len()].account_id.clone())
}

fn check_validator_signature(&self, _account_id: &AccountId, _signature: &Signature) -> bool {
fn check_validator_signature(
&self,
_epoch_hash: &CryptoHash,
_account_id: &AccountId,
_data: &[u8],
_signature: &Signature,
) -> bool {
true
}

Expand Down
10 changes: 8 additions & 2 deletions chain/chain/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,14 @@ pub trait RuntimeAdapter: Send + Sync {
height: BlockIndex,
) -> Result<AccountId, Box<dyn std::error::Error>>;

/// Check validator's signature.
fn check_validator_signature(&self, account_id: &AccountId, signature: &Signature) -> bool;
/// Check validator signature for the given epoch
fn check_validator_signature(
&self,
epoch_hash: &CryptoHash,
account_id: &AccountId,
data: &[u8],
signature: &Signature,
) -> bool;

/// Get current number of shards.
fn num_shards(&self) -> ShardId;
Expand Down
7 changes: 6 additions & 1 deletion chain/client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,12 @@ impl ClientActor {
return false;
}
// Check signature is correct for given validator.
if !self.runtime_adapter.check_validator_signature(account_id, signature) {
if !self.runtime_adapter.check_validator_signature(
&header.epoch_hash,
account_id,
hash.as_ref(),
signature,
) {
return false;
}
debug!(target: "client", "Received approval for {} from {}", hash, account_id);
Expand Down
71 changes: 65 additions & 6 deletions near/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use near_chain::{
BlockHeader, Error, ErrorKind, ReceiptResult, RuntimeAdapter, ValidTransaction, Weight,
};
use near_primitives::account::{AccessKey, Account};
use near_primitives::crypto::signature::{PublicKey, Signature};
use near_primitives::crypto::signature::{verify, PublicKey, Signature};
use near_primitives::hash::{hash, CryptoHash};
use near_primitives::rpc::{AccountViewCallResult, QueryResponse, ViewStateResult};
use near_primitives::transaction::{ReceiptTransaction, SignedTransaction, TransactionResult};
Expand Down Expand Up @@ -176,8 +176,21 @@ impl RuntimeAdapter for NightshadeRuntime {
unreachable!()
}

fn check_validator_signature(&self, _account_id: &AccountId, _signature: &Signature) -> bool {
true
fn check_validator_signature(
&self,
epoch_hash: &CryptoHash,
account_id: &AccountId,
data: &[u8],
signature: &Signature,
) -> bool {
let mut vm = self.validator_manager.write().expect(POISONED_LOCK_ERR);
if let Ok(validators) = vm.get_validators(*epoch_hash) {
if let Some(idx) = validators.validator_to_index.get(account_id) {
let staking_key = &validators.validators[*idx].public_key;
return verify(data, signature, staking_key);
}
}
false
}

fn num_shards(&self) -> ShardId {
Expand Down Expand Up @@ -423,7 +436,7 @@ mod test {
use crate::{get_store_path, GenesisConfig, NightshadeRuntime};
use near_chain::RuntimeAdapter;
use near_client::BlockProducer;
use near_primitives::crypto::signer::InMemorySigner;
use near_primitives::crypto::signer::{EDSigner, InMemorySigner};
use near_primitives::hash::{hash, CryptoHash};
use near_primitives::rpc::AccountViewCallResult;
use near_primitives::serialize::BaseEncode;
Expand Down Expand Up @@ -669,7 +682,7 @@ mod test {

#[test]
fn test_validator_stake_change() {
let dir = TempDir::new("validator_rotation").unwrap();
let dir = TempDir::new("validator_stake_change").unwrap();
let store = create_store(&get_store_path(dir.path()));
let num_nodes = 2;
let validators = (0..num_nodes).map(|i| format!("test{}", i + 1)).collect::<Vec<_>>();
Expand Down Expand Up @@ -766,7 +779,7 @@ mod test {

#[test]
fn test_validator_stake_change_multiple_times() {
let dir = TempDir::new("validator_rotation").unwrap();
let dir = TempDir::new("validator_stake_change_multiple_times").unwrap();
let store = create_store(&get_store_path(dir.path()));
let num_nodes = 2;
let validators = (0..num_nodes).map(|i| format!("test{}", i + 1)).collect::<Vec<_>>();
Expand Down Expand Up @@ -892,4 +905,50 @@ mod test {
}
);
}

#[test]
fn test_check_validator_signature() {
let dir = TempDir::new("check_validator_signature").unwrap();
let store = create_store(&get_store_path(dir.path()));
let num_nodes = 2;
let validators = (0..num_nodes).map(|i| format!("test{}", i + 1)).collect::<Vec<_>>();
let mut genesis_config =
GenesisConfig::test(validators.iter().map(|v| v.as_str()).collect());
genesis_config.epoch_length = 2;
let nightshade = NightshadeRuntime::new(dir.path(), store, genesis_config);
let (store_update, _) = nightshade.genesis_state();
store_update.commit().unwrap();
let data = [0; 32];
let signer = InMemorySigner::from_seed(&validators[0], &validators[0]);
let signature = signer.sign(&data);
assert!(nightshade.check_validator_signature(
&CryptoHash::default(),
&validators[0],
&data,
&signature
));
}

#[test]
fn test_check_validator_signature_failure() {
let dir = TempDir::new("check_validator_signature_failure").unwrap();
let store = create_store(&get_store_path(dir.path()));
let num_nodes = 2;
let validators = (0..num_nodes).map(|i| format!("test{}", i + 1)).collect::<Vec<_>>();
let mut genesis_config =
GenesisConfig::test(validators.iter().map(|v| v.as_str()).collect());
genesis_config.epoch_length = 2;
let nightshade = NightshadeRuntime::new(dir.path(), store, genesis_config);
let (store_update, _) = nightshade.genesis_state();
store_update.commit().unwrap();
let data = [0; 32];
let signer = InMemorySigner::from_seed(&validators[0], &validators[0]);
let signature = signer.sign(&data);
assert!(!nightshade.check_validator_signature(
&CryptoHash::default(),
&validators[1],
&data,
&signature
));
}
}