Skip to content

Commit

Permalink
Add an oracle for the validation round.
Browse files Browse the repository at this point in the history
  • Loading branch information
afck committed Jan 23, 2025
1 parent ec7bb41 commit b2ad189
Show file tree
Hide file tree
Showing 31 changed files with 280 additions and 67 deletions.
18 changes: 17 additions & 1 deletion linera-base/src/data_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,20 @@ pub struct BlockHeight(pub u64);

/// An identifier for successive attempts to decide a value in a consensus protocol.
#[derive(
Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Default, Debug, Serialize, Deserialize,
Eq,
PartialEq,
Ord,
PartialOrd,
Copy,
Clone,
Hash,
Default,
Debug,
Serialize,
Deserialize,
WitType,
WitLoad,
WitStore,
)]
pub enum Round {
/// The initial fast round.
Expand Down Expand Up @@ -763,6 +776,8 @@ pub enum OracleResponse {
Blob(BlobId),
/// An assertion oracle that passed.
Assert,
/// The block's validation round.
Round(Round),
}

impl Display for OracleResponse {
Expand All @@ -774,6 +789,7 @@ impl Display for OracleResponse {
OracleResponse::Post(bytes) => write!(f, "Post:{}", STANDARD_NO_PAD.encode(bytes))?,
OracleResponse::Blob(blob_id) => write!(f, "Blob:{}", blob_id)?,
OracleResponse::Assert => write!(f, "Assert")?,
OracleResponse::Round(round) => write!(f, "Round:{round}")?,
};

Ok(())
Expand Down
7 changes: 6 additions & 1 deletion linera-chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use futures::stream::{self, StreamExt, TryStreamExt};
use linera_base::{
crypto::CryptoHash,
data_types::{
Amount, ArithmeticError, Blob, BlockHeight, OracleResponse, Timestamp,
Amount, ArithmeticError, Blob, BlockHeight, OracleResponse, Round, Timestamp,
UserApplicationDescription,
},
ensure,
Expand Down Expand Up @@ -666,6 +666,7 @@ where
&mut self,
block: &ProposedBlock,
local_time: Timestamp,
round: Option<Round>,
replaying_oracle_responses: Option<Vec<Vec<OracleResponse>>>,
) -> Result<BlockExecutionOutcome, ChainError> {
#[cfg(with_metrics)]
Expand Down Expand Up @@ -785,6 +786,7 @@ where
posted_message,
incoming_bundle,
block,
round,
txn_index,
local_time,
&mut txn_tracker,
Expand All @@ -803,6 +805,7 @@ where
chain_id,
height: block.height,
index: Some(txn_index),
round,
authenticated_signer: block.authenticated_signer,
authenticated_caller_id: None,
};
Expand Down Expand Up @@ -935,6 +938,7 @@ where
posted_message: &PostedMessage,
incoming_bundle: &IncomingBundle,
block: &ProposedBlock,
round: Option<Round>,
txn_index: u32,
local_time: Timestamp,
txn_tracker: &mut TransactionTracker,
Expand All @@ -946,6 +950,7 @@ where
chain_id: block.chain_id,
is_bouncing: posted_message.is_bouncing(),
height: block.height,
round,
certificate_hash: incoming_bundle.bundle.certificate_hash,
message_id,
authenticated_signer: posted_message.authenticated_signer,
Expand Down
17 changes: 10 additions & 7 deletions linera-chain/src/unit_tests/chain_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ async fn test_block_size_limit() {
recipient: Recipient::root(0),
amount: Amount::ONE,
});
let result = chain.execute_block(&invalid_block, time, None).await;
let result = chain.execute_block(&invalid_block, time, None, None).await;
assert_matches!(
result,
Err(ChainError::ExecutionError(
Expand All @@ -170,7 +170,10 @@ async fn test_block_size_limit() {
);

// The valid block is accepted...
let outcome = chain.execute_block(&valid_block, time, None).await.unwrap();
let outcome = chain
.execute_block(&valid_block, time, None, None)
.await
.unwrap();
let block = Block::new(valid_block, outcome);

// ...because its size is exactly at the allowed limit.
Expand Down Expand Up @@ -231,7 +234,7 @@ async fn test_application_permissions() -> anyhow::Result<()> {
let invalid_block = make_first_block(chain_id)
.with_incoming_bundle(bundle.clone())
.with_simple_transfer(chain_id, Amount::ONE);
let result = chain.execute_block(&invalid_block, time, None).await;
let result = chain.execute_block(&invalid_block, time, None, None).await;
assert_matches!(result, Err(ChainError::AuthorizedApplications(app_ids))
if app_ids == vec![application_id]
);
Expand All @@ -247,7 +250,7 @@ async fn test_application_permissions() -> anyhow::Result<()> {
.with_incoming_bundle(bundle)
.with_operation(app_operation.clone());
let executed_block = chain
.execute_block(&valid_block, time, None)
.execute_block(&valid_block, time, None, None)
.await?
.with(valid_block);
let value = Hashed::new(ConfirmedBlock::new(executed_block));
Expand All @@ -256,14 +259,14 @@ async fn test_application_permissions() -> anyhow::Result<()> {
let invalid_block = make_child_block(&value.clone())
.with_simple_transfer(chain_id, Amount::ONE)
.with_operation(app_operation.clone());
let result = chain.execute_block(&invalid_block, time, None).await;
let result = chain.execute_block(&invalid_block, time, None, None).await;
assert_matches!(result, Err(ChainError::AuthorizedApplications(app_ids))
if app_ids == vec![application_id]
);

// Also, blocks without an application operation or incoming message are forbidden.
let invalid_block = make_child_block(&value.clone());
let result = chain.execute_block(&invalid_block, time, None).await;
let result = chain.execute_block(&invalid_block, time, None, None).await;
assert_matches!(result, Err(ChainError::MissingMandatoryApplications(app_ids))
if app_ids == vec![application_id]
);
Expand All @@ -272,7 +275,7 @@ async fn test_application_permissions() -> anyhow::Result<()> {
application.expect_call(ExpectedCall::execute_operation(|_, _, _| Ok(vec![])));
application.expect_call(ExpectedCall::default_finalize());
let valid_block = make_child_block(&value).with_operation(app_operation);
chain.execute_block(&valid_block, time, None).await?;
chain.execute_block(&valid_block, time, None, None).await?;

Ok(())
}
5 changes: 3 additions & 2 deletions linera-client/src/client_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use {
futures::{stream, StreamExt as _, TryStreamExt as _},
linera_base::{
crypto::PublicKey,
data_types::Amount,
data_types::{Amount, Round},
identifiers::{AccountOwner, ApplicationId, Owner},
},
linera_chain::data_types::{
Expand Down Expand Up @@ -972,11 +972,12 @@ where
pub async fn stage_block_execution(
&self,
block: ProposedBlock,
round: Option<Round>,
) -> Result<ExecutedBlock, Error> {
Ok(self
.client
.local_node()
.stage_block_execution(block)
.stage_block_execution(block, round)
.await?
.0)
}
Expand Down
11 changes: 8 additions & 3 deletions linera-core/src/chain_worker/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::{
use custom_debug_derive::Debug;
use linera_base::{
crypto::CryptoHash,
data_types::{Blob, BlockHeight, Timestamp, UserApplicationDescription},
data_types::{Blob, BlockHeight, Round, Timestamp, UserApplicationDescription},
hashed::Hashed,
identifiers::{BlobId, ChainId, UserApplicationId},
};
Expand Down Expand Up @@ -85,6 +85,7 @@ where
/// Execute a block but discard any changes to the chain state.
StageBlockExecution {
block: ProposedBlock,
round: Option<Round>,
#[debug(skip)]
callback: oneshot::Sender<Result<(ExecutedBlock, ChainInfoResponse), WorkerError>>,
},
Expand Down Expand Up @@ -286,8 +287,12 @@ where
} => callback
.send(self.worker.describe_application(application_id).await)
.is_ok(),
ChainWorkerRequest::StageBlockExecution { block, callback } => callback
.send(self.worker.stage_block_execution(block).await)
ChainWorkerRequest::StageBlockExecution {
block,
round,
callback,
} => callback
.send(self.worker.stage_block_execution(block, round).await)
.is_ok(),
ChainWorkerRequest::ProcessTimeout {
certificate,
Expand Down
1 change: 1 addition & 0 deletions linera-core/src/chain_worker/state/attempted_changes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ where
let verified_outcome = Box::pin(self.state.chain.execute_block(
&executed_block.block,
local_time,
None,
Some(executed_block.outcome.oracle_responses.clone()),
))
.await?;
Expand Down
5 changes: 3 additions & 2 deletions linera-core/src/chain_worker/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::{

use linera_base::{
crypto::CryptoHash,
data_types::{Blob, BlockHeight, UserApplicationDescription},
data_types::{Blob, BlockHeight, Round, UserApplicationDescription},
ensure,
hashed::Hashed,
identifiers::{BlobId, ChainId, UserApplicationId},
Expand Down Expand Up @@ -179,10 +179,11 @@ where
pub(super) async fn stage_block_execution(
&mut self,
block: ProposedBlock,
round: Option<Round>,
) -> Result<(ExecutedBlock, ChainInfoResponse), WorkerError> {
ChainWorkerStateWithTemporaryChanges::new(self)
.await
.stage_block_execution(block)
.stage_block_execution(block, round)
.await
}

Expand Down
18 changes: 12 additions & 6 deletions linera-core/src/chain_worker/state/temporary_changes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use linera_base::{
data_types::{
ArithmeticError, Blob, BlobContent, CompressedBytecode, Timestamp,
ArithmeticError, Blob, BlobContent, CompressedBytecode, Round, Timestamp,
UserApplicationDescription,
},
ensure,
Expand Down Expand Up @@ -126,14 +126,15 @@ where
/// Executes a block without persisting any changes to the state.
pub(super) async fn stage_block_execution(
&mut self,
proposal: ProposedBlock,
block: ProposedBlock,
round: Option<Round>,
) -> Result<(ExecutedBlock, ChainInfoResponse), WorkerError> {
let local_time = self.0.storage.clock().current_time();
let signer = proposal.authenticated_signer;
let signer = block.authenticated_signer;

let executed_block = Box::pin(self.0.chain.execute_block(&proposal, local_time, None))
let executed_block = Box::pin(self.0.chain.execute_block(&block, local_time, round, None))
.await?
.with(proposal);
.with(block);

let mut response = ChainInfoResponse::new(&self.0.chain, None);
if let Some(signer) = signer {
Expand Down Expand Up @@ -238,7 +239,12 @@ where
let outcome = if let Some(outcome) = outcome {
outcome.clone()
} else {
Box::pin(self.0.chain.execute_block(block, local_time, None)).await?
Box::pin(
self.0
.chain
.execute_block(block, local_time, Some(*round), None),
)
.await?
};

let executed_block = outcome.with(block.clone());
Expand Down
Loading

0 comments on commit b2ad189

Please sign in to comment.