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)]
36#[borsh(use_discriminant = true)]
37#[repr(u8)]
38pub enum MaybeEncodedShardChunk {
39    Encoded(EncodedShardChunk) = 0,
40    Decoded(ShardChunk) = 1,
41}
42
43/// Doesn't match post-{state root, outgoing receipts, gas used, etc} results after applying previous chunk.
44#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Debug, ProtocolSchema)]
45pub struct ChunkState {
46    /// Encoded prev block header.
47    pub prev_block_header: Vec<u8>,
48    /// Block height.
49    /// TODO: block header is likely to be needed if we ever want to support
50    /// challenges fully.
51    pub block_height: BlockHeight,
52    /// Merkle proof in inclusion of prev chunk.
53    pub prev_merkle_proof: MerklePath,
54    /// Previous chunk that contains transactions.
55    pub prev_chunk: ShardChunk,
56    /// Merkle proof of inclusion of this chunk.
57    pub merkle_proof: MerklePath,
58    /// Invalid chunk header.
59    pub chunk_header: ShardChunkHeader,
60    /// Partial state that was affected by transactions of given chunk.
61    pub partial_state: PartialState,
62}
63
64#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Debug, ProtocolSchema)]
65// TODO(#1313): Use Box
66#[allow(clippy::large_enum_variant)]
67#[borsh(use_discriminant = true)]
68#[repr(u8)]
69pub enum ChallengeBody {
70    BlockDoubleSign(BlockDoubleSign) = 0,
71    ChunkProofs(ChunkProofs) = 1,
72    ChunkState(ChunkState) = 2,
73}
74
75#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Debug, ProtocolSchema)]
76#[borsh(init=init)]
77pub struct Challenge {
78    pub body: ChallengeBody,
79    pub account_id: AccountId,
80    pub signature: Signature,
81
82    #[borsh(skip)]
83    pub hash: CryptoHash,
84}
85
86impl Challenge {
87    pub fn init(&mut self) {
88        self.hash = CryptoHash::hash_borsh(&self.body);
89    }
90}
91
92#[derive(
93    BorshSerialize,
94    BorshDeserialize,
95    PartialEq,
96    Eq,
97    Clone,
98    Debug,
99    serde::Serialize,
100    serde::Deserialize,
101    ProtocolSchema,
102)]
103#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
104pub struct SlashedValidator {
105    pub account_id: AccountId,
106    pub is_double_sign: bool,
107}