Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid cloning blob content. #3055

Merged
merged 3 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 30 additions & 23 deletions linera-base/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,18 +374,18 @@ pub trait HasTypeName {
/// Activate the blanket implementation of `Hashable` based on serde and BCS.
/// * We use `serde_name` to extract a seed from the name of structs and enums.
/// * We use `BCS` to generate canonical bytes suitable for hashing.
pub trait BcsHashable: Serialize + serde::de::DeserializeOwned {}
pub trait BcsHashable<'de>: Serialize + Deserialize<'de> {}

/// Activate the blanket implementation of `Signable` based on serde and BCS.
/// * We use `serde_name` to extract a seed from the name of structs and enums.
/// * We use `BCS` to generate canonical bytes suitable for signing.
pub trait BcsSignable: Serialize + serde::de::DeserializeOwned {}
pub trait BcsSignable<'de>: Serialize + Deserialize<'de> {}

impl<T: BcsSignable> BcsHashable for T {}
impl<'de, T: BcsSignable<'de>> BcsHashable<'de> for T {}

impl<T, Hasher> Hashable<Hasher> for T
impl<'de, T, Hasher> Hashable<Hasher> for T
where
T: BcsHashable,
T: BcsHashable<'de>,
Hasher: io::Write,
{
fn write(&self, hasher: &mut Hasher) {
Expand All @@ -405,9 +405,9 @@ where
}
}

impl<T> HasTypeName for T
impl<'de, T> HasTypeName for T
where
T: BcsHashable,
T: BcsHashable<'de>,
{
fn type_name() -> &'static str {
serde_name::trace_name::<Self>().expect("Self must be a struct or an enum")
Expand All @@ -416,7 +416,7 @@ where

impl CryptoHash {
/// Computes a hash.
pub fn new<T: BcsHashable>(value: &T) -> Self {
pub fn new<'de, T: BcsHashable<'de>>(value: &T) -> Self {
use sha3::digest::Digest;

let mut hasher = sha3::Sha3_256::default();
Expand All @@ -438,19 +438,23 @@ impl CryptoHash {

impl Signature {
/// Computes a signature.
pub fn new<T>(value: &T, secret: &KeyPair) -> Self
pub fn new<'de, T>(value: &T, secret: &KeyPair) -> Self
where
T: BcsSignable,
T: BcsSignable<'de>,
{
let mut message = Vec::new();
value.write(&mut message);
let signature = secret.0.sign(&message);
Signature(signature)
}

fn check_internal<T>(&self, value: &T, author: PublicKey) -> Result<(), dalek::SignatureError>
fn check_internal<'de, T>(
&self,
value: &T,
author: PublicKey,
) -> Result<(), dalek::SignatureError>
where
T: BcsSignable,
T: BcsSignable<'de>,
{
let mut message = Vec::new();
value.write(&mut message);
Expand All @@ -459,9 +463,9 @@ impl Signature {
}

/// Checks a signature.
pub fn check<T>(&self, value: &T, author: PublicKey) -> Result<(), CryptoError>
pub fn check<'de, T>(&self, value: &T, author: PublicKey) -> Result<(), CryptoError>
where
T: BcsSignable + fmt::Debug,
T: BcsSignable<'de> + fmt::Debug,
{
self.check_internal(value, author)
.map_err(|error| CryptoError::InvalidSignature {
Expand All @@ -471,13 +475,13 @@ impl Signature {
}

/// Checks an optional signature.
pub fn check_optional_signature<T>(
pub fn check_optional_signature<'de, T>(
signature: Option<&Self>,
value: &T,
author: &PublicKey,
) -> Result<(), CryptoError>
where
T: BcsSignable + fmt::Debug,
T: BcsSignable<'de> + fmt::Debug,
{
match signature {
Some(sig) => sig.check(value, *author),
Expand All @@ -487,9 +491,12 @@ impl Signature {
}
}

fn verify_batch_internal<'a, T, I>(value: &'a T, votes: I) -> Result<(), dalek::SignatureError>
fn verify_batch_internal<'a, 'de, T, I>(
value: &'a T,
votes: I,
) -> Result<(), dalek::SignatureError>
where
T: BcsSignable,
T: BcsSignable<'de>,
I: IntoIterator<Item = (&'a PublicKey, &'a Signature)>,
{
let mut msg = Vec::new();
Expand All @@ -506,9 +513,9 @@ impl Signature {
}

/// Verifies a batch of signatures.
pub fn verify_batch<'a, T, I>(value: &'a T, votes: I) -> Result<(), CryptoError>
pub fn verify_batch<'a, 'de, T, I>(value: &'a T, votes: I) -> Result<(), CryptoError>
where
T: BcsSignable,
T: BcsSignable<'de>,
I: IntoIterator<Item = (&'a PublicKey, &'a Signature)>,
{
Signature::verify_batch_internal(value, votes).map_err(|error| {
Expand Down Expand Up @@ -682,7 +689,7 @@ impl Arbitrary for CryptoHash {
}
}

impl BcsHashable for PublicKey {}
impl<'de> BcsHashable<'de> for PublicKey {}

doc_scalar!(CryptoHash, "A Sha3-256 value");
doc_scalar!(PublicKey, "A signature public key");
Expand All @@ -702,15 +709,15 @@ impl TestString {
}

#[cfg(with_testing)]
impl BcsSignable for TestString {}
impl<'de> BcsSignable<'de> for TestString {}

#[cfg(with_getrandom)]
#[test]
fn test_signatures() {
#[derive(Debug, Serialize, Deserialize)]
struct Foo(String);

impl BcsSignable for Foo {}
impl<'de> BcsSignable<'de> for Foo {}

let key1 = KeyPair::generate();
let addr1 = key1.public();
Expand Down
53 changes: 30 additions & 23 deletions linera-base/src/data_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::sync::LazyLock;
use std::{
fmt::{self, Display},
fs,
hash::{Hash, Hasher},
hash::Hash,
io, iter,
num::ParseIntError,
path::Path,
Expand Down Expand Up @@ -953,18 +953,12 @@ impl CompressedBytecode {
}

/// Internal bytes of a blob.
#[derive(Clone, Serialize, Deserialize, WitType, WitStore)]
#[derive(Clone, Hash, Serialize, Deserialize)]
#[cfg_attr(with_testing, derive(Eq, PartialEq))]
#[repr(transparent)]
pub struct BlobBytes(#[serde(with = "serde_bytes")] pub Vec<u8>);
pub struct BlobBytes<'a>(#[serde(with = "serde_bytes")] pub &'a [u8]);

impl BcsHashable for BlobBytes {}

impl Hash for BlobBytes {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<'a> BcsHashable<'a> for BlobBytes<'a> {}

/// A blob of binary data.
#[derive(Hash, Clone, Debug, Serialize, Deserialize, WitType, WitStore)]
Expand Down Expand Up @@ -1021,14 +1015,10 @@ impl BlobContent {

/// Creates a `Blob` checking that this is the correct `BlobId`.
pub fn with_blob_id_checked(self, blob_id: BlobId) -> Option<Blob> {
match blob_id.blob_type {
BlobType::Data if matches!(&self, BlobContent::Data(_)) => Some(()),
BlobType::ContractBytecode if matches!(&self, BlobContent::ContractBytecode(_)) => {
Some(())
}
BlobType::ServiceBytecode if matches!(&self, BlobContent::ServiceBytecode(_)) => {
Some(())
}
match (blob_id.blob_type, &self) {
(BlobType::Data, BlobContent::Data(_)) => Some(()),
(BlobType::ContractBytecode, BlobContent::ContractBytecode(_)) => Some(()),
(BlobType::ServiceBytecode, BlobContent::ServiceBytecode(_)) => Some(()),
_ => None,
}?;

Expand All @@ -1041,8 +1031,8 @@ impl BlobContent {
}
}

/// Gets the inner blob's bytes.
pub fn inner_bytes(&self) -> Vec<u8> {
/// Gets a reference to the inner blob's bytes.
pub fn inner_bytes(&self) -> &[u8] {
match self {
BlobContent::Data(bytes) => bytes,
BlobContent::ContractBytecode(compressed_bytecode) => {
Expand All @@ -1052,7 +1042,19 @@ impl BlobContent {
&compressed_bytecode.compressed_bytes
}
}
.clone()
}

/// Gets the inner blob's bytes, consuming the blob.
pub fn into_inner_bytes(self) -> Vec<u8> {
match self {
BlobContent::Data(bytes) => bytes,
BlobContent::ContractBytecode(compressed_bytecode) => {
compressed_bytecode.compressed_bytes
}
BlobContent::ServiceBytecode(compressed_bytecode) => {
compressed_bytecode.compressed_bytes
}
}
}

/// Gets the `BlobBytes` for this `BlobContent`.
Expand Down Expand Up @@ -1133,11 +1135,16 @@ impl Blob {
self.content
}

/// Gets the inner blob's bytes.
pub fn inner_bytes(&self) -> Vec<u8> {
/// Gets a reference to the inner blob's bytes.
pub fn inner_bytes(&self) -> &[u8] {
self.content.inner_bytes()
}

/// Gets the inner blob's bytes.
pub fn into_inner_bytes(self) -> Vec<u8> {
self.content.into_inner_bytes()
}

/// Loads data blob content from a file.
pub async fn load_data_blob_from_file(path: impl AsRef<Path>) -> io::Result<Self> {
Ok(Self::new_data(fs::read(path)?))
Expand Down
2 changes: 1 addition & 1 deletion linera-base/src/identifiers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -998,7 +998,7 @@ impl ChainId {
}
}

impl BcsHashable for ChainDescription {}
impl<'de> BcsHashable<'de> for ChainDescription {}

bcs_scalar!(ApplicationId, "A unique identifier for a user application");
doc_scalar!(
Expand Down
6 changes: 3 additions & 3 deletions linera-chain/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl ValidatedBlock {
}
}

impl BcsHashable for ValidatedBlock {}
impl<'de> BcsHashable<'de> for ValidatedBlock {}

/// Wrapper around an `ExecutedBlock` that has been confirmed.
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
Expand Down Expand Up @@ -98,7 +98,7 @@ impl Hashed<ConfirmedBlock> {
}
}

impl BcsHashable for ConfirmedBlock {}
impl<'de> BcsHashable<'de> for ConfirmedBlock {}

impl ConfirmedBlock {
pub fn new(executed_block: ExecutedBlock) -> Self {
Expand Down Expand Up @@ -194,7 +194,7 @@ impl Timeout {
}
}

impl BcsHashable for Timeout {}
impl<'de> BcsHashable<'de> for Timeout {}

/// Failure to convert a `Certificate` into one of the expected certificate types.
#[derive(Clone, Copy, Debug, Error)]
Expand Down
8 changes: 4 additions & 4 deletions linera-chain/src/certificate/hashed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::borrow::Cow;

use custom_debug_derive::Debug;
use linera_base::crypto::{BcsHashable, CryptoHash};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde::{Deserialize, Serialize};

use super::CertificateValueT;
use crate::data_types::LiteValue;
Expand All @@ -33,9 +33,9 @@ impl<T> Hashed<T> {
///
/// Note: Contrary to its `unchecked_new` counterpart, this method is safe because it
/// calculates the hash from the value.
pub fn new(value: T) -> Self
pub fn new<'de>(value: T) -> Self
where
T: BcsHashable,
T: BcsHashable<'de>,
{
let hash = CryptoHash::new(&value);
Self { value, hash }
Expand Down Expand Up @@ -74,7 +74,7 @@ impl<T: Serialize> Serialize for Hashed<T> {
}
}

impl<'de, T: DeserializeOwned + BcsHashable> Deserialize<'de> for Hashed<T> {
impl<'de, T: BcsHashable<'de>> Deserialize<'de> for Hashed<T> {
fn deserialize<D>(deserializer: D) -> Result<Hashed<T>, D::Error>
where
D: serde::Deserializer<'de>,
Expand Down
10 changes: 5 additions & 5 deletions linera-chain/src/data_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use linera_execution::{
system::OpenChainConfig,
Message, MessageKind, Operation, SystemMessage, SystemOperation,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde::{Deserialize, Serialize};

use crate::{
types::{
Expand Down Expand Up @@ -400,7 +400,7 @@ pub struct ExecutedBlock {
pub outcome: BlockExecutionOutcome,
}

impl BcsHashable for ExecutedBlock {}
impl<'de> BcsHashable<'de> for ExecutedBlock {}

/// The messages and the state hash resulting from a [`Block`]'s execution.
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, SimpleObject)]
Expand Down Expand Up @@ -444,7 +444,7 @@ struct VoteValue(CryptoHash, Round, CertificateKind);

/// A vote on a statement from a validator.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(bound(deserialize = "T: DeserializeOwned + BcsHashable"))]
#[serde(bound(deserialize = "T: BcsHashable<'de>"))]
pub struct Vote<T> {
pub value: Hashed<T>,
pub round: Round,
Expand Down Expand Up @@ -916,9 +916,9 @@ pub(crate) fn check_signatures(
Ok(())
}

impl BcsSignable for ProposalContent {}
impl<'de> BcsSignable<'de> for ProposalContent {}

impl BcsSignable for VoteValue {}
impl<'de> BcsSignable<'de> for VoteValue {}

doc_scalar!(
MessageAction,
Expand Down
2 changes: 1 addition & 1 deletion linera-client/src/client_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ where
.await?;

info!("{}", "Data blob published successfully!");
Ok(CryptoHash::new(&BlobBytes(blob_bytes)))
Ok(CryptoHash::new(&BlobBytes(&blob_bytes)))
}

// TODO(#2490): Consider removing or renaming this.
Expand Down
2 changes: 1 addition & 1 deletion linera-client/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ pub struct GenesisConfig {
pub network_name: String,
}

impl BcsSignable for GenesisConfig {}
impl<'de> BcsSignable<'de> for GenesisConfig {}

impl GenesisConfig {
pub fn new(
Expand Down
2 changes: 1 addition & 1 deletion linera-core/src/data_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ impl ChainInfoResponse {
}
}

impl BcsSignable for ChainInfo {}
impl<'de> BcsSignable<'de> for ChainInfo {}

/// The outcome of trying to commit a list of operations to the chain.
#[derive(Debug)]
Expand Down
Loading
Loading