Skip to content

Commit

Permalink
[stateless_validation] Remove old state witness distribution mechanism (
Browse files Browse the repository at this point in the history
near#11179)

This PR removes a bunch of things that were being used in the old way of
distributing chunk state witness. Changes include
- Rename `ProcessChunkStateWitnessMessage` to `ChunkStateWitnessMessage`
- Remove `verify_chunk_state_witness_signature` in epoch manager
- Remove `process_signed_chunk_state_witness` and
`partially_validate_state_witness` in client
- State witness actions doesn't use old mechanism for sending state
witness
- Remove `ChunkStateWitness` network message
- Remove `SignedEncodedChunkStateWitness`

Note: Do not merge this till all nodes in forknet are deployed with the
partial encoded state witness change
  • Loading branch information
Shreyan Gupta authored May 24, 2024
1 parent 66031e2 commit a8ff1d2
Show file tree
Hide file tree
Showing 22 changed files with 42 additions and 284 deletions.
2 changes: 1 addition & 1 deletion chain/chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4696,7 +4696,7 @@ pub struct BlockCatchUpResponse {

#[derive(actix::Message, Debug, Clone, PartialEq, Eq)]
#[rtype(result = "()")]
pub struct ProcessChunkStateWitnessMessage(pub EncodedChunkStateWitness);
pub struct ChunkStateWitnessMessage(pub EncodedChunkStateWitness);

/// Helper to track blocks catch up
/// Lifetime of a block_hash is as follows:
Expand Down
10 changes: 0 additions & 10 deletions chain/chain/src/test_utils/kv_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ use near_primitives::sharding::{ChunkHash, ShardChunkHeader};
use near_primitives::state_part::PartId;
use near_primitives::stateless_validation::{
ChunkEndorsement, ChunkValidatorAssignments, PartialEncodedStateWitness,
SignedEncodedChunkStateWitness,
};
use near_primitives::transaction::{
Action, ExecutionMetadata, ExecutionOutcome, ExecutionOutcomeWithId, ExecutionStatus,
Expand Down Expand Up @@ -957,15 +956,6 @@ impl EpochManagerAdapter for MockEpochManager {
Ok(true)
}

fn verify_chunk_state_witness_signature(
&self,
_signed_witness: &SignedEncodedChunkStateWitness,
_chunk_producer: &AccountId,
_epoch_id: &EpochId,
) -> Result<bool, Error> {
Ok(true)
}

fn verify_partial_witness_signature(
&self,
_partial_witness: &PartialEncodedStateWitness,
Expand Down
1 change: 0 additions & 1 deletion chain/client/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ pub fn client_sender_for_network(
tx_status_request: view_client_addr.clone().into_sender(),
tx_status_response: view_client_addr.clone().into_sender(),
announce_account: view_client_addr.into_sender(),
chunk_state_witness: client_addr.clone().into_sender(),
chunk_endorsement: client_addr.into_sender(),
}
}
18 changes: 4 additions & 14 deletions chain/client/src/client_actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use near_async::time::{Duration, Instant};
use near_async::{MultiSend, MultiSendMessage, MultiSenderFrom};
use near_chain::chain::{
ApplyChunksDoneMessage, ApplyStatePartsRequest, ApplyStatePartsResponse, BlockCatchUpRequest,
BlockCatchUpResponse, LoadMemtrieRequest, LoadMemtrieResponse, ProcessChunkStateWitnessMessage,
BlockCatchUpResponse, ChunkStateWitnessMessage, LoadMemtrieRequest, LoadMemtrieResponse,
};
use near_chain::rayon_spawner::RayonAsyncComputationSpawner;
use near_chain::resharding::{ReshardingRequest, ReshardingResponse};
Expand All @@ -53,9 +53,8 @@ use near_client_primitives::types::{
use near_epoch_manager::shard_tracker::ShardTracker;
use near_epoch_manager::{EpochManagerAdapter, RngSeed};
use near_network::client::{
BlockApproval, BlockHeadersResponse, BlockResponse, ChunkEndorsementMessage,
ChunkStateWitnessMessage, ProcessTxRequest, ProcessTxResponse, RecvChallenge, SetNetworkInfo,
StateResponse,
BlockApproval, BlockHeadersResponse, BlockResponse, ChunkEndorsementMessage, ProcessTxRequest,
ProcessTxResponse, RecvChallenge, SetNetworkInfo, StateResponse,
};
use near_network::types::ReasonForBan;
use near_network::types::{
Expand Down Expand Up @@ -220,7 +219,7 @@ pub struct SyncJobsSenderForClient {
#[derive(Clone, MultiSend, MultiSenderFrom, MultiSendMessage)]
#[multi_send_message_derive(Debug)]
pub struct ClientSenderForPartialWitness {
pub receive_chunk_state_witness: Sender<ProcessChunkStateWitnessMessage>,
pub chunk_state_witness: Sender<ChunkStateWitnessMessage>,
}

// A small helper macro to unwrap a result of some state sync operation. If the
Expand Down Expand Up @@ -2120,15 +2119,6 @@ impl Handler<SyncMessage> for ClientActorInner {
impl Handler<ChunkStateWitnessMessage> for ClientActorInner {
#[perf]
fn handle(&mut self, msg: ChunkStateWitnessMessage) {
if let Err(err) = self.client.process_signed_chunk_state_witness(msg.0, None) {
tracing::error!(target: "client", ?err, "Error processing signed chunk state witness");
}
}
}

impl Handler<ProcessChunkStateWitnessMessage> for ClientActorInner {
#[perf]
fn handle(&mut self, msg: ProcessChunkStateWitnessMessage) {
if let Err(err) = self.client.process_chunk_state_witness(msg.0, None) {
tracing::error!(target: "client", ?err, "Error processing chunk state witness");
}
Expand Down
71 changes: 4 additions & 67 deletions chain/client/src/stateless_validation/chunk_validator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use near_primitives::receipt::Receipt;
use near_primitives::sharding::{ChunkHash, ReceiptProof, ShardChunkHeader};
use near_primitives::stateless_validation::{
ChunkEndorsement, ChunkStateWitness, ChunkStateWitnessAck, ChunkStateWitnessSize,
EncodedChunkStateWitness, SignedEncodedChunkStateWitness,
EncodedChunkStateWitness,
};
use near_primitives::transaction::SignedTransaction;
use near_primitives::types::chunk_extra::ChunkExtra;
Expand Down Expand Up @@ -716,27 +716,6 @@ pub(crate) fn send_chunk_endorsement_to_block_producers(
}

impl Client {
// TODO(stateless_validation): Remove this function after partial state witness impl
pub fn process_signed_chunk_state_witness(
&mut self,
signed_witness: SignedEncodedChunkStateWitness,
processing_done_tracker: Option<ProcessingDoneTracker>,
) -> Result<(), Error> {
// TODO(stateless_validation): Inefficient, we are decoding the witness twice, but fine for temporary measure
let (witness, _) = signed_witness.witness_bytes.decode()?;
if !self.epoch_manager.verify_chunk_state_witness_signature(
&signed_witness,
&witness.chunk_producer,
&witness.epoch_id,
)? {
return Err(Error::InvalidChunkStateWitness("Invalid signature".to_string()));
}

self.process_chunk_state_witness(signed_witness.witness_bytes, processing_done_tracker)?;

Ok(())
}

/// Responds to a network request to verify a `ChunkStateWitness`, which is
/// sent by chunk producers after they produce a chunk.
/// State witness is processed asynchronously, if you want to wait for the processing to finish
Expand All @@ -746,8 +725,7 @@ impl Client {
encoded_witness: EncodedChunkStateWitness,
processing_done_tracker: Option<ProcessingDoneTracker>,
) -> Result<(), Error> {
let (witness, raw_witness_size) =
self.partially_validate_state_witness(&encoded_witness)?;
let (witness, raw_witness_size) = self.decode_state_witness(&encoded_witness)?;

tracing::debug!(
target: "client",
Expand Down Expand Up @@ -825,55 +803,14 @@ impl Client {
self.chunk_validator.start_validating_chunk(witness, &self.chain, processing_done_tracker)
}

/// Performs state witness decoding and partial validation without requiring the previous block.
/// Here we rely on epoch_id provided as part of the state witness. Later we verify that this
/// epoch_id actually corresponds to the chunk's previous block.
fn partially_validate_state_witness(
fn decode_state_witness(
&self,
encoded_witness: &EncodedChunkStateWitness,
) -> Result<(ChunkStateWitness, ChunkStateWitnessSize), Error> {
let decode_start = std::time::Instant::now();
let (witness, raw_witness_size) = encoded_witness.decode()?;
let decode_elapsed_seconds = decode_start.elapsed().as_secs_f64();
let chunk_header = &witness.chunk_header;
let witness_height = chunk_header.height_created();
let witness_shard = chunk_header.shard_id();

if !self
.epoch_manager
.get_shard_layout(&witness.epoch_id)?
.shard_ids()
.contains(&witness_shard)
{
return Err(Error::InvalidChunkStateWitness(format!(
"Invalid shard_id in ChunkStateWitness: {}",
witness_shard
)));
}

let chunk_producer = self.epoch_manager.get_chunk_producer(
&witness.epoch_id,
witness_height,
witness_shard,
)?;
if witness.chunk_producer != chunk_producer {
return Err(Error::InvalidChunkStateWitness(format!(
"Incorrect chunk producer for epoch {:?} at height {}: expected {}, got {}",
witness.epoch_id, witness_height, chunk_producer, witness.chunk_producer,
)));
}

// Reject witnesses for chunks for which this node isn't a validator.
// It's an error, as chunk producer shouldn't send the witness to a non-validator node.
let my_signer = self.chunk_validator.my_signer.as_ref().ok_or(Error::NotAValidator)?;
let chunk_validator_assignments = self.epoch_manager.get_chunk_validator_assignments(
&witness.epoch_id,
witness_shard,
witness_height,
)?;
if !chunk_validator_assignments.contains(my_signer.validator_id()) {
return Err(Error::NotAChunkValidator);
}
let witness_shard = witness.chunk_header.shard_id();

// Record metrics after validating the witness
metrics::CHUNK_STATE_WITNESS_DECODE_TIME
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@ use near_network::state_witness::{
};
use near_network::types::{NetworkRequests, PeerManagerAdapter, PeerManagerMessageRequest};
use near_performance_metrics_macros::perf;
use near_primitives::checked_feature;
use near_primitives::reed_solomon::reed_solomon_encode;
use near_primitives::sharding::ShardChunkHeader;
use near_primitives::stateless_validation::{
ChunkStateWitness, ChunkStateWitnessAck, EncodedChunkStateWitness, PartialEncodedStateWitness,
SignedEncodedChunkStateWitness,
};
use near_primitives::types::{AccountId, EpochId};
use near_primitives::validator_signer::ValidatorSigner;
Expand Down Expand Up @@ -143,37 +141,11 @@ impl PartialWitnessActor {
chunk_validators.len(),
);

let protocol_version = self.epoch_manager.get_epoch_protocol_version(&epoch_id)?;
if !checked_feature!("stable", PartialEncodedStateWitness, protocol_version) {
self.send_state_witness(witness_bytes, chunk_validators);
} else {
self.send_state_witness_parts(epoch_id, chunk_header, witness_bytes, chunk_validators)?;
}
self.send_state_witness_parts(epoch_id, chunk_header, witness_bytes, chunk_validators)?;

Ok(())
}

// TODO(stateless_validation): Deprecate once we send state witness in parts.
// This is the original way of sending out state witness where the chunk producer sends the whole witness
// to all chunk validators.
fn send_state_witness(
&self,
witness_bytes: EncodedChunkStateWitness,
mut chunk_validators: Vec<AccountId>,
) {
// Remove ourselves from the list of chunk validators. Network can't send messages to ourselves.
chunk_validators.retain(|validator| validator != self.my_signer.validator_id());

let signed_witness = SignedEncodedChunkStateWitness {
signature: self.my_signer.sign_chunk_state_witness(&witness_bytes),
witness_bytes,
};

self.network_adapter.send(PeerManagerMessageRequest::NetworkRequests(
NetworkRequests::ChunkStateWitness(chunk_validators, signed_witness),
));
}

// Function to generate the parts of the state witness and return them as a tuple of chunk_validator and part.
fn generate_state_witness_parts(
&mut self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::sync::Arc;
use lru::LruCache;
use near_async::messaging::CanSend;
use near_async::time::{Duration, Instant};
use near_chain::chain::ProcessChunkStateWitnessMessage;
use near_chain::chain::ChunkStateWitnessMessage;
use near_chain::Error;
use near_epoch_manager::EpochManagerAdapter;
use near_primitives::reed_solomon::reed_solomon_decode;
Expand Down Expand Up @@ -200,7 +200,7 @@ impl PartialEncodedStateWitnessTracker {
.with_label_values(&[entry.shard_id.to_string().as_str()])
.observe(entry.duration_to_last_part.as_seconds_f64());

self.client_sender.send(ProcessChunkStateWitnessMessage(encoded_witness));
self.client_sender.send(ChunkStateWitnessMessage(encoded_witness));
}
self.record_total_parts_cache_size_metric();
Ok(())
Expand Down
1 change: 0 additions & 1 deletion chain/client/src/test_utils/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,6 @@ pub fn setup_mock_all_validators(
| NetworkRequests::TxStatus(_, _, _)
| NetworkRequests::SnapshotHostInfo { .. }
| NetworkRequests::Challenge(_)
| NetworkRequests::ChunkStateWitness(_, _)
| NetworkRequests::ChunkStateWitnessAck(_, _)
| NetworkRequests::ChunkEndorsement(_, _)
| NetworkRequests::PartialEncodedStateWitness(_)
Expand Down
2 changes: 1 addition & 1 deletion chain/client/src/test_utils/test_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ impl TestEnv {
// clients. Ideally the route should have been the following:
// [client] ----(DistributeStateWitnessRequest)----> [partial_witness_actor]
// [partial_witness_actor] ----(PartialEncodedStateWitness + Forward)----> [partial_witness_actor]
// [partial_witness_actor] ----(ProcessChunkStateWitnessMessage)----> [client]
// [partial_witness_actor] ----(ChunkStateWitnessMessage)----> [client]
// But we go directly from processing DistributeStateWitnessRequest to sending it to all the chunk validators.
// Validation of state witness is done in the partial_witness_actor which should be tested by test_loop.
let partial_witness_adapters = self.partial_witness_adapters.clone();
Expand Down
26 changes: 3 additions & 23 deletions chain/client/src/test_utils/test_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use near_async::time::Duration;

use crate::Client;
use near_network::client::{
BlockApproval, BlockResponse, ChunkEndorsementMessage, ChunkStateWitnessMessage,
ClientSenderForNetwork, ClientSenderForNetworkMessage, ProcessTxRequest,
BlockApproval, BlockResponse, ChunkEndorsementMessage, ClientSenderForNetwork,
ClientSenderForNetworkMessage, ProcessTxRequest,
};
use near_network::state_witness::{
ChunkStateWitnessAckMessage, PartialEncodedStateWitnessForwardMessage,
Expand Down Expand Up @@ -165,24 +165,6 @@ pub fn route_network_messages_to_client<
tracing::warn!("Dropping message to self");
}
}
NetworkRequests::ChunkStateWitness(targets, witness) => {
let other_idxes = targets
.iter()
.map(|account| data.index_for_account(account))
.collect::<Vec<_>>();
for other_idx in &other_idxes {
if *other_idx != idx {
drop(
client_senders[*other_idx]
.send_async(ChunkStateWitnessMessage(witness.clone())),
);
} else {
tracing::warn!(
"ChunkStateWitness asked to send to nodes {:?}, but {} is ourselves, so skipping that",
other_idxes, idx);
}
}
}
NetworkRequests::ChunkStateWitnessAck(target, witness_ack) => {
let other_idx = data.index_for_account(&target);
if other_idx != idx {
Expand Down Expand Up @@ -352,8 +334,6 @@ impl<Data: AsRef<Client> + AsRef<AccountId>> ClientQueries for Vec<Data> {
pub fn forward_messages_from_partial_witness_actor_to_client(
) -> LoopEventHandler<ClientActorInner, ClientSenderForPartialWitnessMessage> {
LoopEventHandler::new_simple(|msg, client_actor: &mut ClientActorInner| match msg {
ClientSenderForPartialWitnessMessage::_receive_chunk_state_witness(msg) => {
client_actor.handle(msg)
}
ClientSenderForPartialWitnessMessage::_chunk_state_witness(msg) => client_actor.handle(msg),
})
}
3 changes: 0 additions & 3 deletions chain/client/src/test_utils/test_loop/client_actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ pub fn forward_client_messages_from_network_to_client_actor(
ClientSenderForNetworkMessage::_network_info(msg) => {
(msg.callback)(Ok(client_actor.handle(msg.message)));
}
ClientSenderForNetworkMessage::_chunk_state_witness(msg) => {
(msg.callback)(Ok(client_actor.handle(msg.message)));
}
ClientSenderForNetworkMessage::_chunk_endorsement(msg) => {
(msg.callback)(Ok(client_actor.handle(msg.message)));
}
Expand Down
23 changes: 0 additions & 23 deletions chain/epoch-manager/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use near_primitives::shard_layout::{account_id_to_shard_id, ShardLayout, ShardLa
use near_primitives::sharding::{ChunkHash, ShardChunkHeader};
use near_primitives::stateless_validation::{
ChunkEndorsement, ChunkValidatorAssignments, PartialEncodedStateWitness,
SignedEncodedChunkStateWitness,
};
use near_primitives::types::validator_stake::ValidatorStake;
use near_primitives::types::{
Expand Down Expand Up @@ -412,14 +411,6 @@ pub trait EpochManagerAdapter: Send + Sync {
endorsement: &ChunkEndorsement,
) -> Result<bool, Error>;

// TODO(stateless_validation): Deprecate this function after partial witness
fn verify_chunk_state_witness_signature(
&self,
signed_witness: &SignedEncodedChunkStateWitness,
chunk_producer: &AccountId,
epoch_id: &EpochId,
) -> Result<bool, Error>;

fn verify_partial_witness_signature(
&self,
partial_witness: &PartialEncodedStateWitness,
Expand Down Expand Up @@ -1064,20 +1055,6 @@ impl EpochManagerAdapter for EpochManagerHandle {
Ok(endorsement.verify(validator.public_key()))
}

// TODO(stateless_validation): Deprecate this function after partial witness
fn verify_chunk_state_witness_signature(
&self,
signed_witness: &SignedEncodedChunkStateWitness,
chunk_producer: &AccountId,
epoch_id: &EpochId,
) -> Result<bool, Error> {
let epoch_manager = self.read();
let validator = epoch_manager.get_validator_by_account_id(epoch_id, chunk_producer)?;
Ok(signed_witness
.signature
.verify(signed_witness.witness_bytes.as_slice(), validator.public_key()))
}

fn verify_partial_witness_signature(
&self,
partial_witness: &PartialEncodedStateWitness,
Expand Down
Loading

0 comments on commit a8ff1d2

Please sign in to comment.