1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright (c) Zefchain Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! This module manages the state of a Linera chain, including cross-chain communication.

mod chain;
pub mod data_types;
mod inbox;
pub mod manager;
mod outbox;
#[cfg(with_testing)]
pub mod test;

pub use chain::ChainStateView;
use data_types::{Event, Origin};
use linera_base::{
    crypto::CryptoError,
    data_types::{ArithmeticError, BlockHeight, Round, Timestamp},
    identifiers::{ApplicationId, ChainId},
};
use linera_execution::ExecutionError;
use linera_views::views::ViewError;
use rand_distr::WeightedError;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum ChainError {
    #[error("Cryptographic error: {0}")]
    CryptoError(#[from] CryptoError),
    #[error("Arithmetic error: {0}")]
    ArithmeticError(#[from] ArithmeticError),
    #[error("Error in view operation: {0}")]
    ViewError(#[from] ViewError),
    #[error("Execution error: {0} during {1:?}")]
    ExecutionError(ExecutionError, ChainExecutionContext),

    #[error("The chain being queried is not active {0:?}")]
    InactiveChain(ChainId),
    #[error(
        "Cannot vote for block proposal of chain {chain_id:?} because a message \
         from origin {origin:?} at height {height:?} has not been received yet"
    )]
    MissingCrossChainUpdate {
        chain_id: ChainId,
        origin: Box<Origin>,
        height: BlockHeight,
    },
    #[error(
        "Message in block proposed to {chain_id:?} does not match the previously received messages from \
        origin {origin:?}: was {event:?} instead of {previous_event:?}"
    )]
    UnexpectedMessage {
        chain_id: ChainId,
        origin: Box<Origin>,
        event: Event,
        previous_event: Event,
    },
    #[error(
        "Message in block proposed to {chain_id:?} is out of order compared to previous messages \
         from origin {origin:?}: {event:?}. Block and height should be at least: \
         {next_height}, {next_index}"
    )]
    IncorrectMessageOrder {
        chain_id: ChainId,
        origin: Box<Origin>,
        event: Event,
        next_height: BlockHeight,
        next_index: u32,
    },
    #[error("Block proposed to {chain_id:?} is attempting to reject protected message {event:?}")]
    CannotRejectMessage {
        chain_id: ChainId,
        origin: Box<Origin>,
        event: Event,
    },
    #[error(
        "Block proposed to {chain_id:?} is attempting to skip a message \
         that cannot be skipped: {event:?}"
    )]
    CannotSkipMessage {
        chain_id: ChainId,
        origin: Box<Origin>,
        event: Event,
    },
    #[error(
        "Incoming message in block proposed to {chain_id:?} has timestamp {message_timestamp:}, \
         which is later than the block timestamp {block_timestamp:}."
    )]
    IncorrectEventTimestamp {
        chain_id: ChainId,
        message_timestamp: Timestamp,
        block_timestamp: Timestamp,
    },
    #[error("The signature was not created by a valid entity")]
    InvalidSigner,
    #[error(
        "Was expecting block height {expected_block_height} but found {found_block_height} instead"
    )]
    UnexpectedBlockHeight {
        expected_block_height: BlockHeight,
        found_block_height: BlockHeight,
    },
    #[error("The previous block hash of a new block should match the last block of the chain")]
    UnexpectedPreviousBlockHash,
    #[error("Sequence numbers above the maximal value are not usable for blocks")]
    InvalidBlockHeight,
    #[error("Block timestamp must not be earlier than the parent block's.")]
    InvalidBlockTimestamp,
    #[error("Cannot initiate a new block while the previous one is still pending confirmation")]
    PreviousBlockMustBeConfirmedFirst,
    #[error("Invalid block proposal")]
    InvalidBlockProposal,
    #[error("Round number should be at least {0:?}")]
    InsufficientRound(Round),
    #[error("Round number should greater than {0:?}")]
    InsufficientRoundStrict(Round),
    #[error("Round number should be {0:?}")]
    WrongRound(Round),
    #[error("A different block for height {0:?} was already locked at round number {1:?}")]
    HasLockedBlock(BlockHeight, Round),
    #[error("Cannot confirm a block before its predecessors: {current_block_height:?}")]
    MissingEarlierBlocks { current_block_height: BlockHeight },
    #[error("Signatures in a certificate must be from different validators")]
    CertificateValidatorReuse,
    #[error("Signatures in a certificate must form a quorum")]
    CertificateRequiresQuorum,
    #[error("Certificate signature verification failed: {error}")]
    CertificateSignatureVerificationFailed { error: String },
    #[error("Internal error {0}")]
    InternalError(String),
    #[error("Insufficient balance to pay the fees")]
    InsufficientBalance,
    #[error("Invalid owner weights: {0}")]
    OwnerWeightError(#[from] WeightedError),
    #[error("Closed chains cannot have operations, accepted messages or empty blocks")]
    ClosedChain,
    #[error("All operations on this chain must be from one of the following applications: {0:?}")]
    AuthorizedApplications(Vec<ApplicationId>),
    #[error("Can't use grant across different broadcast messages")]
    GrantUseOnBroadcast,
    #[error("ExecutedBlock contains fewer oracle responses than requests")]
    MissingOracleRecord,
}

#[derive(Copy, Clone, Debug)]
pub enum ChainExecutionContext {
    Query,
    DescribeApplication,
    IncomingMessage(u32),
    Operation(u32),
    Block,
}