Skip to content

Commit

Permalink
refactor: move verify_approvals_and_threshold_orphan to EMA (#7657)
Browse files Browse the repository at this point in the history
Part of #6910, depends on #7656

This is slighly less trivial than pure move -- the API is adjusted to
remove direct dependency on doomslug which lives in a different crate
  • Loading branch information
matklad authored and nikurt committed Nov 9, 2022
1 parent 85805dc commit c13999b
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 94 deletions.
8 changes: 7 additions & 1 deletion chain/chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4880,7 +4880,13 @@ impl<'a> ChainUpdate<'a> {
let approvals = header.approvals();
self.runtime_adapter.verify_approvals_and_threshold_orphan(
epoch_id,
self.doomslug_threshold_mode,
&|approvals, stakes| {
Doomslug::can_approved_block_be_produced(
self.doomslug_threshold_mode,
approvals,
stakes,
)
},
prev_hash,
prev_height,
height,
Expand Down
73 changes: 38 additions & 35 deletions chain/chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ use crate::types::{
AcceptedBlock, ApplySplitStateResult, ApplyTransactionResult, BlockHeaderInfo, ChainGenesis,
};
use crate::{BlockHeader, DoomslugThresholdMode, RuntimeAdapter};
use crate::{BlockProcessingArtifact, Doomslug, Provenance};
use crate::{BlockProcessingArtifact, Provenance};
use near_primitives::epoch_manager::ShardConfig;
use near_primitives::time::Clock;
use near_primitives::utils::MaybeValidated;
Expand Down Expand Up @@ -561,6 +561,43 @@ impl EpochManagerAdapter for KeyValueRuntime {
) -> Result<bool, Error> {
Ok(true)
}

fn verify_approvals_and_threshold_orphan(
&self,
epoch_id: &EpochId,
can_approved_block_be_produced: &dyn Fn(
&[Option<Signature>],
&[(Balance, Balance, bool)],
) -> bool,
prev_block_hash: &CryptoHash,
prev_block_height: BlockHeight,
block_height: BlockHeight,
approvals: &[Option<Signature>],
) -> Result<(), Error> {
let validators = self.get_block_producers(self.get_valset_for_epoch(epoch_id)?);
let message_to_sign = Approval::get_data_for_sig(
&if prev_block_height + 1 == block_height {
ApprovalInner::Endorsement(*prev_block_hash)
} else {
ApprovalInner::Skip(prev_block_height)
},
block_height,
);

for (validator, may_be_signature) in validators.iter().zip(approvals.iter()) {
if let Some(signature) = may_be_signature {
if !signature.verify(message_to_sign.as_ref(), validator.public_key()) {
return Err(Error::InvalidApprovals);
}
}
}
let stakes = validators.iter().map(|stake| (stake.stake(), 0, false)).collect::<Vec<_>>();
if !can_approved_block_be_produced(approvals, &stakes) {
Err(Error::NotEnoughApprovals)
} else {
Ok(())
}
}
}

impl RuntimeAdapter for KeyValueRuntime {
Expand Down Expand Up @@ -609,40 +646,6 @@ impl RuntimeAdapter for KeyValueRuntime {
) {
}

fn verify_approvals_and_threshold_orphan(
&self,
epoch_id: &EpochId,
doomslug_threshold_mode: DoomslugThresholdMode,
prev_block_hash: &CryptoHash,
prev_block_height: BlockHeight,
block_height: BlockHeight,
approvals: &[Option<Signature>],
) -> Result<(), Error> {
let validators = self.get_block_producers(self.get_valset_for_epoch(epoch_id)?);
let message_to_sign = Approval::get_data_for_sig(
&if prev_block_height + 1 == block_height {
ApprovalInner::Endorsement(*prev_block_hash)
} else {
ApprovalInner::Skip(prev_block_height)
},
block_height,
);

for (validator, may_be_signature) in validators.iter().zip(approvals.iter()) {
if let Some(signature) = may_be_signature {
if !signature.verify(message_to_sign.as_ref(), validator.public_key()) {
return Err(Error::InvalidApprovals);
}
}
}
let stakes = validators.iter().map(|stake| (stake.stake(), 0, false)).collect::<Vec<_>>();
if !Doomslug::can_approved_block_be_produced(doomslug_threshold_mode, approvals, &stakes) {
Err(Error::NotEnoughApprovals)
} else {
Ok(())
}
}

fn num_shards(&self, _epoch_id: &EpochId) -> Result<ShardId, Error> {
Ok(self.num_shards)
}
Expand Down
14 changes: 1 addition & 13 deletions chain/chain/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ use near_primitives::sandbox::state_patch::SandboxStatePatch;
use near_primitives::time::Utc;
use num_rational::Rational32;

use crate::{metrics, DoomslugThresholdMode};
use crate::metrics;
use near_chain_configs::{Genesis, ProtocolConfig};
use near_chain_primitives::Error;
use near_client_primitives::types::StateSplitApplyingStatus;
use near_crypto::Signature;
use near_pool::types::PoolIterator;
use near_primitives::challenge::{ChallengesResult, SlashedValidator};
use near_primitives::checked_feature;
Expand Down Expand Up @@ -332,17 +331,6 @@ pub trait RuntimeAdapter: EpochManagerAdapter + Send + Sync {
current_protocol_version: ProtocolVersion,
) -> Result<Vec<SignedTransaction>, Error>;

/// Verify approvals and check threshold, but ignore next epoch approvals and slashing
fn verify_approvals_and_threshold_orphan(
&self,
epoch_id: &EpochId,
doomslug_threshold_mode: DoomslugThresholdMode,
prev_block_hash: &CryptoHash,
prev_block_height: BlockHeight,
block_height: BlockHeight,
approvals: &[Option<Signature>],
) -> Result<(), Error>;

/// Get current number of shards.
fn num_shards(&self, epoch_id: &EpochId) -> Result<ShardId, Error>;

Expand Down
62 changes: 61 additions & 1 deletion chain/epoch-manager/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use near_primitives::{
hash::CryptoHash,
sharding::{ChunkHash, ShardChunkHeader},
types::{
validator_stake::ValidatorStake, AccountId, ApprovalStake, BlockHeight, EpochId, ShardId,
validator_stake::ValidatorStake, AccountId, ApprovalStake, Balance, BlockHeight, EpochId,
ShardId,
},
};

Expand Down Expand Up @@ -143,6 +144,21 @@ pub trait EpochManagerAdapter: Send + Sync {
block_height: BlockHeight,
approvals: &[Option<Signature>],
) -> Result<bool, Error>;

/// Verify approvals and check threshold, but ignore next epoch approvals and slashing
fn verify_approvals_and_threshold_orphan(
&self,
epoch_id: &EpochId,
can_approved_block_be_produced: &dyn Fn(
&[Option<Signature>],
// (stake this in epoch, stake in next epoch, is_slashed)
&[(Balance, Balance, bool)],
) -> bool,
prev_block_hash: &CryptoHash,
prev_block_height: BlockHeight,
block_height: BlockHeight,
approvals: &[Option<Signature>],
) -> Result<(), Error>;
}

/// A technical plumbing trait to conveniently implement [`EpochManagerAdapter`]
Expand Down Expand Up @@ -367,4 +383,48 @@ impl<T: HasEpochMangerHandle + Send + Sync> EpochManagerAdapter for T {
}
Ok(true)
}

fn verify_approvals_and_threshold_orphan(
&self,
epoch_id: &EpochId,
can_approved_block_be_produced: &dyn Fn(
&[Option<Signature>],
&[(Balance, Balance, bool)],
) -> bool,
prev_block_hash: &CryptoHash,
prev_block_height: BlockHeight,
block_height: BlockHeight,
approvals: &[Option<Signature>],
) -> Result<(), Error> {
let info = {
let epoch_manager = self.read();
epoch_manager.get_heuristic_block_approvers_ordered(epoch_id).map_err(Error::from)?
};

let message_to_sign = Approval::get_data_for_sig(
&if prev_block_height + 1 == block_height {
ApprovalInner::Endorsement(*prev_block_hash)
} else {
ApprovalInner::Skip(prev_block_height)
},
block_height,
);

for (validator, may_be_signature) in info.iter().zip(approvals.iter()) {
if let Some(signature) = may_be_signature {
if !signature.verify(message_to_sign.as_ref(), &validator.public_key) {
return Err(Error::InvalidApprovals);
}
}
}
let stakes = info
.iter()
.map(|stake| (stake.stake_this_epoch, stake.stake_next_epoch, false))
.collect::<Vec<_>>();
if !can_approved_block_be_produced(approvals, &stakes) {
Err(Error::NotEnoughApprovals)
} else {
Ok(())
}
}
}
46 changes: 2 additions & 44 deletions nearcore/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@ use borsh::ser::BorshSerialize;
use borsh::BorshDeserialize;
use errors::FromStateViewerErrors;
use near_chain::types::{ApplySplitStateResult, ApplyTransactionResult, BlockHeaderInfo};
use near_chain::{Doomslug, DoomslugThresholdMode, Error, RuntimeAdapter};
use near_chain::{Error, RuntimeAdapter};
use near_chain_configs::{
Genesis, GenesisConfig, ProtocolConfig, DEFAULT_GC_NUM_EPOCHS_TO_KEEP,
MIN_GC_NUM_EPOCHS_TO_KEEP,
};
use near_client_primitives::types::StateSplitApplyingStatus;
use near_crypto::{PublicKey, Signature};
use near_crypto::PublicKey;
use near_epoch_manager::{EpochManager, EpochManagerHandle};
use near_o11y::log_assert;
use near_pool::types::PoolIterator;
use near_primitives::account::{AccessKey, Account};
use near_primitives::block::{Approval, ApprovalInner};
use near_primitives::challenge::ChallengesResult;
use near_primitives::contract::ContractCode;
use near_primitives::epoch_manager::block_info::BlockInfo;
Expand Down Expand Up @@ -843,47 +842,6 @@ impl RuntimeAdapter for NightshadeRuntime {
Ok(transactions)
}

fn verify_approvals_and_threshold_orphan(
&self,
epoch_id: &EpochId,
doomslug_threshold_mode: DoomslugThresholdMode,
prev_block_hash: &CryptoHash,
prev_block_height: BlockHeight,
block_height: BlockHeight,
approvals: &[Option<Signature>],
) -> Result<(), Error> {
let info = {
let epoch_manager = self.epoch_manager.read();
epoch_manager.get_heuristic_block_approvers_ordered(epoch_id).map_err(Error::from)?
};

let message_to_sign = Approval::get_data_for_sig(
&if prev_block_height + 1 == block_height {
ApprovalInner::Endorsement(*prev_block_hash)
} else {
ApprovalInner::Skip(prev_block_height)
},
block_height,
);

for (validator, may_be_signature) in info.iter().zip(approvals.iter()) {
if let Some(signature) = may_be_signature {
if !signature.verify(message_to_sign.as_ref(), &validator.public_key) {
return Err(Error::InvalidApprovals);
}
}
}
let stakes = info
.iter()
.map(|stake| (stake.stake_this_epoch, stake.stake_next_epoch, false))
.collect::<Vec<_>>();
if !Doomslug::can_approved_block_be_produced(doomslug_threshold_mode, approvals, &stakes) {
Err(Error::NotEnoughApprovals)
} else {
Ok(())
}
}

fn num_shards(&self, epoch_id: &EpochId) -> Result<NumShards, Error> {
let epoch_manager = self.epoch_manager.read();
Ok(epoch_manager.get_shard_layout(epoch_id).map_err(Error::from)?.num_shards())
Expand Down

0 comments on commit c13999b

Please sign in to comment.