Skip to content

Commit

Permalink
feat(verification-common): implement transformation functions (#1157)
Browse files Browse the repository at this point in the history
* feat(verification-common): add convenience functions to verify creation and runtime code

* feat(verification-common): add cbor_auxdata handling

* feat(verification-common): add immutable_references handling

* feat(verification-common): add libraries handling

* test(verification-common): add test cases for constructor arguments handling

* refactor(verification-common): update mod orders
  • Loading branch information
rimrakhimov authored Jan 13, 2025
1 parent 7975894 commit 5481500
Show file tree
Hide file tree
Showing 8 changed files with 777 additions and 33 deletions.
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

0 comments on commit 5481500

Please sign in to comment.