near_primitives/
challenge.rs

1use crate::hash::CryptoHash;
2use crate::merkle::MerklePath;
3use crate::sharding::{EncodedShardChunk, ShardChunk, ShardChunkHeader};
4use crate::state::PartialState;
5use crate::types::AccountId;
6use borsh::{BorshDeserialize, BorshSerialize};
7use near_crypto::Signature;
8use near_primitives_core::types::BlockHeight;
9use near_schema_checker_lib::ProtocolSchema;
10use std::fmt::Debug;
11
12/// Double signed block.
13#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Debug, ProtocolSchema)]
14pub struct BlockDoubleSign {
15    pub left_block_header: Vec<u8>,
16    pub right_block_header: Vec<u8>,
17}
18
19/// Invalid chunk (body of the chunk doesn't match proofs or invalid encoding).
20#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Debug, ProtocolSchema)]
21pub struct ChunkProofs {
22    /// Encoded block header that contains invalid chunk.
23    pub block_header: Vec<u8>,
24    /// Merkle proof of inclusion of this chunk.
25    pub merkle_proof: MerklePath,
26    /// Invalid chunk in an encoded form or in a decoded form.
27    pub chunk: Box<MaybeEncodedShardChunk>,
28}
29
30/// Either `EncodedShardChunk` or `ShardChunk`. Used for `ChunkProofs`.
31/// `Decoded` is used to avoid re-encoding an already decoded chunk to construct a challenge.
32/// `Encoded` is still needed in case a challenge challenges an invalid encoded chunk that can't be
33/// decoded.
34#[allow(clippy::large_enum_variant)] // both variants are large
35#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Debug, ProtocolSchema)]
36pub enum MaybeEncodedShardChunk {
37    Encoded(EncodedShardChunk),
38    Decoded(ShardChunk),
39}
40
41/// Doesn't match post-{state root, outgoing receipts, gas used, etc} results after applying previous chunk.
42#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Debug, ProtocolSchema)]
43pub struct ChunkState {
44    /// Encoded prev block header.
45    pub prev_block_header: Vec<u8>,
46    /// Block height.
47    /// TODO: block header is likely to be needed if we ever want to support
48    /// challenges fully.
49    pub block_height: BlockHeight,
50    /// Merkle proof in inclusion of prev chunk.
51    pub prev_merkle_proof: MerklePath,
52    /// Previous chunk that contains transactions.
53    pub prev_chunk: ShardChunk,
54    /// Merkle proof of inclusion of this chunk.
55    pub merkle_proof: MerklePath,
56    /// Invalid chunk header.
57    pub chunk_header: ShardChunkHeader,
58    /// Partial state that was affected by transactions of given chunk.
59    pub partial_state: PartialState,
60}
61
62#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Debug, ProtocolSchema)]
63// TODO(#1313): Use Box
64#[allow(clippy::large_enum_variant)]
65pub enum ChallengeBody {
66    BlockDoubleSign(BlockDoubleSign),
67    ChunkProofs(ChunkProofs),
68    ChunkState(ChunkState),
69}
70
71#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Debug, ProtocolSchema)]
72#[borsh(init=init)]
73pub struct Challenge {
74    pub body: ChallengeBody,
75    pub account_id: AccountId,
76    pub signature: Signature,
77
78    #[borsh(skip)]
79    pub hash: CryptoHash,
80}
81
82impl Challenge {
83    pub fn init(&mut self) {
84        self.hash = CryptoHash::hash_borsh(&self.body);
85    }
86}
87
88#[derive(
89    BorshSerialize,
90    BorshDeserialize,
91    PartialEq,
92    Eq,
93    Clone,
94    Debug,
95    serde::Serialize,
96    serde::Deserialize,
97    ProtocolSchema,
98)]
99#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
100pub struct SlashedValidator {
101    pub account_id: AccountId,
102    pub is_double_sign: bool,
103}