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

feat(verification-common): implement transformation functions #1157

Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;

#[serde_with::serde_as]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct CborAuxdataValue {
#[serde_as(as = "blockscout_display_bytes::serde_as::Hex")]
pub value: Vec<u8>,
pub offset: u32,
}
pub type CborAuxdata = BTreeMap<String, CborAuxdataValue>;

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Offset {
pub start: u32,
pub length: u32,
}
pub type Offsets = Vec<Offset>;

pub type ImmutableReferences = BTreeMap<String, Offsets>;

pub type LinkReferences = BTreeMap<String, BTreeMap<String, Offsets>>;
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use super::code_artifact_types::{CborAuxdata, LinkReferences};
use serde::{Deserialize, Serialize};
use serde_json::Value;

pub trait ToCreationCodeArtifacts {
fn cbor_auxdata(&self) -> Option<Value> {
fn cbor_auxdata(&self) -> Option<CborAuxdata> {
None
}
fn link_references(&self) -> Option<Value> {
fn link_references(&self) -> Option<LinkReferences> {
None
}
fn source_map(&self) -> Option<Value> {
Expand All @@ -14,10 +15,10 @@ pub trait ToCreationCodeArtifacts {
}

impl<T: ToCreationCodeArtifacts> ToCreationCodeArtifacts for &T {
fn cbor_auxdata(&self) -> Option<Value> {
fn cbor_auxdata(&self) -> Option<CborAuxdata> {
(*self).cbor_auxdata()
}
fn link_references(&self) -> Option<Value> {
fn link_references(&self) -> Option<LinkReferences> {
(*self).link_references()
}
fn source_map(&self) -> Option<Value> {
Expand All @@ -29,8 +30,8 @@ impl<T: ToCreationCodeArtifacts> ToCreationCodeArtifacts for &T {
#[serde(rename_all = "camelCase")]
pub struct CreationCodeArtifacts {
pub source_map: Option<Value>,
pub link_references: Option<Value>,
pub cbor_auxdata: Option<Value>,
pub link_references: Option<LinkReferences>,
pub cbor_auxdata: Option<CborAuxdata>,
}

impl<T: ToCreationCodeArtifacts> From<T> for CreationCodeArtifacts {
Expand Down
10 changes: 8 additions & 2 deletions libs/verification-common/src/verifier_alliance/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
mod code_artifact_types;
mod compilation_artifacts;
mod creation_code_artifacts;
mod runtime_code_artifacts;
mod verification_match;

mod verification_match_transformations;
mod verification_match_values;

pub use code_artifact_types::{
CborAuxdata, CborAuxdataValue, ImmutableReferences, LinkReferences, Offset, Offsets,
};
pub use compilation_artifacts::{CompilationArtifacts, SourceId, ToCompilationArtifacts};
pub use creation_code_artifacts::{CreationCodeArtifacts, ToCreationCodeArtifacts};
pub use runtime_code_artifacts::{RuntimeCodeArtifacts, ToRuntimeCodeArtifacts};
pub use verification_match::{Match, MatchBuilder, MatchTransformation, MatchValues};
pub use verification_match::{
verify_creation_code, verify_runtime_code, Match, MatchBuilder, MatchTransformation,
MatchValues,
};
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use super::code_artifact_types::{CborAuxdata, ImmutableReferences, LinkReferences};
use serde::{Deserialize, Serialize};
use serde_json::Value;

pub trait ToRuntimeCodeArtifacts {
fn cbor_auxdata(&self) -> Option<Value> {
fn cbor_auxdata(&self) -> Option<CborAuxdata> {
None
}
fn immutable_references(&self) -> Option<Value> {
fn immutable_references(&self) -> Option<ImmutableReferences> {
None
}
fn link_references(&self) -> Option<Value> {
fn link_references(&self) -> Option<LinkReferences> {
None
}
fn source_map(&self) -> Option<Value> {
Expand All @@ -17,13 +18,13 @@ pub trait ToRuntimeCodeArtifacts {
}

impl<T: ToRuntimeCodeArtifacts> ToRuntimeCodeArtifacts for &T {
fn cbor_auxdata(&self) -> Option<Value> {
fn cbor_auxdata(&self) -> Option<CborAuxdata> {
(*self).cbor_auxdata()
}
fn immutable_references(&self) -> Option<Value> {
fn immutable_references(&self) -> Option<ImmutableReferences> {
(*self).immutable_references()
}
fn link_references(&self) -> Option<Value> {
fn link_references(&self) -> Option<LinkReferences> {
(*self).link_references()
}
fn source_map(&self) -> Option<Value> {
Expand All @@ -34,9 +35,9 @@ impl<T: ToRuntimeCodeArtifacts> ToRuntimeCodeArtifacts for &T {
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RuntimeCodeArtifacts {
pub cbor_auxdata: Option<Value>,
pub immutable_references: Option<Value>,
pub link_references: Option<Value>,
pub cbor_auxdata: Option<CborAuxdata>,
pub immutable_references: Option<ImmutableReferences>,
pub link_references: Option<LinkReferences>,
pub source_map: Option<Value>,
}

Expand Down
141 changes: 133 additions & 8 deletions libs/verification-common/src/verifier_alliance/verification_match.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use super::{
compilation_artifacts::CompilationArtifacts, creation_code_artifacts::CreationCodeArtifacts,
code_artifact_types::{CborAuxdata, ImmutableReferences, LinkReferences},
compilation_artifacts::CompilationArtifacts,
creation_code_artifacts::CreationCodeArtifacts,
runtime_code_artifacts::RuntimeCodeArtifacts,
};
pub use super::{
verification_match_transformations::Transformation as MatchTransformation,
verification_match_values::Values as MatchValues,
};
use alloy_dyn_abi::JsonAbiExt;
use anyhow::Context;
use anyhow::{anyhow, Context};
use bytes::Bytes;
use serde::Deserialize;

Expand All @@ -18,6 +20,35 @@ pub struct Match {
pub values: MatchValues,
}

pub fn verify_creation_code(
on_chain_code: &[u8],
compiled_code: Vec<u8>,
creation_code_artifacts: &CreationCodeArtifacts,
compilation_artifacts: &CompilationArtifacts,
) -> Result<Option<Match>, anyhow::Error> {
let builder = MatchBuilder::new(on_chain_code, compiled_code);
if let Some(builder) = builder {
return Ok(builder
.apply_creation_code_transformations(creation_code_artifacts, compilation_artifacts)?
.verify_and_build());
}
Ok(None)
}

pub fn verify_runtime_code(
on_chain_code: &[u8],
compiled_code: Vec<u8>,
runtime_code_artifacts: &RuntimeCodeArtifacts,
) -> Result<Option<Match>, anyhow::Error> {
let builder = MatchBuilder::new(on_chain_code, compiled_code);
if let Some(builder) = builder {
return Ok(builder
.apply_runtime_code_transformations(runtime_code_artifacts)?
.verify_and_build());
}
Ok(None)
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MatchBuilder<'a> {
deployed_code: &'a [u8],
Expand Down Expand Up @@ -86,23 +117,117 @@ impl<'a> MatchBuilder<'a> {
}

fn apply_cbor_auxdata_transformations(
self,
_cbor_auxdata: Option<&serde_json::Value>,
mut self,
cbor_auxdata: Option<&CborAuxdata>,
) -> Result<Self, anyhow::Error> {
let cbor_auxdata = match cbor_auxdata {
Some(cbor_auxdata) => cbor_auxdata,
None => return Ok(self),
};

self.has_cbor_auxdata = !cbor_auxdata.is_empty();
for (id, cbor_auxdata_value) in cbor_auxdata {
let offset = cbor_auxdata_value.offset as usize;
let re_compiled_value = cbor_auxdata_value.value.to_vec();

let range = offset..offset + re_compiled_value.len();

if self.compiled_code.len() < range.end {
return Err(anyhow!("(reason=cbor_auxdata; id={id}) out of range"));
}

let on_chain_value = &self.deployed_code[range.clone()];
if on_chain_value != re_compiled_value {
self.has_cbor_auxdata_transformation = true;
self.compiled_code.as_mut_slice()[range].copy_from_slice(on_chain_value);

self.transformations
.push(MatchTransformation::auxdata(offset, id));
self.values.add_cbor_auxdata(id, on_chain_value.to_vec());
}
}

Ok(self)
}

fn apply_library_transformations(
self,
_link_references: Option<&serde_json::Value>,
mut self,
link_references: Option<&LinkReferences>,
) -> Result<Self, anyhow::Error> {
let link_references = match link_references {
Some(link_references) => link_references,
None => return Ok(self),
};

for (file, file_references) in link_references {
for (contract, offsets) in file_references {
let id = format!("{file}:{contract}");
let mut on_chain_value = None;
for offset in offsets {
let start = offset.start as usize;
let end = start + offset.length as usize;
let range = start..end;

let offset_value = &self.deployed_code[range.clone()];
match on_chain_value {
None => {
on_chain_value = Some(offset_value);
}
Some(on_chain_value) if on_chain_value != offset_value => {
return Err(anyhow!(
"(reason=link_reference; id={id}) offset values are not consistent"
))
}
_ => {}
}

self.compiled_code.as_mut_slice()[range].copy_from_slice(offset_value);
self.transformations
.push(MatchTransformation::library(start, &id));
self.values.add_library(&id, offset_value.to_vec());
}
}
}

Ok(self)
}

fn apply_immutable_transformations(
self,
_immutable_references: Option<&serde_json::Value>,
mut self,
immutable_references: Option<&ImmutableReferences>,
) -> Result<Self, anyhow::Error> {
let immutable_references = match immutable_references {
Some(immutable_references) => immutable_references,
None => return Ok(self),
};

for (id, offsets) in immutable_references {
let mut on_chain_value = None;
for offset in offsets {
let start = offset.start as usize;
let end = start + offset.length as usize;
let range = start..end;

let offset_value = &self.deployed_code[range.clone()];
match on_chain_value {
None => {
on_chain_value = Some(offset_value);
}
Some(on_chain_value) if on_chain_value != offset_value => {
return Err(anyhow!(
"(reason=immutable_reference; id={id}) offset values are not consistent"
))
}
_ => {}
}

self.compiled_code.as_mut_slice()[range].copy_from_slice(offset_value);
self.transformations
.push(MatchTransformation::immutable(start, id));
self.values.add_immutable(id, offset_value.to_vec());
}
}

Ok(self)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,27 @@ impl From<Values> for serde_json::Value {
}

impl Values {
pub fn add_cbor_auxdata(&mut self, key: impl Into<String>, value: Bytes) {
self.cbor_auxdata.insert(key.into(), value);
pub fn add_cbor_auxdata(
&mut self,
key: impl Into<String>,
value: impl Into<Bytes>,
) -> &mut Self {
self.cbor_auxdata.insert(key.into(), value.into());
self
}

pub fn add_constructor_arguments(&mut self, value: Bytes) {
self.constructor_arguments = Some(value);
pub fn add_constructor_arguments(&mut self, value: impl Into<Bytes>) -> &mut Self {
self.constructor_arguments = Some(value.into());
self
}

pub fn add_library(&mut self, key: impl Into<String>, value: Bytes) {
self.libraries.insert(key.into(), value);
pub fn add_library(&mut self, key: impl Into<String>, value: impl Into<Bytes>) -> &mut Self {
self.libraries.insert(key.into(), value.into());
self
}

pub fn add_immutable(&mut self, key: impl Into<String>, value: Bytes) {
self.immutables.insert(key.into(), value);
pub fn add_immutable(&mut self, key: impl Into<String>, value: impl Into<Bytes>) -> &mut Self {
self.immutables.insert(key.into(), value.into());
self
}
}
1 change: 1 addition & 0 deletions libs/verification-common/tests/integration/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod verifier_alliance_matches;
Loading
Loading