Skip to content

Commit

Permalink
Add blobs as oracle records (#2162)
Browse files Browse the repository at this point in the history
## Motivation

We'll need blobs are oracles to be able to properly check things for #2151. Fixes #2032

## Proposal

Add blobs as oracles

## Test Plan

CI + will be used in following PRs
  • Loading branch information
Andre da Silva authored Jun 21, 2024
1 parent 0c49178 commit bac58ca
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 10 deletions.
22 changes: 22 additions & 0 deletions linera-base/src/data_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -718,24 +718,43 @@ pub struct OracleRecord {
pub responses: Vec<OracleResponse>,
}

impl OracleRecord {
/// Wether an `OracleRecord` is permitted in fast blocks or not.
pub fn is_permitted_in_fast_blocks(&self) -> bool {
self.responses
.iter()
.all(|oracle_response| oracle_response.is_permitted_in_fast_blocks())
}
}

/// A record of a single oracle response.
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub enum OracleResponse {
/// The response from a service query.
Service(Vec<u8>),
/// The response from an HTTP POST request.
Post(Vec<u8>),
/// A successful read or write of a blob.
Blob(BlobId),
/// An assertion oracle that passed.
Assert,
}

impl OracleResponse {
/// Wether an `OracleResponse` is permitted in fast blocks or not.
pub fn is_permitted_in_fast_blocks(&self) -> bool {
matches!(self, OracleResponse::Blob(_))
}
}

impl fmt::Display for OracleResponse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
match self {
OracleResponse::Service(bytes) => {
write!(f, "Service:{}", STANDARD_NO_PAD.encode(bytes))?
}
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")?,
};

Expand All @@ -757,6 +776,9 @@ impl std::str::FromStr for OracleResponse {
STANDARD_NO_PAD.decode(string).context("Invalid base64")?,
));
}
if let Some(string) = s.strip_prefix("Blob:") {
return Ok(OracleResponse::Blob(BlobId(CryptoHash::from_str(string)?)));
}
Err(anyhow::anyhow!("Invalid enum! Enum: {}", s))
}
}
Expand Down
6 changes: 4 additions & 2 deletions linera-core/src/chain_worker/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,9 +355,11 @@ where
.ok_or_else(|| WorkerError::InvalidLiteCertificate)?;
}
if round.is_fast() {
let mut records = outcome.oracle_records.iter();
ensure!(
records.all(|record| record.responses.is_empty()),
outcome
.oracle_records
.iter()
.all(|record| record.is_permitted_in_fast_blocks()),
WorkerError::FastBlockUsingOracles
);
}
Expand Down
4 changes: 2 additions & 2 deletions linera-execution/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ where
assert_eq!(context.chain_id, self.context().extra().chain_id());
match operation {
Operation::System(op) => {
let (mut result, new_application) =
let (mut result, new_application, returned_oracle_record) =
self.system.execute_operation(context, op).await?;
result.authenticated_signer = context.authenticated_signer;
result.refund_grant_to = context.refund_grant_to();
Expand All @@ -318,7 +318,7 @@ where
outcomes.extend(user_outcomes);
return Ok((outcomes, oracle_record));
}
Ok((outcomes, OracleRecord::default()))
Ok((outcomes, returned_oracle_record))
}
Operation::User {
application_id,
Expand Down
20 changes: 14 additions & 6 deletions linera-execution/src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ use async_graphql::Enum;
use custom_debug_derive::Debug;
use linera_base::{
crypto::{CryptoHash, PublicKey},
data_types::{Amount, ApplicationPermissions, ArithmeticError, Timestamp},
data_types::{
Amount, ApplicationPermissions, ArithmeticError, OracleRecord, OracleResponse, Timestamp,
},
ensure, hex_debug,
identifiers::{Account, BlobId, BytecodeId, ChainDescription, ChainId, MessageId, Owner},
ownership::{ChainOwnership, TimeoutConfig},
Expand Down Expand Up @@ -443,12 +445,16 @@ where
(
RawExecutionOutcome<SystemMessage, Amount>,
Option<(UserApplicationId, Vec<u8>)>,
OracleRecord,
),
SystemExecutionError,
> {
use SystemOperation::*;
let mut outcome = RawExecutionOutcome::default();
let mut new_application = None;
let mut oracle_record = OracleRecord {
responses: Vec::new(),
};
match operation {
OpenChain(config) => {
let next_message_id = context.next_message_id();
Expand Down Expand Up @@ -672,10 +678,12 @@ where
};
outcome.messages.push(message);
}
PublishBlob { .. } => (),
PublishBlob { blob_id } => {
oracle_record.responses.push(OracleResponse::Blob(blob_id));
}
}

Ok((outcome, new_application))
Ok((outcome, new_application, oracle_record))
}

pub async fn transfer(
Expand Down Expand Up @@ -1074,7 +1082,7 @@ mod tests {
contract: Bytecode::new(vec![]),
service: Bytecode::new(vec![]),
};
let (result, new_application) = view
let (result, new_application, _) = view
.system
.execute_operation(context, operation)
.await
Expand Down Expand Up @@ -1112,7 +1120,7 @@ mod tests {
instantiation_argument: vec![],
required_application_ids: vec![],
};
let (result, new_application) = view
let (result, new_application, _) = view
.system
.execute_operation(context, operation)
.await
Expand Down Expand Up @@ -1149,7 +1157,7 @@ mod tests {
application_permissions: Default::default(),
};
let operation = SystemOperation::OpenChain(config.clone());
let (result, new_application) = view
let (result, new_application, _) = view
.system
.execute_operation(context, operation)
.await
Expand Down
4 changes: 4 additions & 0 deletions linera-rpc/tests/snapshots/format__format.yaml.snap
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,10 @@ OracleResponse:
NEWTYPE:
SEQ: U8
2:
Blob:
NEWTYPE:
TYPENAME: BlobId
3:
Assert: UNIT
Origin:
STRUCT:
Expand Down

0 comments on commit bac58ca

Please sign in to comment.