1pub mod block;
7mod certificate;
8
9pub mod types {
10 pub use super::{block::*, certificate::*};
11}
12
13mod block_tracker;
14mod chain;
15pub mod data_types;
16mod inbox;
17pub mod manager;
18mod outbox;
19mod pending_blobs;
20#[cfg(with_testing)]
21pub mod test;
22
23pub use chain::ChainStateView;
24use data_types::{MessageBundle, PostedMessage};
25use linera_base::{
26 bcs,
27 crypto::CryptoError,
28 data_types::{ArithmeticError, BlockHeight, Round, Timestamp},
29 identifiers::{ApplicationId, ChainId},
30};
31use linera_execution::ExecutionError;
32use linera_views::ViewError;
33use rand_distr::WeightedError;
34use thiserror::Error;
35
36#[derive(Error, Debug)]
37pub enum ChainError {
38 #[error("Cryptographic error: {0}")]
39 CryptoError(#[from] CryptoError),
40 #[error(transparent)]
41 ArithmeticError(#[from] ArithmeticError),
42 #[error(transparent)]
43 ViewError(#[from] ViewError),
44 #[error("Execution error: {0} during {1:?}")]
45 ExecutionError(Box<ExecutionError>, ChainExecutionContext),
46
47 #[error("The chain being queried is not active {0}")]
48 InactiveChain(ChainId),
49 #[error(
50 "Cannot vote for block proposal of chain {chain_id} because a message \
51 from chain {origin} at height {height} has not been received yet"
52 )]
53 MissingCrossChainUpdate {
54 chain_id: ChainId,
55 origin: ChainId,
56 height: BlockHeight,
57 },
58 #[error(
59 "Message in block proposed to {chain_id:?} does not match the previously received messages from \
60 origin {origin:?}: was {bundle:?} instead of {previous_bundle:?}"
61 )]
62 UnexpectedMessage {
63 chain_id: ChainId,
64 origin: ChainId,
65 bundle: Box<MessageBundle>,
66 previous_bundle: Box<MessageBundle>,
67 },
68 #[error(
69 "Message in block proposed to {chain_id:?} is out of order compared to previous messages \
70 from origin {origin:?}: {bundle:?}. Block and height should be at least: \
71 {next_height}, {next_index}"
72 )]
73 IncorrectMessageOrder {
74 chain_id: ChainId,
75 origin: ChainId,
76 bundle: Box<MessageBundle>,
77 next_height: BlockHeight,
78 next_index: u32,
79 },
80 #[error(
81 "Block proposed to {chain_id:?} is attempting to reject protected message \
82 {posted_message:?}"
83 )]
84 CannotRejectMessage {
85 chain_id: ChainId,
86 origin: ChainId,
87 posted_message: Box<PostedMessage>,
88 },
89 #[error(
90 "Block proposed to {chain_id:?} is attempting to skip a message bundle \
91 that cannot be skipped: {bundle:?}"
92 )]
93 CannotSkipMessage {
94 chain_id: ChainId,
95 origin: ChainId,
96 bundle: Box<MessageBundle>,
97 },
98 #[error(
99 "Incoming message bundle in block proposed to {chain_id:?} has timestamp \
100 {bundle_timestamp:}, which is later than the block timestamp {block_timestamp:}."
101 )]
102 IncorrectBundleTimestamp {
103 chain_id: ChainId,
104 bundle_timestamp: Timestamp,
105 block_timestamp: Timestamp,
106 },
107 #[error("The signature was not created by a valid entity")]
108 InvalidSigner,
109 #[error(
110 "Was expecting block height {expected_block_height} but found {found_block_height} instead"
111 )]
112 UnexpectedBlockHeight {
113 expected_block_height: BlockHeight,
114 found_block_height: BlockHeight,
115 },
116 #[error("The previous block hash of a new block should match the last block of the chain")]
117 UnexpectedPreviousBlockHash,
118 #[error("Sequence numbers above the maximal value are not usable for blocks")]
119 BlockHeightOverflow,
120 #[error(
121 "Block timestamp {new} must not be earlier than the parent block's timestamp {parent}"
122 )]
123 InvalidBlockTimestamp { parent: Timestamp, new: Timestamp },
124 #[error("Round number should be at least {0:?}")]
125 InsufficientRound(Round),
126 #[error("Round number should be greater than {0:?}")]
127 InsufficientRoundStrict(Round),
128 #[error("Round number should be {0:?}")]
129 WrongRound(Round),
130 #[error("Already voted to confirm a different block for height {0:?} at round number {1:?}")]
131 HasIncompatibleConfirmedVote(BlockHeight, Round),
132 #[error("Proposal for height {0:?} is not newer than locking block in round {1:?}")]
133 MustBeNewerThanLockingBlock(BlockHeight, Round),
134 #[error("Cannot confirm a block before its predecessors: {current_block_height:?}")]
135 MissingEarlierBlocks { current_block_height: BlockHeight },
136 #[error("Signatures in a certificate must be from different validators")]
137 CertificateValidatorReuse,
138 #[error("Signatures in a certificate must form a quorum")]
139 CertificateRequiresQuorum,
140 #[error("Internal error {0}")]
141 InternalError(String),
142 #[error("Block proposal has size {0} which is too large")]
143 BlockProposalTooLarge(usize),
144 #[error(transparent)]
145 BcsError(#[from] bcs::Error),
146 #[error("Invalid owner weights: {0}")]
147 OwnerWeightError(#[from] WeightedError),
148 #[error("Closed chains cannot have operations, accepted messages or empty blocks")]
149 ClosedChain,
150 #[error("Empty blocks are not allowed")]
151 EmptyBlock,
152 #[error("All operations on this chain must be from one of the following applications: {0:?}")]
153 AuthorizedApplications(Vec<ApplicationId>),
154 #[error("Missing operations or messages from mandatory applications: {0:?}")]
155 MissingMandatoryApplications(Vec<ApplicationId>),
156 #[error("Executed block contains fewer oracle responses than requests")]
157 MissingOracleResponseList,
158 #[error("Not signing timeout certificate; current round does not time out")]
159 RoundDoesNotTimeOut,
160 #[error("Not signing timeout certificate; current round times out at time {0}")]
161 NotTimedOutYet(Timestamp),
162}
163
164#[derive(Copy, Clone, Debug)]
165#[cfg_attr(with_testing, derive(Eq, PartialEq))]
166pub enum ChainExecutionContext {
167 Query,
168 DescribeApplication,
169 IncomingBundle(u32),
170 Operation(u32),
171 Block,
172}
173
174pub trait ExecutionResultExt<T> {
175 fn with_execution_context(self, context: ChainExecutionContext) -> Result<T, ChainError>;
176}
177
178impl<T, E> ExecutionResultExt<T> for Result<T, E>
179where
180 E: Into<ExecutionError>,
181{
182 fn with_execution_context(self, context: ChainExecutionContext) -> Result<T, ChainError> {
183 self.map_err(|error| ChainError::ExecutionError(Box::new(error.into()), context))
184 }
185}